diff options
Diffstat (limited to 'vendor/tinystr')
-rw-r--r-- | vendor/tinystr/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | vendor/tinystr/CHANGELOG.md | 35 | ||||
-rw-r--r-- | vendor/tinystr/Cargo.lock | 625 | ||||
-rw-r--r-- | vendor/tinystr/Cargo.toml | 42 | ||||
-rw-r--r-- | vendor/tinystr/LICENSE-APACHE | 201 | ||||
-rw-r--r-- | vendor/tinystr/LICENSE-MIT | 23 | ||||
-rw-r--r-- | vendor/tinystr/README.md | 95 | ||||
-rw-r--r-- | vendor/tinystr/benches/construct.rs | 154 | ||||
-rw-r--r-- | vendor/tinystr/benches/tinystr.rs | 176 | ||||
-rw-r--r-- | vendor/tinystr/examples/main.rs | 18 | ||||
-rw-r--r-- | vendor/tinystr/src/helpers.rs | 32 | ||||
-rw-r--r-- | vendor/tinystr/src/lib.rs | 105 | ||||
-rw-r--r-- | vendor/tinystr/src/tinystr16.rs | 327 | ||||
-rw-r--r-- | vendor/tinystr/src/tinystr4.rs | 299 | ||||
-rw-r--r-- | vendor/tinystr/src/tinystr8.rs | 319 | ||||
-rw-r--r-- | vendor/tinystr/src/tinystrauto.rs | 72 | ||||
-rw-r--r-- | vendor/tinystr/tests/main.rs | 538 |
17 files changed, 3062 insertions, 0 deletions
diff --git a/vendor/tinystr/.cargo-checksum.json b/vendor/tinystr/.cargo-checksum.json new file mode 100644 index 000000000..b2cb895be --- /dev/null +++ b/vendor/tinystr/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"cb378d2a5c7efd2259cdb7513e1a6bc8bc05b2c5f89b69b69f1f16037495760b","Cargo.lock":"c772766a0c3008c0e528d1ef08c5d8b0e8752a308cb5a782855f691c4b3c223f","Cargo.toml":"af00927b1bd3451ef45685cb34c466566df816aa41f31555c9492c74af597c2c","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"7eaffe990ac4432ab388dcda2703f5594e9b1c7a6f753882906b0b8df9876bb4","benches/construct.rs":"9c8652afb0770f60238952b06abb4b90c6cec41d50fd19b760e573eb8dff8e4f","benches/tinystr.rs":"dc61b52ca7be3312a8c504786ad60e5e2c4c729e111c2033716c9996c5e87bc8","examples/main.rs":"463f7c0db47a3843097b012315fc8b0d68baa4afca0a0fe06210ed3c8c471453","src/helpers.rs":"d7768b34dacbb586ade41249147bce1c90d1c08dbfd7c7de6792c88ea45200e1","src/lib.rs":"17740bacc4b05e433f58ddd06d86287097f83024849166e95e8ddb16e491873f","src/tinystr16.rs":"b40595634190ee298bbdcb60b3699b11a25ef2861bccdb567821815ff21fbac3","src/tinystr4.rs":"1787c52e9ec9711b0a115f4c32bee952fb410ce569db4a89fef4c5282bb4f04f","src/tinystr8.rs":"2baf0330c3a20e2e01ff791aa932450d2727d53eb8ed80d76a685bdd824700b6","src/tinystrauto.rs":"55b9333cd8a69e8ea79db72801c4f2b946c5b61108e1ddfb2bf2e06384c41f4a","tests/main.rs":"83b1892f2c5437f99be3ce6d5e98a8df42a5c293447437cc567dcc133a2768d7"},"package":"29738eedb4388d9ea620eeab9384884fc3f06f586a2eddb56bedc5885126c7c1"}
\ No newline at end of file diff --git a/vendor/tinystr/CHANGELOG.md b/vendor/tinystr/CHANGELOG.md new file mode 100644 index 000000000..257012a4a --- /dev/null +++ b/vendor/tinystr/CHANGELOG.md @@ -0,0 +1,35 @@ +# Changelog + +## Unreleased + + - … + +## tinystr 0.3.4 (August 21, 2020) + + - Add `macros` feature which exposes `tinystr::macros`. + +## tinystr 0.3.3 (July 26, 2020) + + - Add `TinyStrAuto`. + - Add `no_std` feature. + +## tinystr 0.3.2 (October 28, 2019) + + - Add `from_bytes` method. + +## tinystr 0.3.1 (October 1, 2019) + + - Documentation. + +## tinystr 0.3.1 (October 1, 2019) + + - Documentation. + +## tinystr 0.3.0 (August 23, 2019) + + - Separate out `is_ascii_numeric`, `is_ascii_alphanumeric` and `is_ascii_alphabetic`. + +## tinystr 0.2.0 (August 16, 2019) + + - Add TinyStr16 + - Add to_ascii_titlecase specialization for all TinyStr* diff --git a/vendor/tinystr/Cargo.lock b/vendor/tinystr/Cargo.lock new file mode 100644 index 000000000..ca4e5151b --- /dev/null +++ b/vendor/tinystr/Cargo.lock @@ -0,0 +1,625 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "bstr" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31accafdb70df7871592c058eca3985b71104e15ac32f64706022c58867da931" +dependencies = [ + "lazy_static", + "memchr", + "regex-automata", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" + +[[package]] +name = "byteorder" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" + +[[package]] +name = "cast" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "clap" +version = "2.33.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" +dependencies = [ + "bitflags", + "textwrap", + "unicode-width", +] + +[[package]] +name = "criterion" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70daa7ceec6cf143990669a04c7df13391d55fb27bd4079d252fca774ba244d8" +dependencies = [ + "atty", + "cast", + "clap", + "criterion-plot", + "csv", + "itertools", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_cbor", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e022feadec601fba1649cfa83586381a4ad31c6bf3a9ab7d408118b05dd9889d" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-deque" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "lazy_static", + "maybe-uninit", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg", + "cfg-if", + "lazy_static", +] + +[[package]] +name = "csv" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00affe7f6ab566df61b4be3ce8cf16bc2576bca0963ceb0955e45d514bf9a279" +dependencies = [ + "bstr", + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", +] + +[[package]] +name = "either" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" + +[[package]] +name = "half" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d36fab90f82edc3c747f9d438e06cf0a491055896f2a279638bb5beed6c40177" + +[[package]] +name = "hermit-abi" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909" +dependencies = [ + "libc", +] + +[[package]] +name = "itertools" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" + +[[package]] +name = "js-sys" +version = "0.3.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4b9172132a62451e56142bff9afc91c8e4a4500aa5b847da36815b63bfda916" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" + +[[package]] +name = "log" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + +[[package]] +name = "memchr" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" + +[[package]] +name = "memoffset" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c198b026e1bbf08a937e94c6c60f9ec4a2267f5b0d2eec9c1b21b061ce2be55f" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num-traits" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "oorandom" +version = "11.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a170cebd8021a008ea92e4db85a72f80b35df514ec664b296fdcbb654eac0b2c" + +[[package]] +name = "plotters" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d1685fbe7beba33de0330629da9d955ac75bd54f33d7b79f9a895590124f6bb" +dependencies = [ + "js-sys", + "num-traits", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "proc-macro2" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rayon" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f02856753d04e03e26929f820d0a0a337ebe71f849801eea335d464b349080" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e92e15d89083484e11353891f1af602cc661426deb9564c298b270c726973280" +dependencies = [ + "crossbeam-deque", + "crossbeam-queue", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + +[[package]] +name = "regex" +version = "1.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4" +dependencies = [ + "byteorder", +] + +[[package]] +name = "regex-syntax" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3" + +[[package]] +name = "serde_cbor" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622" +dependencies = [ + "half", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3433e879a558dde8b5e8feb2a04899cf34fdde1fafb894687e52105fc1162ac3" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8d5d96e8cbb005d6959f119f773bfaebb5684296108fb32600c00cde305b2cd" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "tinystr" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707151f004e8db265b83b1c7509d6c3b4c2c2bc8696113cbe0a8e595c2fdbd3b" + +[[package]] +name = "tinystr" +version = "0.3.4" +dependencies = [ + "criterion", + "tinystr-macros", +] + +[[package]] +name = "tinystr-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c97a45afd04e6bf6d5945895d6982afd9a428e0ebf66585d5e09961d8319ac30" +dependencies = [ + "tinystr 0.3.3", +] + +[[package]] +name = "tinytemplate" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d3dc76004a03cec1c5932bca4cdc2e39aaa798e3f82363dd94f9adf6098c12f" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "walkdir" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a634620115e4a229108b71bde263bb4220c483b3f07f5ba514ee8d15064c4c2" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e53963b583d18a5aa3aaae4b4c1cb535218246131ba22a71f05b518098571df" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fcfd5ef6eec85623b4c6e844293d4516470d8f19cd72d0d12246017eb9060b8" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9adff9ee0e94b926ca81b57f57f86d5545cdcb1d259e21ec9bdd95b901754c75" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7b90ea6c632dd06fd765d44542e234d5e63d9bb917ecd64d79778a13bd79ae" + +[[package]] +name = "web-sys" +version = "0.3.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "863539788676619aac1a23e2df3655e96b32b0e05eb72ca34ba045ad573c625d" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/vendor/tinystr/Cargo.toml b/vendor/tinystr/Cargo.toml new file mode 100644 index 000000000..53f9fc1f7 --- /dev/null +++ b/vendor/tinystr/Cargo.toml @@ -0,0 +1,42 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "tinystr" +version = "0.3.4" +authors = ["Raph Levien <raph.levien@gmail.com>", "Zibi Braniecki <zibi@braniecki.net>"] +description = "A small ASCII-only bounded length string representation.\n" +readme = "README.md" +keywords = ["string", "str", "small", "tiny", "no_std"] +categories = ["data-structures"] +license = "Apache-2.0/MIT" +repository = "https://github.com/zbraniecki/tinystr" + +[[bench]] +name = "construct" +harness = false + +[[bench]] +name = "tinystr" +harness = false +[dependencies.tinystr-macros] +version = "0.1" +optional = true +[dev-dependencies.criterion] +version = "0.3" + +[features] +alloc = [] +default = ["std"] +macros = ["tinystr-macros"] +std = [] diff --git a/vendor/tinystr/LICENSE-APACHE b/vendor/tinystr/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/vendor/tinystr/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/tinystr/LICENSE-MIT b/vendor/tinystr/LICENSE-MIT new file mode 100644 index 000000000..31aa79387 --- /dev/null +++ b/vendor/tinystr/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/vendor/tinystr/README.md b/vendor/tinystr/README.md new file mode 100644 index 000000000..15a8338be --- /dev/null +++ b/vendor/tinystr/README.md @@ -0,0 +1,95 @@ +# tinystr [![crates.io](http://meritbadge.herokuapp.com/tinystr)](https://crates.io/crates/tinystr) [![Build Status](https://travis-ci.org/zbraniecki/tinystr.svg?branch=master)](https://travis-ci.org/zbraniecki/tinystr) [![Coverage Status](https://coveralls.io/repos/github/zbraniecki/tinystr/badge.svg?branch=master)](https://coveralls.io/github/zbraniecki/tinystr?branch=master) + +`tinystr` is a small ASCII-only bounded length string representation. + +Usage +----- + +```rust +use tinystr::{TinyStr4, TinyStr8, TinyStr16, TinyStrAuto}; + +fn main() { + let s1: TinyStr4 = "tEsT".parse() + .expect("Failed to parse."); + + assert_eq!(s1, "tEsT"); + assert_eq!(s1.to_ascii_uppercase(), "TEST"); + assert_eq!(s1.to_ascii_lowercase(), "test"); + assert_eq!(s1.to_ascii_titlecase(), "Test"); + assert_eq!(s1.is_ascii_alphanumeric(), true); + + let s2: TinyStr8 = "New York".parse() + .expect("Failed to parse."); + + assert_eq!(s2, "New York"); + assert_eq!(s2.to_ascii_uppercase(), "NEW YORK"); + assert_eq!(s2.to_ascii_lowercase(), "new york"); + assert_eq!(s2.to_ascii_titlecase(), "New york"); + assert_eq!(s2.is_ascii_alphanumeric(), false); + + let s3: TinyStr16 = "metaMoRphosis123".parse() + .expect("Failed to parse."); + + assert_eq!(s3, "metaMoRphosis123"); + assert_eq!(s3.to_ascii_uppercase(), "METAMORPHOSIS123"); + assert_eq!(s3.to_ascii_lowercase(), "metamorphosis123"); + assert_eq!(s3.to_ascii_titlecase(), "Metamorphosis123"); + assert_eq!(s3.is_ascii_alphanumeric(), true); + + let s4: TinyStrAuto = "shortNoAlloc".parse().unwrap(); + assert!(matches!(s4, TinyStrAuto::Tiny { .. })); + assert_eq!(s4, "shortNoAlloc"); + + let s5: TinyStrAuto = "longFallbackToHeap".parse().unwrap(); + assert!(matches!(s4, TinyStrAuto::Heap { .. })); + assert_eq!(s4, "shortNoAlloc"); +} +``` + +Details +------- + +The crate provides three structs and an enum: + * `TinyStr4` an ASCII-only string limited to 4 characters. + * `TinyStr8` an ASCII-only string limited to 8 characters. + * `TinyStr16` an ASCII-only string limited to 16 characters. + * `TinyStrAuto` (enum): + * `Tiny` when the string is 16 characters or less. + * `Heap` when the string is 17 or more characters. + +The structs stores the characters as `u32`/`u64`/`u128` and uses bitmasking to provide basic string manipulation operations: + * is_ascii_numeric + * is_ascii_alphabetic + * is_ascii_alphanumeric + * to_ascii_lowercase + * to_ascii_uppercase + * to_ascii_titlecase + * PartialEq + +`TinyStrAuto` stores the string as a TinyStr16 when it is short enough, or else falls back to a standard `String`. You should use TinyStrAuto when you expect most strings to be 16 characters or smaller, but occasionally you receive one that exceeds that length. Unlike the structs, `TinyStrAuto` does not implement `Copy`. + +This set is sufficient for certain classes of uses such as `unic-langid` libraries. + +no_std +------ + +Disable the `std` feature of this crate to make it `#[no_std]`. Doing so disables `TinyStrAuto`. You +can re-enable `TinyStrAuto` in `#[no_std]` mode by enabling the `alloc` feature. + +Performance +----------- + +For those uses, TinyStr provides [performance characteristics](https://github.com/zbraniecki/tinystr/wiki/Performance) much better than the regular `String`. + +Status +------ + +The crate is fully functional and ready to be used in production. +The capabilities can be extended. + +#### License + +<sup> +Licensed under either of <a href="LICENSE-APACHE">Apache License, Version +2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option. +</sup diff --git a/vendor/tinystr/benches/construct.rs b/vendor/tinystr/benches/construct.rs new file mode 100644 index 000000000..a93fce8f6 --- /dev/null +++ b/vendor/tinystr/benches/construct.rs @@ -0,0 +1,154 @@ +use criterion::black_box; +use criterion::criterion_group; +use criterion::criterion_main; +use criterion::Bencher; +use criterion::Criterion; +use criterion::Fun; + +use tinystr::{TinyStr16, TinyStr4, TinyStr8, TinyStrAuto}; + +static STRINGS_4: &[&str] = &[ + "US", "GB", "AR", "Hans", "CN", "AT", "PL", "FR", "AT", "Cyrl", "SR", "NO", "FR", "MK", "UK", +]; + +static STRINGS_8: &[&str] = &[ + "Latn", "windows", "AR", "Hans", "macos", "AT", "pl", "FR", "en", "Cyrl", "SR", "NO", "419", + "und", "UK", +]; + +static STRINGS_16: &[&str] = &[ + "Latn", + "windows", + "AR", + "Hans", + "macos", + "AT", + "infiniband", + "FR", + "en", + "Cyrl", + "FromIntegral", + "NO", + "419", + "MacintoshOSX2019", + "UK", +]; + +macro_rules! bench_block { + ($c:expr, $name:expr, $action:ident) => { + let funcs = vec![ + Fun::new("String", $action!(String)), + Fun::new("TinyStr4", $action!(TinyStr4)), + Fun::new("TinyStr8", $action!(TinyStr8)), + Fun::new("TinyStr16", $action!(TinyStr16)), + Fun::new("TinyStrAuto", $action!(TinyStrAuto)), + ]; + + $c.bench_functions(&format!("{}/4", $name), funcs, STRINGS_4); + + let funcs = vec![ + Fun::new("String", $action!(String)), + Fun::new("TinyStr8", $action!(TinyStr8)), + Fun::new("TinyStr16", $action!(TinyStr16)), + Fun::new("TinyStrAuto", $action!(TinyStrAuto)), + ]; + + $c.bench_functions(&format!("{}/8", $name), funcs, STRINGS_8); + + let funcs = vec![ + Fun::new("String", $action!(String)), + Fun::new("TinyStr16", $action!(TinyStr16)), + Fun::new("TinyStrAuto", $action!(TinyStrAuto)), + ]; + + $c.bench_functions(&format!("{}/16", $name), funcs, STRINGS_16); + }; +} + +fn construct_from_str(c: &mut Criterion) { + macro_rules! cfs { + ($r:ty) => { + |b: &mut Bencher, strings: &&[&str]| { + b.iter(|| { + for s in *strings { + let _: $r = black_box(s.parse().unwrap()); + } + }) + } + }; + }; + + bench_block!(c, "construct_from_str", cfs); +} + +fn construct_from_bytes(c: &mut Criterion) { + macro_rules! cfu { + ($r:ty) => { + |b, inputs: &&[&str]| { + let raw: Vec<&[u8]> = inputs.iter().map(|s| s.as_bytes()).collect(); + b.iter(move || { + for u in &raw { + let _ = black_box(<$r>::from_bytes(*u).unwrap()); + } + }) + } + }; + }; + + let funcs = vec![ + Fun::new("TinyStr4", cfu!(TinyStr4)), + Fun::new("TinyStr8", cfu!(TinyStr8)), + Fun::new("TinyStr16", cfu!(TinyStr16)), + ]; + + c.bench_functions("construct_from_bytes/4", funcs, STRINGS_4); + + let funcs = vec![ + Fun::new("TinyStr8", cfu!(TinyStr8)), + Fun::new("TinyStr16", cfu!(TinyStr16)), + ]; + + c.bench_functions("construct_from_bytes/8", funcs, STRINGS_8); + + let funcs = vec![Fun::new("TinyStr16", cfu!(TinyStr16))]; + + c.bench_functions("construct_from_bytes/16", funcs, STRINGS_16); +} + +fn construct_unchecked(c: &mut Criterion) { + macro_rules! cu { + ($tty:ty, $rty:ty) => { + |b, inputs: &&[&str]| { + let raw: Vec<$rty> = inputs + .iter() + .map(|s| s.parse::<$tty>().unwrap().into()) + .collect(); + b.iter(move || { + for num in &raw { + let _ = unsafe { <$tty>::new_unchecked(black_box(*num)) }; + } + }) + } + }; + }; + + let funcs = vec![Fun::new("TinyStr4", cu!(TinyStr4, u32))]; + + c.bench_functions("construct_unchecked/4", funcs, STRINGS_4); + + let funcs = vec![Fun::new("TinyStr8", cu!(TinyStr8, u64))]; + + c.bench_functions("construct_unchecked/8", funcs, STRINGS_8); + + let funcs = vec![Fun::new("TinyStr16", cu!(TinyStr16, u128))]; + + c.bench_functions("construct_unchecked/16", funcs, STRINGS_16); +} + +criterion_group!( + benches, + construct_from_str, + construct_from_bytes, + construct_unchecked, +); +criterion_main!(benches); diff --git a/vendor/tinystr/benches/tinystr.rs b/vendor/tinystr/benches/tinystr.rs new file mode 100644 index 000000000..83b26a30a --- /dev/null +++ b/vendor/tinystr/benches/tinystr.rs @@ -0,0 +1,176 @@ +use criterion::black_box; +use criterion::criterion_group; +use criterion::criterion_main; +use criterion::Bencher; +use criterion::Criterion; +use criterion::Fun; + +use tinystr::{TinyStr16, TinyStr4, TinyStr8}; + +static STRINGS_4: &[&str] = &[ + "US", "GB", "AR", "Hans", "CN", "AT", "PL", "FR", "AT", "Cyrl", "SR", "NO", "FR", "MK", "UK", +]; + +static STRINGS_8: &[&str] = &[ + "Latn", "windows", "AR", "Hans", "macos", "AT", "pl", "FR", "en", "Cyrl", "SR", "NO", "419", + "und", "UK", +]; + +static STRINGS_16: &[&str] = &[ + "Latn", + "windows", + "AR", + "Hans", + "macos", + "AT", + "infiniband", + "FR", + "en", + "Cyrl", + "FromIntegral", + "NO", + "419", + "MacintoshOSX2019", + "UK", +]; + +macro_rules! bench_block { + ($c:expr, $name:expr, $action:ident) => { + let funcs = vec![ + Fun::new("String", $action!(String)), + Fun::new("TinyStr4", $action!(TinyStr4)), + Fun::new("TinyStr8", $action!(TinyStr8)), + Fun::new("TinyStr16", $action!(TinyStr16)), + ]; + + $c.bench_functions(&format!("{}/4", $name), funcs, STRINGS_4); + + let funcs = vec![ + Fun::new("String", $action!(String)), + Fun::new("TinyStr8", $action!(TinyStr8)), + Fun::new("TinyStr16", $action!(TinyStr16)), + ]; + + $c.bench_functions(&format!("{}/8", $name), funcs, STRINGS_8); + + let funcs = vec![ + Fun::new("String", $action!(String)), + Fun::new("TinyStr16", $action!(TinyStr16)), + ]; + + $c.bench_functions(&format!("{}/16", $name), funcs, STRINGS_16); + }; +} + +macro_rules! convert_to_ascii { + ($ty:ty, $action:ident) => { + |b: &mut Bencher, inputs: &&[&str]| { + let raw: Vec<$ty> = inputs.iter().map(|s| s.parse::<$ty>().unwrap()).collect(); + b.iter(move || { + for s in &raw { + let _ = black_box(s.$action()); + } + }) + } + }; +} + +fn convert_to_ascii_lowercase(c: &mut Criterion) { + macro_rules! ctal { + ($ty:ty) => { + convert_to_ascii!($ty, to_ascii_lowercase) + }; + } + + bench_block!(c, "convert_to_ascii_lowercase", ctal); +} + +fn convert_to_ascii_uppercase(c: &mut Criterion) { + macro_rules! ctau { + ($ty:ty) => { + convert_to_ascii!($ty, to_ascii_uppercase) + }; + } + + bench_block!(c, "convert_to_ascii_uppercase", ctau); +} + +trait ExtToAsciiTitlecase { + #[inline(always)] + fn to_ascii_titlecase(&self) -> String; +} + +impl ExtToAsciiTitlecase for str { + fn to_ascii_titlecase(&self) -> String { + let mut result = self.to_ascii_lowercase(); + result[0..1].make_ascii_uppercase(); + result + } +} + +fn convert_to_ascii_titlecase(c: &mut Criterion) { + macro_rules! ctat { + ($ty:ty) => { + convert_to_ascii!($ty, to_ascii_titlecase) + }; + } + + bench_block!(c, "convert_to_ascii_titlecase", ctat); +} + +trait ExtIsAsciiAlphanumeric { + #[inline(always)] + fn is_ascii_alphanumeric(&self) -> bool; +} + +impl ExtIsAsciiAlphanumeric for str { + fn is_ascii_alphanumeric(&self) -> bool { + self.chars().all(|c| c.is_ascii_alphanumeric()) + } +} + +fn test_is_ascii_alphanumeric(c: &mut Criterion) { + macro_rules! tiaa { + ($ty:ty) => { + |b: &mut Bencher, inputs: &&[&str]| { + let raw: Vec<$ty> = inputs.iter().map(|s| s.parse::<$ty>().unwrap()).collect(); + b.iter(move || { + for s in &raw { + let _ = black_box(s.is_ascii_alphanumeric()); + } + }) + } + }; + } + + bench_block!(c, "test_is_ascii_alphanumeric", tiaa); +} + +fn test_eq(c: &mut Criterion) { + macro_rules! te { + ($ty:ty) => { + |b: &mut Bencher, inputs: &&[&str]| { + let raw: Vec<$ty> = inputs.iter().map(|s| s.parse::<$ty>().unwrap()).collect(); + b.iter(move || { + for s in &raw { + for l in &raw { + let _ = black_box(s == l); + } + } + }) + } + }; + } + + bench_block!(c, "test_eq", te); +} + +criterion_group!( + benches, + convert_to_ascii_lowercase, + convert_to_ascii_uppercase, + convert_to_ascii_titlecase, + test_is_ascii_alphanumeric, + test_eq, +); +criterion_main!(benches); diff --git a/vendor/tinystr/examples/main.rs b/vendor/tinystr/examples/main.rs new file mode 100644 index 000000000..2e0d2a10b --- /dev/null +++ b/vendor/tinystr/examples/main.rs @@ -0,0 +1,18 @@ +use tinystr::{TinyStr4, TinyStr8}; + +fn main() { + let s1: TinyStr4 = "tEsT".parse().expect("Failed to parse."); + + assert_eq!(s1, "tEsT"); + assert_eq!(s1.to_ascii_uppercase(), "TEST"); + assert_eq!(s1.to_ascii_lowercase(), "test"); + assert_eq!(s1.to_ascii_titlecase(), "Test"); + assert_eq!(s1.is_ascii_alphanumeric(), true); + + let s2: TinyStr8 = "New York".parse().expect("Failed to parse."); + + assert_eq!(s2, "New York"); + assert_eq!(s2.to_ascii_uppercase(), "NEW YORK"); + assert_eq!(s2.to_ascii_lowercase(), "new york"); + assert_eq!(s2.is_ascii_alphanumeric(), false); +} diff --git a/vendor/tinystr/src/helpers.rs b/vendor/tinystr/src/helpers.rs new file mode 100644 index 000000000..c3d17d028 --- /dev/null +++ b/vendor/tinystr/src/helpers.rs @@ -0,0 +1,32 @@ +use std::num::NonZeroU32; +use std::ptr::copy_nonoverlapping; + +use super::Error; + +#[cfg(any(feature = "std", test))] +pub use std::string::String; + +#[cfg(all(not(feature = "std"), not(test)))] +extern crate alloc; + +#[cfg(all(not(feature = "std"), not(test)))] +pub use alloc::string::String; + +#[inline(always)] +pub(crate) unsafe fn make_4byte_bytes( + bytes: &[u8], + len: usize, + mask: u32, +) -> Result<NonZeroU32, Error> { + // Mask is always supplied as little-endian. + let mask = u32::from_le(mask); + let mut word: u32 = 0; + copy_nonoverlapping(bytes.as_ptr(), &mut word as *mut u32 as *mut u8, len); + if (word & mask) != 0 { + return Err(Error::NonAscii); + } + if ((mask - word) & mask) != 0 { + return Err(Error::InvalidNull); + } + Ok(NonZeroU32::new_unchecked(word)) +} diff --git a/vendor/tinystr/src/lib.rs b/vendor/tinystr/src/lib.rs new file mode 100644 index 000000000..6f4c59658 --- /dev/null +++ b/vendor/tinystr/src/lib.rs @@ -0,0 +1,105 @@ +//! `tinystr` is a small ASCII-only bounded length string representation. +//! +//! The crate is meant to be used for scenarios where one needs a fast +//! and memory efficient way to store and manipulate short ASCII-only strings. +//! +//! `tinystr` converts each string into an unsigned integer, and uses bitmasking +//! to compare, convert cases and test for common characteristics of strings. +//! +//! # Details +//! +//! The crate provides three structs and an enum: +//! * `TinyStr4` an ASCII-only string limited to 4 characters. +//! * `TinyStr8` an ASCII-only string limited to 8 characters. +//! * `TinyStr16` an ASCII-only string limited to 16 characters. +//! * `TinyStrAuto` (enum): +//! * `Tiny` when the string is 16 characters or less. +//! * `Heap` when the string is 17 or more characters. +//! +//! `TinyStrAuto` stores the string as a TinyStr16 when it is short enough, or else falls back to a +//! standard `String`. You should use TinyStrAuto when you expect most strings to be 16 characters +//! or smaller, but occasionally you receive one that exceeds that length. Unlike the structs, +//! `TinyStrAuto` does not implement `Copy`. +//! +//! # no_std +//! +//! Disable the `std` feature of this crate to make it `#[no_std]`. Doing so disables `TinyStrAuto`. +//! You can re-enable `TinyStrAuto` in `#[no_std]` mode by enabling the `alloc` feature. +//! +//! # Example +//! +//! ``` +//! use tinystr::{TinyStr4, TinyStr8, TinyStr16, TinyStrAuto}; +//! +//! let s1: TinyStr4 = "tEsT".parse() +//! .expect("Failed to parse."); +//! +//! assert_eq!(s1, "tEsT"); +//! assert_eq!(s1.to_ascii_uppercase(), "TEST"); +//! assert_eq!(s1.to_ascii_lowercase(), "test"); +//! assert_eq!(s1.to_ascii_titlecase(), "Test"); +//! assert_eq!(s1.is_ascii_alphanumeric(), true); +//! +//! let s2: TinyStr8 = "New York".parse() +//! .expect("Failed to parse."); +//! +//! assert_eq!(s2, "New York"); +//! assert_eq!(s2.to_ascii_uppercase(), "NEW YORK"); +//! assert_eq!(s2.to_ascii_lowercase(), "new york"); +//! assert_eq!(s2.to_ascii_titlecase(), "New york"); +//! assert_eq!(s2.is_ascii_alphanumeric(), false); +//! +//! let s3: TinyStr16 = "metaMoRphosis123".parse() +//! .expect("Failed to parse."); +//! +//! assert_eq!(s3, "metaMoRphosis123"); +//! assert_eq!(s3.to_ascii_uppercase(), "METAMORPHOSIS123"); +//! assert_eq!(s3.to_ascii_lowercase(), "metamorphosis123"); +//! assert_eq!(s3.to_ascii_titlecase(), "Metamorphosis123"); +//! assert_eq!(s3.is_ascii_alphanumeric(), true); +//! +//! let s4: TinyStrAuto = "shortNoAlloc".parse().unwrap(); +//! assert!(matches!(s4, TinyStrAuto::Tiny { .. })); +//! assert_eq!(s4, "shortNoAlloc"); +//! +//! let s5: TinyStrAuto = "longFallbackToHeap".parse().unwrap(); +//! assert!(matches!(s5, TinyStrAuto::Heap { .. })); +//! assert_eq!(s5, "longFallbackToHeap"); +//! ``` + +#![no_std] + +#[cfg(any(feature = "std", test))] +extern crate std; + +#[cfg(all(not(feature = "std"), not(test)))] +extern crate core as std; + +mod helpers; +mod tinystr16; +mod tinystr4; +mod tinystr8; + +#[cfg(any(feature = "std", feature = "alloc"))] +mod tinystrauto; + +pub use tinystr16::TinyStr16; +pub use tinystr4::TinyStr4; +pub use tinystr8::TinyStr8; + +#[cfg(any(feature = "std", feature = "alloc"))] +pub use tinystrauto::TinyStrAuto; + +#[cfg(feature = "macros")] +pub use tinystr_macros as macros; + +/// Enum to store the various types of errors that can cause parsing a TinyStr to fail. +#[derive(PartialEq, Eq, Debug)] +pub enum Error { + /// String is too large or too small to store as TinyStr. + InvalidSize, + /// String is empty. + InvalidNull, + /// String contains non-ASCII character(s). + NonAscii, +} diff --git a/vendor/tinystr/src/tinystr16.rs b/vendor/tinystr/src/tinystr16.rs new file mode 100644 index 000000000..7403813f2 --- /dev/null +++ b/vendor/tinystr/src/tinystr16.rs @@ -0,0 +1,327 @@ +use std::cmp::Ordering; +use std::convert::Into; +use std::fmt; +use std::num::NonZeroU128; +use std::ops::Deref; +use std::ptr::copy_nonoverlapping; +use std::str::FromStr; + +use crate::Error; + +/// A tiny string that is from 1 to 16 non-NUL ASCII characters. +/// +/// # Examples +/// +/// ``` +/// use tinystr::TinyStr16; +/// +/// let s1: TinyStr16 = "Metamorphosis".parse() +/// .expect("Failed to parse."); +/// +/// assert_eq!(s1, "Metamorphosis"); +/// assert!(s1.is_ascii_alphabetic()); +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct TinyStr16(NonZeroU128); + +impl TinyStr16 { + /// Creates a TinyStr16 from a byte slice. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr16; + /// + /// let s1 = TinyStr16::from_bytes("Testing".as_bytes()) + /// .expect("Failed to parse."); + /// + /// assert_eq!(s1, "Testing"); + /// ``` + #[inline(always)] + pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> { + let len = bytes.len(); + if len < 1 || len > 16 { + return Err(Error::InvalidSize); + } + unsafe { + let mut word: u128 = 0; + copy_nonoverlapping(bytes.as_ptr(), &mut word as *mut u128 as *mut u8, len); + let mask = 0x80808080_80808080_80808080_80808080u128 >> (8 * (16 - len)); + // TODO: could do this with #cfg(target_endian), but this is clearer and + // more confidence-inspiring. + let mask = u128::from_le(mask); + if (word & mask) != 0 { + return Err(Error::NonAscii); + } + if ((mask - word) & mask) != 0 { + return Err(Error::InvalidNull); + } + Ok(Self(NonZeroU128::new_unchecked(word))) + } + } + + /// An unsafe constructor intended for cases where the consumer + /// guarantees that the input is a little endian integer which + /// is a correct representation of a `TinyStr16` string. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr16; + /// + /// let s1: TinyStr16 = "Metamorphosis".parse() + /// .expect("Failed to parse."); + /// + /// let num: u128 = s1.into(); + /// + /// let s2 = unsafe { TinyStr16::new_unchecked(num) }; + /// + /// assert_eq!(s1, s2); + /// assert_eq!(s2.as_str(), "Metamorphosis"); + /// ``` + /// + /// # Safety + /// + /// The method does not validate the `u128` to be properly encoded + /// value for `TinyStr16`. + /// The value can be retrieved via `Into<u128> for TinyStr16`. + #[inline(always)] + pub const unsafe fn new_unchecked(text: u128) -> Self { + Self(NonZeroU128::new_unchecked(u128::from_le(text))) + } + + /// Extracts a string slice containing the entire `TinyStr16`. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr16; + /// + /// let s1: TinyStr16 = "Metamorphosis".parse() + /// .expect("Failed to parse."); + /// + /// assert_eq!(s1.as_str(), "Metamorphosis"); + /// ``` + #[inline(always)] + pub fn as_str(&self) -> &str { + self.deref() + } + + /// Checks if the value is composed of ASCII alphabetic characters: + /// + /// * U+0041 'A' ..= U+005A 'Z', or + /// * U+0061 'a' ..= U+007A 'z'. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr16; + /// + /// let s1: TinyStr16 = "Metamorphosis".parse() + /// .expect("Failed to parse."); + /// let s2: TinyStr16 = "Met3mo4pho!is".parse() + /// .expect("Failed to parse."); + /// + /// assert!(s1.is_ascii_alphabetic()); + /// assert!(!s2.is_ascii_alphabetic()); + /// ``` + pub fn is_ascii_alphabetic(self) -> bool { + let word = self.0.get(); + let mask = + (word + 0x7f7f7f7f_7f7f7f7f_7f7f7f7f_7f7f7f7f) & 0x80808080_80808080_80808080_80808080; + let lower = word | 0x20202020_20202020_20202020_20202020; + let alpha = !(lower + 0x1f1f1f1f_1f1f1f1f_1f1f1f1f_1f1f1f1f) + | (lower + 0x05050505_05050505_05050505_05050505); + (alpha & mask) == 0 + } + + /// Checks if the value is composed of ASCII alphanumeric characters: + /// + /// * U+0041 'A' ..= U+005A 'Z', or + /// * U+0061 'a' ..= U+007A 'z', or + /// * U+0030 '0' ..= U+0039 '9'. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr16; + /// + /// let s1: TinyStr16 = "A15bingA1".parse() + /// .expect("Failed to parse."); + /// let s2: TinyStr16 = "[3@w00Fs1".parse() + /// .expect("Failed to parse."); + /// + /// assert!(s1.is_ascii_alphanumeric()); + /// assert!(!s2.is_ascii_alphanumeric()); + /// ``` + pub fn is_ascii_alphanumeric(self) -> bool { + let word = self.0.get(); + let mask = + (word + 0x7f7f7f7f_7f7f7f7f_7f7f7f7f_7f7f7f7f) & 0x80808080_80808080_80808080_80808080; + let numeric = !(word + 0x50505050_50505050_50505050_50505050) + | (word + 0x46464646_46464646_46464646_46464646); + let lower = word | 0x20202020_20202020_20202020_20202020; + let alpha = !(lower + 0x1f1f1f1f_1f1f1f1f_1f1f1f1f_1f1f1f1f) + | (lower + 0x05050505_05050505_05050505_05050505); + (alpha & numeric & mask) == 0 + } + + /// Checks if the value is composed of ASCII decimal digits: + /// + /// * U+0030 '0' ..= U+0039 '9'. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr16; + /// + /// let s1: TinyStr16 = "31212314141".parse() + /// .expect("Failed to parse."); + /// let s2: TinyStr16 = "3d3d3d3d".parse() + /// .expect("Failed to parse."); + /// + /// assert!(s1.is_ascii_numeric()); + /// assert!(!s2.is_ascii_numeric()); + /// ``` + pub fn is_ascii_numeric(self) -> bool { + let word = self.0.get(); + let mask = + (word + 0x7f7f7f7f_7f7f7f7f_7f7f7f7f_7f7f7f7f) & 0x80808080_80808080_80808080_80808080; + let numeric = !(word + 0x50505050_50505050_50505050_50505050) + | (word + 0x46464646_46464646_46464646_46464646); + (numeric & mask) == 0 + } + + /// Converts this type to its ASCII lower case equivalent in-place. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', other characters are unchanged. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr16; + /// + /// let s1: TinyStr16 = "MeTAmOrpHo3sis".parse() + /// .expect("Failed to parse."); + /// + /// assert_eq!(s1.to_ascii_lowercase(), "metamorpho3sis"); + /// ``` + pub fn to_ascii_lowercase(self) -> Self { + let word = self.0.get(); + let result = word + | (((word + 0x3f3f3f3f_3f3f3f3f_3f3f3f3f_3f3f3f3f) + & !(word + 0x25252525_25252525_25252525_25252525) + & 0x80808080_80808080_80808080_80808080) + >> 2); + unsafe { Self(NonZeroU128::new_unchecked(result)) } + } + + /// Converts this type to its ASCII title case equivalent in-place. + /// + /// First character, if is an ASCII letter 'a' to 'z' is mapped to 'A' to 'Z', + /// other characters are unchanged. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr16; + /// + /// let s1: TinyStr16 = "metamorphosis".parse() + /// .expect("Failed to parse."); + /// + /// assert_eq!(s1.to_ascii_titlecase(), "Metamorphosis"); + /// ``` + pub fn to_ascii_titlecase(self) -> Self { + let word = self.0.get().to_le(); + let mask = ((word + 0x3f3f3f3f_3f3f3f3f_3f3f3f3f_3f3f3f1f) + & !(word + 0x25252525_25252525_25252525_25252505) + & 0x80808080_80808080_80808080_80808080) + >> 2; + let result = (word | mask) & !(0x20 & mask); + unsafe { Self(NonZeroU128::new_unchecked(u128::from_le(result))) } + } + + /// Converts this type to its ASCII upper case equivalent in-place. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', other characters are unchanged. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr16; + /// + /// let s1: TinyStr16 = "Met3amorphosis".parse() + /// .expect("Failed to parse."); + /// + /// assert_eq!(s1.to_ascii_uppercase(), "MET3AMORPHOSIS"); + /// ``` + pub fn to_ascii_uppercase(self) -> Self { + let word = self.0.get(); + let result = word + & !(((word + 0x1f1f1f1f_1f1f1f1f_1f1f1f1f_1f1f1f1f) + & !(word + 0x05050505_05050505_05050505_05050505) + & 0x80808080_80808080_80808080_80808080) + >> 2); + unsafe { Self(NonZeroU128::new_unchecked(result)) } + } +} + +impl fmt::Display for TinyStr16 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.deref()) + } +} + +impl fmt::Debug for TinyStr16 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self.deref()) + } +} + +impl Deref for TinyStr16 { + type Target = str; + + #[inline(always)] + fn deref(&self) -> &str { + // Again, could use #cfg to hand-roll a big-endian implementation. + let word = self.0.get().to_le(); + let len = (16 - word.leading_zeros() / 8) as usize; + unsafe { + let slice = core::slice::from_raw_parts(&self.0 as *const _ as *const u8, len); + std::str::from_utf8_unchecked(slice) + } + } +} + +impl PartialEq<&str> for TinyStr16 { + fn eq(&self, other: &&str) -> bool { + self.deref() == *other + } +} + +impl PartialOrd for TinyStr16 { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +impl Ord for TinyStr16 { + fn cmp(&self, other: &Self) -> Ordering { + self.0.get().to_be().cmp(&other.0.get().to_be()) + } +} + +impl FromStr for TinyStr16 { + type Err = Error; + + #[inline(always)] + fn from_str(text: &str) -> Result<Self, Self::Err> { + Self::from_bytes(text.as_bytes()) + } +} + +impl Into<u128> for TinyStr16 { + fn into(self) -> u128 { + self.0.get().to_le() + } +} diff --git a/vendor/tinystr/src/tinystr4.rs b/vendor/tinystr/src/tinystr4.rs new file mode 100644 index 000000000..c63d25113 --- /dev/null +++ b/vendor/tinystr/src/tinystr4.rs @@ -0,0 +1,299 @@ +use std::cmp::Ordering; +use std::convert::Into; +use std::fmt; +use std::num::NonZeroU32; +use std::ops::Deref; +use std::str::FromStr; + +use crate::helpers::make_4byte_bytes; +use crate::Error; + +/// A tiny string that is from 1 to 4 non-NUL ASCII characters. +/// +/// # Examples +/// +/// ``` +/// use tinystr::TinyStr4; +/// +/// let s1: TinyStr4 = "Test".parse() +/// .expect("Failed to parse."); +/// +/// assert_eq!(s1, "Test"); +/// assert!(s1.is_ascii_alphabetic()); +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct TinyStr4(NonZeroU32); + +impl TinyStr4 { + /// Creates a TinyStr4 from a byte slice. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr4; + /// + /// let s1 = TinyStr4::from_bytes("Test".as_bytes()) + /// .expect("Failed to parse."); + /// + /// assert_eq!(s1, "Test"); + /// ``` + #[inline(always)] + pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> { + unsafe { + match bytes.len() { + 1 => make_4byte_bytes(bytes, 1, 0x80).map(Self), + 2 => make_4byte_bytes(bytes, 2, 0x8080).map(Self), + 3 => make_4byte_bytes(bytes, 3, 0x0080_8080).map(Self), + 4 => make_4byte_bytes(bytes, 4, 0x8080_8080).map(Self), + _ => Err(Error::InvalidSize), + } + } + } + + /// An unsafe constructor intended for cases where the consumer + /// guarantees that the input is a little endian integer which + /// is a correct representation of a `TinyStr4` string. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr4; + /// + /// let s1: TinyStr4 = "Test".parse() + /// .expect("Failed to parse."); + /// + /// let num: u32 = s1.into(); + /// + /// let s2 = unsafe { TinyStr4::new_unchecked(num) }; + /// + /// assert_eq!(s1, s2); + /// assert_eq!(s2.as_str(), "Test"); + /// ``` + /// + /// # Safety + /// + /// The method does not validate the `u32` to be properly encoded + /// value for `TinyStr4`. + /// The value can be retrieved via `Into<u32> for TinyStr4`. + #[inline(always)] + pub const unsafe fn new_unchecked(text: u32) -> Self { + Self(NonZeroU32::new_unchecked(u32::from_le(text))) + } + + /// Extracts a string slice containing the entire `TinyStr4`. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr4; + /// + /// let s1: TinyStr4 = "Test".parse() + /// .expect("Failed to parse."); + /// + /// assert_eq!(s1.as_str(), "Test"); + /// ``` + #[inline(always)] + pub fn as_str(&self) -> &str { + self.deref() + } + + /// Checks if the value is composed of ASCII alphabetic characters: + /// + /// * U+0041 'A' ..= U+005A 'Z', or + /// * U+0061 'a' ..= U+007A 'z'. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr4; + /// + /// let s1: TinyStr4 = "Test".parse() + /// .expect("Failed to parse."); + /// let s2: TinyStr4 = "Te3t".parse() + /// .expect("Failed to parse."); + /// + /// assert!(s1.is_ascii_alphabetic()); + /// assert!(!s2.is_ascii_alphabetic()); + /// ``` + pub fn is_ascii_alphabetic(self) -> bool { + let word = self.0.get(); + let mask = (word + 0x7f7f_7f7f) & 0x8080_8080; + let lower = word | 0x2020_2020; + let alpha = !(lower + 0x1f1f_1f1f) | (lower + 0x0505_0505); + (alpha & mask) == 0 + } + + /// Checks if the value is composed of ASCII alphanumeric characters: + /// + /// * U+0041 'A' ..= U+005A 'Z', or + /// * U+0061 'a' ..= U+007A 'z', or + /// * U+0030 '0' ..= U+0039 '9'. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr4; + /// + /// let s1: TinyStr4 = "A15b".parse() + /// .expect("Failed to parse."); + /// let s2: TinyStr4 = "[3@w".parse() + /// .expect("Failed to parse."); + /// + /// assert!(s1.is_ascii_alphanumeric()); + /// assert!(!s2.is_ascii_alphanumeric()); + /// ``` + pub fn is_ascii_alphanumeric(self) -> bool { + let word = self.0.get(); + let mask = (word + 0x7f7f_7f7f) & 0x8080_8080; + let numeric = !(word + 0x5050_5050) | (word + 0x4646_4646); + let lower = word | 0x2020_2020; + let alpha = !(lower + 0x1f1f_1f1f) | (lower + 0x0505_0505); + (alpha & numeric & mask) == 0 + } + + /// Checks if the value is composed of ASCII decimal digits: + /// + /// * U+0030 '0' ..= U+0039 '9'. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr4; + /// + /// let s1: TinyStr4 = "312".parse() + /// .expect("Failed to parse."); + /// let s2: TinyStr4 = "3d".parse() + /// .expect("Failed to parse."); + /// + /// assert!(s1.is_ascii_numeric()); + /// assert!(!s2.is_ascii_numeric()); + /// ``` + pub fn is_ascii_numeric(self) -> bool { + let word = self.0.get(); + let mask = (word + 0x7f7f_7f7f) & 0x8080_8080; + let numeric = !(word + 0x5050_5050) | (word + 0x4646_4646); + (numeric & mask) == 0 + } + + /// Converts this type to its ASCII lower case equivalent in-place. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', other characters are unchanged. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr4; + /// + /// let s1: TinyStr4 = "TeS3".parse() + /// .expect("Failed to parse."); + /// + /// assert_eq!(s1.to_ascii_lowercase(), "tes3"); + /// ``` + pub fn to_ascii_lowercase(self) -> Self { + let word = self.0.get(); + let result = word | (((word + 0x3f3f_3f3f) & !(word + 0x2525_2525) & 0x8080_8080) >> 2); + unsafe { Self(NonZeroU32::new_unchecked(result)) } + } + + /// Converts this type to its ASCII title case equivalent in-place. + /// + /// First character, if is an ASCII letter 'a' to 'z' is mapped to 'A' to 'Z', + /// other characters are unchanged. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr4; + /// + /// let s1: TinyStr4 = "test".parse() + /// .expect("Failed to parse."); + /// + /// assert_eq!(s1.to_ascii_titlecase(), "Test"); + /// ``` + pub fn to_ascii_titlecase(self) -> Self { + let word = self.0.get().to_le(); + let mask = ((word + 0x3f3f_3f1f) & !(word + 0x2525_2505) & 0x8080_8080) >> 2; + let result = (word | mask) & !(0x20 & mask); + unsafe { Self(NonZeroU32::new_unchecked(u32::from_le(result))) } + } + + /// Converts this type to its ASCII upper case equivalent in-place. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', other characters are unchanged. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr4; + /// + /// let s1: TinyStr4 = "Tes3".parse() + /// .expect("Failed to parse."); + /// + /// assert_eq!(s1.to_ascii_uppercase(), "TES3"); + /// ``` + pub fn to_ascii_uppercase(self) -> Self { + let word = self.0.get(); + let result = word & !(((word + 0x1f1f_1f1f) & !(word + 0x0505_0505) & 0x8080_8080) >> 2); + unsafe { Self(NonZeroU32::new_unchecked(result)) } + } +} + +impl fmt::Display for TinyStr4 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.deref()) + } +} + +impl fmt::Debug for TinyStr4 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self.deref()) + } +} + +impl Deref for TinyStr4 { + type Target = str; + + #[inline(always)] + fn deref(&self) -> &str { + // Again, could use #cfg to hand-roll a big-endian implementation. + let word = self.0.get().to_le(); + let len = (4 - word.leading_zeros() / 8) as usize; + unsafe { + let slice = core::slice::from_raw_parts(&self.0 as *const _ as *const u8, len); + std::str::from_utf8_unchecked(slice) + } + } +} + +impl PartialEq<&str> for TinyStr4 { + fn eq(&self, other: &&str) -> bool { + self.deref() == *other + } +} + +impl PartialOrd for TinyStr4 { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +impl Ord for TinyStr4 { + fn cmp(&self, other: &Self) -> Ordering { + self.0.get().to_be().cmp(&other.0.get().to_be()) + } +} + +impl FromStr for TinyStr4 { + type Err = Error; + + #[inline(always)] + fn from_str(text: &str) -> Result<Self, Self::Err> { + Self::from_bytes(text.as_bytes()) + } +} + +impl Into<u32> for TinyStr4 { + fn into(self) -> u32 { + self.0.get().to_le() + } +} diff --git a/vendor/tinystr/src/tinystr8.rs b/vendor/tinystr/src/tinystr8.rs new file mode 100644 index 000000000..e121c519a --- /dev/null +++ b/vendor/tinystr/src/tinystr8.rs @@ -0,0 +1,319 @@ +use std::cmp::Ordering; +use std::convert::Into; +use std::fmt; +use std::num::NonZeroU64; +use std::ops::Deref; +use std::ptr::copy_nonoverlapping; +use std::str::FromStr; + +use crate::Error; + +/// A tiny string that is from 1 to 8 non-NUL ASCII characters. +/// +/// # Examples +/// +/// ``` +/// use tinystr::TinyStr8; +/// +/// let s1: TinyStr8 = "Testing".parse() +/// .expect("Failed to parse."); +/// +/// assert_eq!(s1, "Testing"); +/// assert!(s1.is_ascii_alphabetic()); +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct TinyStr8(NonZeroU64); + +impl TinyStr8 { + /// Creates a TinyStr8 from a byte slice. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr8; + /// + /// let s1 = TinyStr8::from_bytes("Testing".as_bytes()) + /// .expect("Failed to parse."); + /// + /// assert_eq!(s1, "Testing"); + /// ``` + #[inline(always)] + pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> { + let len = bytes.len(); + if len < 1 || len > 8 { + return Err(Error::InvalidSize); + } + unsafe { + let mut word: u64 = 0; + copy_nonoverlapping(bytes.as_ptr(), &mut word as *mut u64 as *mut u8, len); + let mask = 0x80808080_80808080u64 >> (8 * (8 - len)); + // TODO: could do this with #cfg(target_endian), but this is clearer and + // more confidence-inspiring. + let mask = u64::from_le(mask); + if (word & mask) != 0 { + return Err(Error::NonAscii); + } + if ((mask - word) & mask) != 0 { + return Err(Error::InvalidNull); + } + Ok(Self(NonZeroU64::new_unchecked(word))) + } + } + + /// An unsafe constructor intended for cases where the consumer + /// guarantees that the input is a little endian integer which + /// is a correct representation of a `TinyStr8` string. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr8; + /// + /// let s1: TinyStr8 = "Testing".parse() + /// .expect("Failed to parse."); + /// + /// let num: u64 = s1.into(); + /// + /// let s2 = unsafe { TinyStr8::new_unchecked(num) }; + /// + /// assert_eq!(s1, s2); + /// assert_eq!(s2.as_str(), "Testing"); + /// ``` + /// + /// # Safety + /// + /// The method does not validate the `u64` to be properly encoded + /// value for `TinyStr8`. + /// The value can be retrieved via `Into<u64> for TinyStr8`. + #[inline(always)] + pub const unsafe fn new_unchecked(text: u64) -> Self { + Self(NonZeroU64::new_unchecked(u64::from_le(text))) + } + + /// Extracts a string slice containing the entire `TinyStr8`. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr8; + /// + /// let s1: TinyStr8 = "Testing".parse() + /// .expect("Failed to parse."); + /// + /// assert_eq!(s1.as_str(), "Testing"); + /// ``` + #[inline(always)] + pub fn as_str(&self) -> &str { + self.deref() + } + + /// Checks if the value is composed of ASCII alphabetic characters: + /// + /// * U+0041 'A' ..= U+005A 'Z', or + /// * U+0061 'a' ..= U+007A 'z'. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr8; + /// + /// let s1: TinyStr8 = "Testing".parse() + /// .expect("Failed to parse."); + /// let s2: TinyStr8 = "Te3ting".parse() + /// .expect("Failed to parse."); + /// + /// assert!(s1.is_ascii_alphabetic()); + /// assert!(!s2.is_ascii_alphabetic()); + /// ``` + pub fn is_ascii_alphabetic(self) -> bool { + let word = self.0.get(); + let mask = (word + 0x7f7f7f7f_7f7f7f7f) & 0x80808080_80808080; + let lower = word | 0x20202020_20202020; + let alpha = !(lower + 0x1f1f1f1f_1f1f1f1f) | (lower + 0x05050505_05050505); + (alpha & mask) == 0 + } + + /// Checks if the value is composed of ASCII alphanumeric characters: + /// + /// * U+0041 'A' ..= U+005A 'Z', or + /// * U+0061 'a' ..= U+007A 'z', or + /// * U+0030 '0' ..= U+0039 '9'. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr8; + /// + /// let s1: TinyStr8 = "A15bing".parse() + /// .expect("Failed to parse."); + /// let s2: TinyStr8 = "[3@wing".parse() + /// .expect("Failed to parse."); + /// + /// assert!(s1.is_ascii_alphanumeric()); + /// assert!(!s2.is_ascii_alphanumeric()); + /// ``` + pub fn is_ascii_alphanumeric(self) -> bool { + let word = self.0.get(); + let mask = (word + 0x7f7f7f7f_7f7f7f7f) & 0x80808080_80808080; + let numeric = !(word + 0x50505050_50505050) | (word + 0x46464646_46464646); + let lower = word | 0x20202020_20202020; + let alpha = !(lower + 0x1f1f1f1f_1f1f1f1f) | (lower + 0x05050505_05050505); + (alpha & numeric & mask) == 0 + } + + /// Checks if the value is composed of ASCII decimal digits: + /// + /// * U+0030 '0' ..= U+0039 '9'. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr8; + /// + /// let s1: TinyStr8 = "3121029".parse() + /// .expect("Failed to parse."); + /// let s2: TinyStr8 = "3d212d".parse() + /// .expect("Failed to parse."); + /// + /// assert!(s1.is_ascii_numeric()); + /// assert!(!s2.is_ascii_numeric()); + /// ``` + pub fn is_ascii_numeric(self) -> bool { + let word = self.0.get(); + let mask = (word + 0x7f7f7f7f_7f7f7f7f) & 0x80808080_80808080; + let numeric = !(word + 0x50505050_50505050) | (word + 0x46464646_46464646); + (numeric & mask) == 0 + } + + /// Converts this type to its ASCII lower case equivalent in-place. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', other characters are unchanged. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr8; + /// + /// let s1: TinyStr8 = "TeS3ing".parse() + /// .expect("Failed to parse."); + /// + /// assert_eq!(s1.to_ascii_lowercase(), "tes3ing"); + /// ``` + pub fn to_ascii_lowercase(self) -> Self { + let word = self.0.get(); + let result = word + | (((word + 0x3f3f3f3f_3f3f3f3f) + & !(word + 0x25252525_25252525) + & 0x80808080_80808080) + >> 2); + unsafe { Self(NonZeroU64::new_unchecked(result)) } + } + + /// Converts this type to its ASCII title case equivalent in-place. + /// + /// First character, if is an ASCII letter 'a' to 'z' is mapped to 'A' to 'Z', + /// other characters are unchanged. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr8; + /// + /// let s1: TinyStr8 = "testing".parse() + /// .expect("Failed to parse."); + /// + /// assert_eq!(s1.to_ascii_titlecase(), "Testing"); + /// ``` + pub fn to_ascii_titlecase(self) -> Self { + let word = self.0.get().to_le(); + let mask = + ((word + 0x3f3f3f3f_3f3f3f1f) & !(word + 0x25252525_25252505) & 0x80808080_80808080) + >> 2; + let result = (word | mask) & !(0x20 & mask); + unsafe { Self(NonZeroU64::new_unchecked(u64::from_le(result))) } + } + + /// Converts this type to its ASCII upper case equivalent in-place. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', other characters are unchanged. + /// + /// # Examples + /// + /// ``` + /// use tinystr::TinyStr8; + /// + /// let s1: TinyStr8 = "Tes3ing".parse() + /// .expect("Failed to parse."); + /// + /// assert_eq!(s1.to_ascii_uppercase(), "TES3ING"); + /// ``` + pub fn to_ascii_uppercase(self) -> Self { + let word = self.0.get(); + let result = word + & !(((word + 0x1f1f1f1f_1f1f1f1f) + & !(word + 0x05050505_05050505) + & 0x80808080_80808080) + >> 2); + unsafe { Self(NonZeroU64::new_unchecked(result)) } + } +} + +impl fmt::Display for TinyStr8 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.deref()) + } +} + +impl fmt::Debug for TinyStr8 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self.deref()) + } +} + +impl Deref for TinyStr8 { + type Target = str; + + #[inline(always)] + fn deref(&self) -> &str { + // Again, could use #cfg to hand-roll a big-endian implementation. + let word = self.0.get().to_le(); + let len = (8 - word.leading_zeros() / 8) as usize; + unsafe { + let slice = core::slice::from_raw_parts(&self.0 as *const _ as *const u8, len); + std::str::from_utf8_unchecked(slice) + } + } +} + +impl PartialEq<&str> for TinyStr8 { + fn eq(&self, other: &&str) -> bool { + self.deref() == *other + } +} + +impl PartialOrd for TinyStr8 { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(self.cmp(other)) + } +} + +impl Ord for TinyStr8 { + fn cmp(&self, other: &Self) -> Ordering { + self.0.get().to_be().cmp(&other.0.get().to_be()) + } +} + +impl FromStr for TinyStr8 { + type Err = Error; + + #[inline(always)] + fn from_str(text: &str) -> Result<Self, Self::Err> { + TinyStr8::from_bytes(text.as_bytes()) + } +} + +impl Into<u64> for TinyStr8 { + fn into(self) -> u64 { + self.0.get().to_le() + } +} diff --git a/vendor/tinystr/src/tinystrauto.rs b/vendor/tinystr/src/tinystrauto.rs new file mode 100644 index 000000000..9e2387cc1 --- /dev/null +++ b/vendor/tinystr/src/tinystrauto.rs @@ -0,0 +1,72 @@ +use std::fmt; +use std::ops::Deref; +use std::str::FromStr; + +use crate::helpers::String; +use crate::Error; +use crate::TinyStr16; + +/// An ASCII string that is tiny when <= 16 chars and a String otherwise. +/// +/// # Examples +/// +/// ``` +/// use tinystr::TinyStrAuto; +/// +/// let s1: TinyStrAuto = "Testing".parse() +/// .expect("Failed to parse."); +/// +/// assert_eq!(s1, "Testing"); +/// ``` +#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] +pub enum TinyStrAuto { + /// Up to 16 characters stored on the stack. + Tiny(TinyStr16), + /// 17 or more characters stored on the heap. + Heap(String), +} + +impl fmt::Display for TinyStrAuto { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.deref().fmt(f) + } +} + +impl Deref for TinyStrAuto { + type Target = str; + + fn deref(&self) -> &str { + use TinyStrAuto::*; + match self { + Tiny(value) => value.deref(), + Heap(value) => value.deref(), + } + } +} + +impl PartialEq<&str> for TinyStrAuto { + fn eq(&self, other: &&str) -> bool { + self.deref() == *other + } +} + +impl FromStr for TinyStrAuto { + type Err = Error; + + fn from_str(text: &str) -> Result<Self, Self::Err> { + if text.len() <= 16 { + match TinyStr16::from_str(text) { + Ok(result) => Ok(TinyStrAuto::Tiny(result)), + Err(err) => Err(err), + } + } else { + if !text.is_ascii() { + return Err(Error::NonAscii); + } + match String::from_str(text) { + Ok(result) => Ok(TinyStrAuto::Heap(result)), + Err(_) => unreachable!(), + } + } + } +} diff --git a/vendor/tinystr/tests/main.rs b/vendor/tinystr/tests/main.rs new file mode 100644 index 000000000..a9cf7be1a --- /dev/null +++ b/vendor/tinystr/tests/main.rs @@ -0,0 +1,538 @@ +use std::fmt::Write; +use std::mem::size_of; +use std::ops::Deref; +use tinystr::{Error, TinyStr16, TinyStr4, TinyStr8}; + +#[cfg(any(feature = "std", feature = "alloc"))] +use tinystr::TinyStrAuto; + +#[test] +fn tiny_sizes() { + assert_eq!(4, size_of::<TinyStr4>()); + assert_eq!(8, size_of::<TinyStr8>()); + assert_eq!(16, size_of::<TinyStr16>()); + assert_eq!(24, size_of::<String>()); + // Note: TinyStrAuto is size 32 even when a smaller TinyStr type is used + #[cfg(any(feature = "std", feature = "alloc"))] + assert_eq!(32, size_of::<TinyStrAuto>()); +} + +#[test] +fn tiny4_basic() { + let s: TinyStr4 = "abc".parse().unwrap(); + assert_eq!(s.deref(), "abc"); +} + +#[test] +fn tiny4_from_bytes() { + let s = TinyStr4::from_bytes("abc".as_bytes()).unwrap(); + assert_eq!(s.deref(), "abc"); + + assert_eq!( + TinyStr4::from_bytes(&[0, 159, 146, 150]), + Err(Error::NonAscii) + ); + assert_eq!(TinyStr4::from_bytes(&[]), Err(Error::InvalidSize)); + assert_eq!(TinyStr4::from_bytes(&[0]), Err(Error::InvalidNull)); +} + +#[test] +fn tiny4_size() { + assert_eq!("".parse::<TinyStr4>(), Err(Error::InvalidSize)); + assert!("1".parse::<TinyStr4>().is_ok()); + assert!("12".parse::<TinyStr4>().is_ok()); + assert!("123".parse::<TinyStr4>().is_ok()); + assert!("1234".parse::<TinyStr4>().is_ok()); + assert_eq!("12345".parse::<TinyStr4>(), Err(Error::InvalidSize)); + assert_eq!("123456789".parse::<TinyStr4>(), Err(Error::InvalidSize)); +} + +#[test] +fn tiny4_null() { + assert_eq!("a\u{0}b".parse::<TinyStr4>(), Err(Error::InvalidNull)); +} + +#[test] +fn tiny4_new_unchecked() { + let reference: TinyStr4 = "en".parse().unwrap(); + let uval: u32 = reference.into(); + let s = unsafe { TinyStr4::new_unchecked(uval) }; + assert_eq!(s, reference); + assert_eq!(s, "en"); +} + +#[test] +fn tiny4_nonascii() { + assert_eq!("\u{4000}".parse::<TinyStr4>(), Err(Error::NonAscii)); +} + +#[test] +fn tiny4_alpha() { + let s: TinyStr4 = "@aZ[".parse().unwrap(); + assert!(!s.is_ascii_alphabetic()); + assert!(!s.is_ascii_alphanumeric()); + assert_eq!(s.to_ascii_uppercase().as_str(), "@AZ["); + assert_eq!(s.to_ascii_lowercase().as_str(), "@az["); + + assert!("abYZ".parse::<TinyStr4>().unwrap().is_ascii_alphabetic()); + assert!("abYZ".parse::<TinyStr4>().unwrap().is_ascii_alphanumeric()); + assert!("a123".parse::<TinyStr4>().unwrap().is_ascii_alphanumeric()); + assert!(!"a123".parse::<TinyStr4>().unwrap().is_ascii_alphabetic()); +} + +#[test] +fn tiny4_numeric() { + let s: TinyStr4 = "@aZ[".parse().unwrap(); + assert!(!s.is_ascii_numeric()); + + assert!("0123".parse::<TinyStr4>().unwrap().is_ascii_numeric()); +} + +#[test] +fn tiny4_titlecase() { + assert_eq!( + "abcd" + .parse::<TinyStr4>() + .unwrap() + .to_ascii_titlecase() + .as_str(), + "Abcd" + ); + assert_eq!( + "ABCD" + .parse::<TinyStr4>() + .unwrap() + .to_ascii_titlecase() + .as_str(), + "Abcd" + ); + assert_eq!( + "aBCD" + .parse::<TinyStr4>() + .unwrap() + .to_ascii_titlecase() + .as_str(), + "Abcd" + ); + assert_eq!( + "A123" + .parse::<TinyStr4>() + .unwrap() + .to_ascii_titlecase() + .as_str(), + "A123" + ); + assert_eq!( + "123a" + .parse::<TinyStr4>() + .unwrap() + .to_ascii_titlecase() + .as_str(), + "123a" + ); +} + +#[test] +fn tiny4_ord() { + let mut v: Vec<TinyStr4> = vec!["zh".parse().unwrap(), "fr".parse().unwrap()]; + v.sort(); + + assert_eq!(v.get(0).unwrap().as_str(), "fr"); + assert_eq!(v.get(1).unwrap().as_str(), "zh"); +} + +#[test] +fn tiny4_eq() { + let s1: TinyStr4 = "en".parse().unwrap(); + let s2: TinyStr4 = "fr".parse().unwrap(); + let s3: TinyStr4 = "en".parse().unwrap(); + + assert_eq!(s1, s3); + assert_ne!(s1, s2); +} + +#[test] +fn tiny4_display() { + let s: TinyStr4 = "abcd".parse().unwrap(); + let mut result = String::new(); + write!(result, "{}", s).unwrap(); + assert_eq!(result, "abcd"); + assert_eq!(format!("{}", s), "abcd"); +} + +#[test] +fn tiny4_debug() { + let s: TinyStr4 = "abcd".parse().unwrap(); + assert_eq!(format!("{:#?}", s), "\"abcd\""); +} + +#[test] +fn tiny8_basic() { + let s: TinyStr8 = "abcde".parse().unwrap(); + assert_eq!(s.deref(), "abcde"); +} + +#[test] +fn tiny8_from_bytes() { + let s = TinyStr8::from_bytes("abcde".as_bytes()).unwrap(); + assert_eq!(s.deref(), "abcde"); + + assert_eq!( + TinyStr8::from_bytes(&[0, 159, 146, 150]), + Err(Error::NonAscii) + ); + assert_eq!(TinyStr8::from_bytes(&[]), Err(Error::InvalidSize)); + assert_eq!(TinyStr8::from_bytes(&[0]), Err(Error::InvalidNull)); +} + +#[test] +fn tiny8_size() { + assert_eq!("".parse::<TinyStr8>(), Err(Error::InvalidSize)); + assert!("1".parse::<TinyStr8>().is_ok()); + assert!("12".parse::<TinyStr8>().is_ok()); + assert!("123".parse::<TinyStr8>().is_ok()); + assert!("1234".parse::<TinyStr8>().is_ok()); + assert!("12345".parse::<TinyStr8>().is_ok()); + assert!("123456".parse::<TinyStr8>().is_ok()); + assert!("1234567".parse::<TinyStr8>().is_ok()); + assert!("12345678".parse::<TinyStr8>().is_ok()); + assert_eq!("123456789".parse::<TinyStr8>(), Err(Error::InvalidSize)); +} + +#[test] +fn tiny8_null() { + assert_eq!("a\u{0}b".parse::<TinyStr8>(), Err(Error::InvalidNull)); +} + +#[test] +fn tiny8_new_unchecked() { + let reference: TinyStr8 = "Windows".parse().unwrap(); + let uval: u64 = reference.into(); + let s = unsafe { TinyStr8::new_unchecked(uval) }; + assert_eq!(s, reference); + assert_eq!(s, "Windows"); +} + +#[test] +fn tiny8_nonascii() { + assert_eq!("\u{4000}".parse::<TinyStr8>(), Err(Error::NonAscii)); +} + +#[test] +fn tiny8_alpha() { + let s: TinyStr8 = "@abcXYZ[".parse().unwrap(); + assert!(!s.is_ascii_alphabetic()); + assert!(!s.is_ascii_alphanumeric()); + assert_eq!(s.to_ascii_uppercase().as_str(), "@ABCXYZ["); + assert_eq!(s.to_ascii_lowercase().as_str(), "@abcxyz["); + + assert!("abcXYZ".parse::<TinyStr8>().unwrap().is_ascii_alphabetic()); + assert!("abcXYZ" + .parse::<TinyStr8>() + .unwrap() + .is_ascii_alphanumeric()); + assert!(!"abc123".parse::<TinyStr8>().unwrap().is_ascii_alphabetic()); + assert!("abc123" + .parse::<TinyStr8>() + .unwrap() + .is_ascii_alphanumeric()); +} + +#[test] +fn tiny8_numeric() { + let s: TinyStr8 = "@abcXYZ[".parse().unwrap(); + assert!(!s.is_ascii_numeric()); + + assert!("01234567".parse::<TinyStr8>().unwrap().is_ascii_numeric()); +} + +#[test] +fn tiny8_titlecase() { + assert_eq!( + "abcdabcd" + .parse::<TinyStr8>() + .unwrap() + .to_ascii_titlecase() + .as_str(), + "Abcdabcd" + ); + assert_eq!( + "ABCDABCD" + .parse::<TinyStr8>() + .unwrap() + .to_ascii_titlecase() + .as_str(), + "Abcdabcd" + ); + assert_eq!( + "aBCDaBCD" + .parse::<TinyStr8>() + .unwrap() + .to_ascii_titlecase() + .as_str(), + "Abcdabcd" + ); + assert_eq!( + "A123a123" + .parse::<TinyStr8>() + .unwrap() + .to_ascii_titlecase() + .as_str(), + "A123a123" + ); + assert_eq!( + "123a123A" + .parse::<TinyStr8>() + .unwrap() + .to_ascii_titlecase() + .as_str(), + "123a123a" + ); +} + +#[test] +fn tiny8_ord() { + let mut v: Vec<TinyStr8> = vec!["nedis".parse().unwrap(), "macos".parse().unwrap()]; + v.sort(); + + assert_eq!(v.get(0).unwrap().as_str(), "macos"); + assert_eq!(v.get(1).unwrap().as_str(), "nedis"); +} + +#[test] +fn tiny8_eq() { + let s1: TinyStr8 = "windows".parse().unwrap(); + let s2: TinyStr8 = "mac".parse().unwrap(); + let s3: TinyStr8 = "windows".parse().unwrap(); + + assert_eq!(s1, s3); + assert_ne!(s1, s2); +} + +#[test] +fn tiny8_display() { + let s: TinyStr8 = "abcdef".parse().unwrap(); + let mut result = String::new(); + write!(result, "{}", s).unwrap(); + assert_eq!(result, "abcdef"); + assert_eq!(format!("{}", s), "abcdef"); +} + +#[test] +fn tiny8_debug() { + let s: TinyStr8 = "abcdef".parse().unwrap(); + assert_eq!(format!("{:#?}", s), "\"abcdef\""); +} + +#[test] +fn tiny16_from_bytes() { + let s = TinyStr16::from_bytes("abcdefghijk".as_bytes()).unwrap(); + assert_eq!(s.deref(), "abcdefghijk"); + + assert_eq!( + TinyStr16::from_bytes(&[0, 159, 146, 150]), + Err(Error::NonAscii) + ); + assert_eq!(TinyStr16::from_bytes(&[]), Err(Error::InvalidSize)); + assert_eq!(TinyStr16::from_bytes(&[0]), Err(Error::InvalidNull)); +} + +#[test] +fn tiny16_size() { + assert_eq!("".parse::<TinyStr16>(), Err(Error::InvalidSize)); + assert!("1".parse::<TinyStr16>().is_ok()); + assert!("12".parse::<TinyStr16>().is_ok()); + assert!("123".parse::<TinyStr16>().is_ok()); + assert!("1234".parse::<TinyStr16>().is_ok()); + assert!("12345".parse::<TinyStr16>().is_ok()); + assert!("123456".parse::<TinyStr16>().is_ok()); + assert!("1234567".parse::<TinyStr16>().is_ok()); + assert!("12345678".parse::<TinyStr16>().is_ok()); + assert!("123456781".parse::<TinyStr16>().is_ok()); + assert!("1234567812".parse::<TinyStr16>().is_ok()); + assert!("12345678123".parse::<TinyStr16>().is_ok()); + assert!("123456781234".parse::<TinyStr16>().is_ok()); + assert!("1234567812345".parse::<TinyStr16>().is_ok()); + assert!("12345678123456".parse::<TinyStr16>().is_ok()); + assert!("123456781234567".parse::<TinyStr16>().is_ok()); + assert!("1234567812345678".parse::<TinyStr16>().is_ok()); + assert_eq!( + "12345678123456789".parse::<TinyStr16>(), + Err(Error::InvalidSize) + ); +} + +#[test] +fn tiny16_null() { + assert_eq!("a\u{0}b".parse::<TinyStr16>(), Err(Error::InvalidNull)); +} + +#[test] +fn tiny16_new_unchecked() { + let reference: TinyStr16 = "WindowsCE/ME/NT".parse().unwrap(); + let uval: u128 = reference.into(); + let s = unsafe { TinyStr16::new_unchecked(uval) }; + assert_eq!(s, reference); + assert_eq!(s, "WindowsCE/ME/NT"); +} + +#[test] +fn tiny16_nonascii() { + assert_eq!("\u{4000}".parse::<TinyStr16>(), Err(Error::NonAscii)); +} + +#[test] +fn tiny16_alpha() { + let s: TinyStr16 = "@abcdefgTUVWXYZ[".parse().unwrap(); + assert!(!s.is_ascii_alphabetic()); + assert!(!s.is_ascii_alphanumeric()); + assert_eq!(s.to_ascii_uppercase().as_str(), "@ABCDEFGTUVWXYZ["); + assert_eq!(s.to_ascii_lowercase().as_str(), "@abcdefgtuvwxyz["); + + assert!("abcdefgTUVWXYZ" + .parse::<TinyStr16>() + .unwrap() + .is_ascii_alphabetic()); + assert!("abcdefgTUVWXYZ" + .parse::<TinyStr16>() + .unwrap() + .is_ascii_alphanumeric()); + assert!(!"abcdefg0123456" + .parse::<TinyStr16>() + .unwrap() + .is_ascii_alphabetic()); + assert!("abcdefgTUVWXYZ" + .parse::<TinyStr16>() + .unwrap() + .is_ascii_alphanumeric()); +} + +#[test] +fn tiny16_numeric() { + let s: TinyStr16 = "@abcdefgTUVWXYZ[".parse().unwrap(); + assert!(!s.is_ascii_numeric()); + + assert!("0123456789" + .parse::<TinyStr16>() + .unwrap() + .is_ascii_numeric()); +} + +#[test] +fn tiny16_titlecase() { + assert_eq!( + "abcdabcdabcdabcd" + .parse::<TinyStr16>() + .unwrap() + .to_ascii_titlecase() + .as_str(), + "Abcdabcdabcdabcd" + ); + assert_eq!( + "ABCDABCDABCDABCD" + .parse::<TinyStr16>() + .unwrap() + .to_ascii_titlecase() + .as_str(), + "Abcdabcdabcdabcd" + ); + assert_eq!( + "aBCDaBCDaBCDaBCD" + .parse::<TinyStr16>() + .unwrap() + .to_ascii_titlecase() + .as_str(), + "Abcdabcdabcdabcd" + ); + assert_eq!( + "A123a123A123a123" + .parse::<TinyStr16>() + .unwrap() + .to_ascii_titlecase() + .as_str(), + "A123a123a123a123" + ); + assert_eq!( + "123a123A123a123A" + .parse::<TinyStr16>() + .unwrap() + .to_ascii_titlecase() + .as_str(), + "123a123a123a123a" + ); +} + +#[test] +fn tiny16_ord() { + let mut v: Vec<TinyStr16> = vec!["nedis_xxxx".parse().unwrap(), "macos_xxxx".parse().unwrap()]; + v.sort(); + + assert_eq!(v.get(0).unwrap().as_str(), "macos_xxxx"); + assert_eq!(v.get(1).unwrap().as_str(), "nedis_xxxx"); +} + +#[test] +fn tiny16_eq() { + let s1: TinyStr16 = "windows98SE".parse().unwrap(); + let s2: TinyStr16 = "mac".parse().unwrap(); + let s3: TinyStr16 = "windows98SE".parse().unwrap(); + + assert_eq!(s1, s3); + assert_ne!(s1, s2); +} + +#[test] +fn tiny16_display() { + let s: TinyStr16 = "abcdefghijkl".parse().unwrap(); + let mut result = String::new(); + write!(result, "{}", s).unwrap(); + assert_eq!(result, "abcdefghijkl"); + assert_eq!(format!("{}", s), "abcdefghijkl"); +} + +#[test] +fn tiny16_debug() { + let s: TinyStr16 = "abcdefghijkl".parse().unwrap(); + assert_eq!(format!("{:#?}", s), "\"abcdefghijkl\""); +} + +#[cfg(any(feature = "std", feature = "alloc"))] +#[test] +fn tinyauto_basic() { + let s1: TinyStrAuto = "abc".parse().unwrap(); + assert_eq!(s1, "abc"); + + let s2: TinyStrAuto = "veryveryveryveryverylong".parse().unwrap(); + assert_eq!(s2, "veryveryveryveryverylong"); +} + +#[cfg(any(feature = "std", feature = "alloc"))] +#[test] +fn tinyauto_nonascii() { + assert_eq!("\u{4000}".parse::<TinyStrAuto>(), Err(Error::NonAscii)); + assert_eq!( + "veryveryveryveryverylong\u{4000}".parse::<TinyStrAuto>(), + Err(Error::NonAscii) + ); +} + +#[cfg(feature = "macros")] +const TS: TinyStr8 = tinystr::macros::tinystr8!("test"); + +#[cfg(feature = "macros")] +#[test] +fn tinystr_macros() { + use tinystr::macros::*; + + let x: TinyStr8 = "test".parse().unwrap(); + assert_eq!(TS, x); + + let x: TinyStr4 = "foo".parse().unwrap(); + assert_eq!(tinystr4!("foo"), x); + + let x: TinyStr8 = "barbaz".parse().unwrap(); + assert_eq!(tinystr8!("barbaz"), x); + + let x: TinyStr16 = "metamorphosis".parse().unwrap(); + assert_eq!(tinystr16!("metamorphosis"), x); +} |