summaryrefslogtreecommitdiffstats
path: root/third_party/rust/tinystr
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/tinystr
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.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.json1
-rw-r--r--third_party/rust/tinystr/CHANGELOG.md26
-rw-r--r--third_party/rust/tinystr/Cargo.lock510
-rw-r--r--third_party/rust/tinystr/Cargo.toml33
-rw-r--r--third_party/rust/tinystr/LICENSE-APACHE201
-rw-r--r--third_party/rust/tinystr/LICENSE-MIT23
-rw-r--r--third_party/rust/tinystr/README.md84
-rw-r--r--third_party/rust/tinystr/benches/construct.rs151
-rw-r--r--third_party/rust/tinystr/benches/tinystr.rs176
-rw-r--r--third_party/rust/tinystr/examples/main.rs18
-rw-r--r--third_party/rust/tinystr/src/helpers.rs23
-rw-r--r--third_party/rust/tinystr/src/lib.rs51
-rw-r--r--third_party/rust/tinystr/src/tinystr16.rs321
-rw-r--r--third_party/rust/tinystr/src/tinystr4.rs293
-rw-r--r--third_party/rust/tinystr/src/tinystr8.rs313
-rw-r--r--third_party/rust/tinystr/tests/main.rs482
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\"");
+}