diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/tinystr | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/tinystr')
-rw-r--r-- | third_party/rust/tinystr/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | third_party/rust/tinystr/CHANGELOG.md | 26 | ||||
-rw-r--r-- | third_party/rust/tinystr/Cargo.lock | 510 | ||||
-rw-r--r-- | third_party/rust/tinystr/Cargo.toml | 33 | ||||
-rw-r--r-- | third_party/rust/tinystr/LICENSE-APACHE | 201 | ||||
-rw-r--r-- | third_party/rust/tinystr/LICENSE-MIT | 23 | ||||
-rw-r--r-- | third_party/rust/tinystr/README.md | 84 | ||||
-rw-r--r-- | third_party/rust/tinystr/benches/construct.rs | 151 | ||||
-rw-r--r-- | third_party/rust/tinystr/benches/tinystr.rs | 176 | ||||
-rw-r--r-- | third_party/rust/tinystr/examples/main.rs | 18 | ||||
-rw-r--r-- | third_party/rust/tinystr/src/helpers.rs | 23 | ||||
-rw-r--r-- | third_party/rust/tinystr/src/lib.rs | 51 | ||||
-rw-r--r-- | third_party/rust/tinystr/src/tinystr16.rs | 321 | ||||
-rw-r--r-- | third_party/rust/tinystr/src/tinystr4.rs | 293 | ||||
-rw-r--r-- | third_party/rust/tinystr/src/tinystr8.rs | 313 | ||||
-rw-r--r-- | third_party/rust/tinystr/tests/main.rs | 482 |
16 files changed, 2706 insertions, 0 deletions
diff --git a/third_party/rust/tinystr/.cargo-checksum.json b/third_party/rust/tinystr/.cargo-checksum.json new file mode 100644 index 0000000000..98a565e36e --- /dev/null +++ b/third_party/rust/tinystr/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"4d414871b3c78ec81a01ba8e024c6ea027b9353d90141bb85f9361143545923a","Cargo.lock":"f9b2a374e4fd6acd0dea78a9c10c0821de05b38fe1bf9c6584734726e1203b5f","Cargo.toml":"1fe812d83bb4dd41560f37b7af3a03fbbaef19ad0b1497bb6d10d243f08fbe86","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"470012da39c075b9da664e74b4be4fb42aa44b9c592129596f58f071f64437d5","benches/construct.rs":"8ca1d6cef3b6adeee8d947cf06b59c4942a93dbd9c710fe4fa2b15fb275383ef","benches/tinystr.rs":"dc61b52ca7be3312a8c504786ad60e5e2c4c729e111c2033716c9996c5e87bc8","examples/main.rs":"463f7c0db47a3843097b012315fc8b0d68baa4afca0a0fe06210ed3c8c471453","src/helpers.rs":"ce56640fad9ce97c425ae931e77e003bbe06365cd2ba28356793ac975ee2ad09","src/lib.rs":"0d869f50cc6e34c919af53b71a50094dbf9ab80e35d41a093f3bf00cedc138e7","src/tinystr16.rs":"4f5b8f84e81cd8be101a1f66115f085aa80c99dab52cadb32d2b93c69aa32876","src/tinystr4.rs":"5635662508f6f9579f7602e18f184f6bdee51dc21d6a80fdaed5e7587b123aaf","src/tinystr8.rs":"2a3b5f685bb60e6aa99e525fc7a0fbc943ef015bb1903beaeefa894a0cf2c2c6","tests/main.rs":"e356b94be237b604a9a31ef8f82c933d3ac3dd62bdd23589115149cdabe1cc75"},"package":"4bac79c4b51eda1b090b1edebfb667821bbb51f713855164dc7cec2cb8ac2ba3"}
\ No newline at end of file diff --git a/third_party/rust/tinystr/CHANGELOG.md b/third_party/rust/tinystr/CHANGELOG.md new file mode 100644 index 0000000000..53a7bc64b5 --- /dev/null +++ b/third_party/rust/tinystr/CHANGELOG.md @@ -0,0 +1,26 @@ +# Changelog + +## Unreleased + + - … + +## 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/third_party/rust/tinystr/Cargo.lock b/third_party/rust/tinystr/Cargo.lock new file mode 100644 index 0000000000..7d30422b76 --- /dev/null +++ b/third_party/rust/tinystr/Cargo.lock @@ -0,0 +1,510 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "arrayvec" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "atty" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "autocfg" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bstr" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "byteorder" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cast" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "clap" +version = "2.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "criterion" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "criterion-plot" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-deque" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-queue" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-utils" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "csv" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bstr 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "csv-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "either" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "getrandom" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itertools" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itoa" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazy_static" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.62" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "memchr" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "memoffset" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "nodrop" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "num-traits" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num_cpus" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_os" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_xoshiro" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rayon" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rayon-core" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-automata" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ryu" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "same-file" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "scopeguard" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde_derive" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.43 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_json" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "0.15.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tinystr" +version = "0.3.2" +dependencies = [ + "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tinytemplate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-width" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "walkdir" +version = "2.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasi" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" +"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" +"checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b" +"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" +"checksum bstr 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e0a692f1c740e7e821ca71a22cf99b9b2322dfa94d10f71443befb1797b3946a" +"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" +"checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" +"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" +"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" +"checksum criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "938703e165481c8d612ea3479ac8342e5615185db37765162e762ec3523e2fc6" +"checksum criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eccdc6ce8bbe352ca89025bee672aa6d24f4eb8c53e3a8b5d1bc58011da072a2" +"checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" +"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" +"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" +"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" +"checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d" +"checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" +"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" +"checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" +"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" +"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" +"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" +"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" +"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" +"checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" +"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" +"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" +"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" +"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +"checksum rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a788ae3edb696cfcba1c19bfd388cc4b8c21f8a408432b199c072825084da58a" +"checksum rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e18c91676f670f6f0312764c759405f13afb98d5d73819840cf72a518487bff" +"checksum rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4b0186e22767d5b9738a05eab7c6ac90b15db17e5b5f9bd87976dd7d89a10a4" +"checksum rayon-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe0df8435ac0c397d467b6cad6d25543d06e8a019ef3f6af3c384597515bd2" +"checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" +"checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421" +"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5626ac617da2f2d9c48af5515a21d5a480dbd151e01bb1c355e26a3e68113" +"checksum serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "01e69e1b8a631f245467ee275b8c757b818653c6d704cdbcaeb56b56767b529c" +"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" +"checksum syn 0.15.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ee06ea4b620ab59a2267c6b48be16244a3389f8bfa0986bdd15c35b890b00af3" +"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +"checksum tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4574b75faccaacddb9b284faecdf0b544b80b6b294f3d062d325c5726a209c20" +"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" +"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" +"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/third_party/rust/tinystr/Cargo.toml b/third_party/rust/tinystr/Cargo.toml new file mode 100644 index 0000000000..ea491ae7d2 --- /dev/null +++ b/third_party/rust/tinystr/Cargo.toml @@ -0,0 +1,33 @@ +# 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.2" +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"] +categories = ["data-structures"] +license = "Apache-2.0/MIT" +repository = "https://github.com/zbraniecki/tinystr" + +[[bench]] +name = "construct" +harness = false + +[[bench]] +name = "tinystr" +harness = false +[dev-dependencies.criterion] +version = "0.3" diff --git a/third_party/rust/tinystr/LICENSE-APACHE b/third_party/rust/tinystr/LICENSE-APACHE new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/third_party/rust/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/third_party/rust/tinystr/LICENSE-MIT b/third_party/rust/tinystr/LICENSE-MIT new file mode 100644 index 0000000000..31aa79387f --- /dev/null +++ b/third_party/rust/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/third_party/rust/tinystr/README.md b/third_party/rust/tinystr/README.md new file mode 100644 index 0000000000..fb26c8307d --- /dev/null +++ b/third_party/rust/tinystr/README.md @@ -0,0 +1,84 @@ +# 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}; + +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); +} +``` + +Details +------- + +The crateh provides three structs: + * `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. + +It stores them 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 + +This set is sufficient for certain classes of uses such as `unic-langid` libraries. + +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> + +<br> + +<sub> +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. +</sub> diff --git a/third_party/rust/tinystr/benches/construct.rs b/third_party/rust/tinystr/benches/construct.rs new file mode 100644 index 0000000000..854a1b0653 --- /dev/null +++ b/third_party/rust/tinystr/benches/construct.rs @@ -0,0 +1,151 @@ +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); + }; +} + +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/third_party/rust/tinystr/benches/tinystr.rs b/third_party/rust/tinystr/benches/tinystr.rs new file mode 100644 index 0000000000..83b26a30a2 --- /dev/null +++ b/third_party/rust/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/third_party/rust/tinystr/examples/main.rs b/third_party/rust/tinystr/examples/main.rs new file mode 100644 index 0000000000..2e0d2a10bc --- /dev/null +++ b/third_party/rust/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/third_party/rust/tinystr/src/helpers.rs b/third_party/rust/tinystr/src/helpers.rs new file mode 100644 index 0000000000..9b5be84152 --- /dev/null +++ b/third_party/rust/tinystr/src/helpers.rs @@ -0,0 +1,23 @@ +use std::num::NonZeroU32; +use std::ptr::copy_nonoverlapping; + +use super::Error; + +#[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/third_party/rust/tinystr/src/lib.rs b/third_party/rust/tinystr/src/lib.rs new file mode 100644 index 0000000000..ba317ac8f6 --- /dev/null +++ b/third_party/rust/tinystr/src/lib.rs @@ -0,0 +1,51 @@ +//! `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. +//! +//! # Example +//! +//! ``` +//! 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); +//! } +//! ``` +mod helpers; +mod tinystr16; +mod tinystr4; +mod tinystr8; + +pub use tinystr16::TinyStr16; +pub use tinystr4::TinyStr4; +pub use tinystr8::TinyStr8; + +/// 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/third_party/rust/tinystr/src/tinystr16.rs b/third_party/rust/tinystr/src/tinystr16.rs new file mode 100644 index 0000000000..c089516419 --- /dev/null +++ b/third_party/rust/tinystr/src/tinystr16.rs @@ -0,0 +1,321 @@ +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"); + /// ``` + #[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/third_party/rust/tinystr/src/tinystr4.rs b/third_party/rust/tinystr/src/tinystr4.rs new file mode 100644 index 0000000000..b454f3f89e --- /dev/null +++ b/third_party/rust/tinystr/src/tinystr4.rs @@ -0,0 +1,293 @@ +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"); + /// ``` + #[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/third_party/rust/tinystr/src/tinystr8.rs b/third_party/rust/tinystr/src/tinystr8.rs new file mode 100644 index 0000000000..450765b1aa --- /dev/null +++ b/third_party/rust/tinystr/src/tinystr8.rs @@ -0,0 +1,313 @@ +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"); + /// ``` + #[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/third_party/rust/tinystr/tests/main.rs b/third_party/rust/tinystr/tests/main.rs new file mode 100644 index 0000000000..a3fb78be65 --- /dev/null +++ b/third_party/rust/tinystr/tests/main.rs @@ -0,0 +1,482 @@ +use std::fmt::Write; +use std::ops::Deref; +use tinystr::{Error, TinyStr16, TinyStr4, TinyStr8}; + +#[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\""); +} |