Package: rscase
This module offers a handful of case-formatting utility functions. It is a very simple Python package, written inRustand implemented usingpyo3which offers you easy Rust bindings for the Python interpreter.InstallationInstall with pip using:pipinstallrscaseNote: This package requiresRust nightly 2020-02-06or an equivalent future release.UsageThe package provides utility functions for generating strings formatted in several different case standards.The case-standards and their functions are listed below.Supported casesFunctionFormat examplecamel casecamel_casecamelCasedValuesnake casesnake_casesnake_cased_valuepascal casepascal_casePascalCasedValuekebab casekebab_casekebab-cased-valuetrain casetrain_caseTRAIN-CASED-VALUEAll functions are imported and accessed the same way:>>[in]fromrscaseimportrscase>>[in]rscase.camel_case('this_is-a_Test')>>[out]thisIsATestIf you want to use this package, please note that the case functions are written to successfully convert camel case and snake case to the remaining formats. Formatting train case to itself doesn’t really make sense, and the way I would use this would be to, e.g., serialize out response data to a camelCased format.Benchmarking PerformanceThis repo is a bit of an experiment, and because the functions contained in this package only do some very simple string manipulation, they seem like they might actually be good candidates for Python vs Rust performance benchmarking.To try and make this a fair comparison - to make sure we’re comparing apples to apples - I decided to test the Rust functionsnake_case(see the Rust functionhere) to an identical Python function. The Python version is shown below:fromrscaseimportrscasetest_string="thisIsALongCamelCasedAlphabeticKey"# Test functionsdeforiginal_snake_case():string=test_stringnew_string=""dash="-"forindexinrange(len(string)):ifindex==0:new_string+=string[index].lower()elifstring[index]==dash:new_string+='_'elifstring[index].upper()==string[index]:new_string+=f'_{string[index]}'else:new_string+=string[index]returnnew_stringdefrust_snake_case():string=test_stringreturnrscase.snake_case(string)The main difference between the two functions, flow-wise, is only that Rust won’t let you just iterate over a string, so you have to create a vector ofchar’s instead - or at least that’s how I did it.ResultsAfter running the tests, the results seems to be pretty promising - in favor of the Rust implementation.RepsRust Execution TimePython Execution TimeDifference118.30 us14.20 us0.78x*1055.20 us114.20 us2.07x100.49 ms1.11 ms2.27x10004.88 ms11.18 ms2.28x10 00047.20 ms109.13 ms2.31x100 000.47 s1.08 s2.31x1000 0004.83 s11.12 s2.30x10 000 00046.67 s109.27 s2.34x100 000 000484 s1102 s2.28xThe results are pretty clear: after only 100 reps, the results seem to stabilize, and flatten out at around a 2.3x longer execution time for the Python implementation.*the 1-rep result seems to show that Python actually outperforms Rust in the scenario that would normallyactuallymatter. Since it makes sense that variance would be high when trying to measure something at the microsecond level I decided to run this individual scenario again, another one million times, to increase the sample size. With a larger sample, the averagedifferencefor 1 rep averages to1.85xslower in Python, and the median is1.88x. In short, the Rust implementation seems to outperform the Python across the board.Benchmarking Performance - UpdateThanks toThomas Hartmannfor suggesting a significant performance improvement in the packaged Rust code.Using some experimental features, we’re able to improve the performance of the Rust code considerably. Thesnake_casetest from above is replicated below, with the performance difference settling at 5x the Python performance.RepsRust Execution TimePython Execution TimeDifference110.70 us15.20 us1.42x1028.70 us113.30 us3.95x100.24 ms1.11 ms4.56x10002.24 ms11.28 ms5.03x10 00022.16 ms107.79 ms4.86x100 000.24 s1.09 s4.44x1000 0002.21 s11.02 s4.99x10 000 00022.09 s110.47 s5.00x100 000 000222 s1086 s4.88xRunning the1 repscenario one million times, gives an average Rust execution time of 3.84 us compared to an average Python execution time of 12.61 us (~3.3x slower for Python).This time around, I also decided to test the camel case implementations, as the logic does behave a bit differently:RepsRust Execution TimePython Execution TimeDifference110.99 us14.40 us1.31x1039.79 us106.90 us2.69x100.25 ms1.02 ms4.07x10002.40 ms10.24 ms4.26x10 00023.55 ms100.17 ms4.25x100 000.23 s0.98 s4.26x1000 0002.34 s9.92 s4.23x10 000 00023.23 s98.91 s4.26x100 000 000232 s990 s4.26xRunning the1 repscenario one million times, gives an average Rust execution time of 3.90 us compared to an average Python execution time of 11.48 us (almost ~3x slower for Python).In summary, the benchmarked performed similarly, with Rust pulling ahead even more, for these two implementations. At the same time, there’s probably room for improvement for both implementations still, and probably especially for the Python one.