diff options
Diffstat (limited to 'vendor/kstring')
-rw-r--r-- | vendor/kstring/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | vendor/kstring/Cargo.lock | 814 | ||||
-rw-r--r-- | vendor/kstring/Cargo.toml | 88 | ||||
-rw-r--r-- | vendor/kstring/LICENSE-APACHE | 201 | ||||
-rw-r--r-- | vendor/kstring/LICENSE-MIT | 21 | ||||
-rw-r--r-- | vendor/kstring/README.md | 58 | ||||
-rw-r--r-- | vendor/kstring/benches/access.rs | 134 | ||||
-rw-r--r-- | vendor/kstring/benches/clone.rs | 139 | ||||
-rw-r--r-- | vendor/kstring/examples/bench.rs | 18 | ||||
-rw-r--r-- | vendor/kstring/src/backend.rs | 97 | ||||
-rw-r--r-- | vendor/kstring/src/lib.rs | 78 | ||||
-rw-r--r-- | vendor/kstring/src/stack.rs | 457 | ||||
-rw-r--r-- | vendor/kstring/src/string.rs | 865 | ||||
-rw-r--r-- | vendor/kstring/src/string_cow.rs | 383 | ||||
-rw-r--r-- | vendor/kstring/src/string_ref.rs | 277 |
15 files changed, 3631 insertions, 0 deletions
diff --git a/vendor/kstring/.cargo-checksum.json b/vendor/kstring/.cargo-checksum.json new file mode 100644 index 000000000..322069c76 --- /dev/null +++ b/vendor/kstring/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.lock":"bb3f1dfc847c9f47c89a5c465a9e91ed68c42695bf80ae147c6c1ea4d3de9928","Cargo.toml":"d6aa48214500ad0cf5de9c904609af1dd6ea2fe2068b405237f9f2576df3c600","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6a5dfb0adf37850239f4b2388a79355c77b625d6c5542dea7743ac5033efaba2","README.md":"dcf7c8593f78a8e5d6cdb520c4c4499b229bdfc93bedcdfb22434b0e0b311d4a","benches/access.rs":"356362c7d1d6517e2e495be2c9edee5130db5aa8dee02dfab053b1374e91326a","benches/clone.rs":"ce6430a1da50da96d7f94b7d9912cf28f28ba4a1baa976f62d6b211c5729184e","examples/bench.rs":"01056ee7b3bca2f9525636080ccdc5d8b513934e5c001eb0b8beb6214c2bac88","src/backend.rs":"6f3ec727cae210c04c720b1ed77de3d4b21713a920aa3ee620861eeadd91ae31","src/lib.rs":"9932b5d3ed4440e2d167b1fff1f835ef0eb51ad0a47a64bde38c0bf5aee60c6d","src/stack.rs":"029dce8e4385f91b2e375cd50a81812b44a93db656890cfe30b81f59ff9af425","src/string.rs":"bca947a52972f59ec7211d9a573110a8b24942c6c1144ea4abd6d272bc07adf0","src/string_cow.rs":"80db9235eee78bc81ee50df1f1fed1863791cb41aa0bae00af3a36b586f5513a","src/string_ref.rs":"79d050ce3bc7145b40aa3f555ea89a830cd84f3ef002a3081f874d5425430937"},"package":"ec3066350882a1cd6d950d055997f379ac37fd39f81cd4d8ed186032eb3c5747"}
\ No newline at end of file diff --git a/vendor/kstring/Cargo.lock b/vendor/kstring/Cargo.lock new file mode 100644 index 000000000..206479e6d --- /dev/null +++ b/vendor/kstring/Cargo.lock @@ -0,0 +1,814 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bit-set" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bstr" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +dependencies = [ + "lazy_static", + "memchr", + "regex-automata", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cast" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "bitflags", + "textwrap", + "unicode-width", +] + +[[package]] +name = "criterion" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10" +dependencies = [ + "atty", + "cast", + "clap", + "criterion-plot", + "csv", + "itertools", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_cbor", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "csv" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" +dependencies = [ + "bstr", + "csv-core", + "itoa 0.4.8", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", +] + +[[package]] +name = "document-features" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b01c09fd63b5136fba41aa625c7b3254f0aa0a435ff6ec4b2c9a28d496c83c88" + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "getrandom" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itertools" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + +[[package]] +name = "js-sys" +version = "0.3.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "kstring" +version = "2.0.0" +dependencies = [ + "criterion", + "document-features", + "proptest", + "serde", + "static_assertions", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" + +[[package]] +name = "log" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "plotters" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d88417318da0eaf0fdcdb51a0ee6c3bed624333bff8f946733049380be67ac1c" + +[[package]] +name = "plotters-svg" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521fa9638fa597e1dc53e9412a4f9cefb01187ee1f7413076f9e6749e2885ba9" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro2" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "proptest" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0d9cc07f18492d879586c92b485def06bc850da3118075cd45d50e9c95b0e5" +dependencies = [ + "bit-set", + "bitflags", + "byteorder", + "lazy_static", + "num-traits", + "quick-error 2.0.1", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quote" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rayon" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae183fc1b06c149f0c1793e1eb447c8b04bfe46d48e9e48bfb8d2d7ed64ecf0" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error 1.2.3", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "ryu" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4" + +[[package]] +name = "serde" +version = "1.0.136" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" + +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.136" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +dependencies = [ + "itoa 1.0.1", + "ryu", + "serde", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "syn" +version = "1.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704df27628939572cd88d33f171cd6f896f4eaca85252c6e0a72d8d8287ee86f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "wasm-bindgen" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" + +[[package]] +name = "web-sys" +version = "0.3.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/vendor/kstring/Cargo.toml b/vendor/kstring/Cargo.toml new file mode 100644 index 000000000..87e11ed79 --- /dev/null +++ b/vendor/kstring/Cargo.toml @@ -0,0 +1,88 @@ +# 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 are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "kstring" +version = "2.0.0" +authors = ["Ed Page <eopage@gmail.com>"] +include = ["build.rs", "src/**/*", "Cargo.toml", "LICENSE*", "README.md", "benches/**/*", "examples/**/*"] +description = "Key String: optimized for map keys" +documentation = "https://docs.rs/kstring" +readme = "README.md" +keywords = ["serde", "serialization", "string"] +categories = ["data-structures", "text-processing"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/cobalt-org/kstring" +[package.metadata.docs.rs] +all-features = true +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +min = 1 +replace = "{{version}}" +search = "Unreleased" + +[[package.metadata.release.pre-release-replacements]] +exactly = 1 +file = "CHANGELOG.md" +replace = "...{{tag_name}}" +search = "\\.\\.\\.HEAD" + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +min = 1 +replace = "{{date}}" +search = "ReleaseDate" + +[[package.metadata.release.pre-release-replacements]] +exactly = 1 +file = "CHANGELOG.md" +replace = "<!-- next-header -->\n## [Unreleased] - ReleaseDate\n" +search = "<!-- next-header -->" + +[[package.metadata.release.pre-release-replacements]] +exactly = 1 +file = "CHANGELOG.md" +replace = "<!-- next-url -->\n[Unreleased]: https://github.com/cobalt-org/kstring/compare/{{tag_name}}...HEAD" +search = "<!-- next-url -->" +[profile.release] +debug = 1 + +[[bench]] +name = "clone" +harness = false + +[[bench]] +name = "access" +harness = false +[dependencies.document-features] +version = "0.2" +optional = true + +[dependencies.serde] +version = "1.0" +optional = true + +[dependencies.static_assertions] +version = "1.1.0" +[dev-dependencies.criterion] +version = "0.3" + +[dev-dependencies.proptest] +version = "1.0.0" + +[features] +arc = [] +default = ["std", "unsafe"] +max_inline = [] +std = [] +unsafe = [] +unstable_bench_subset = [] diff --git a/vendor/kstring/LICENSE-APACHE b/vendor/kstring/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/vendor/kstring/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/kstring/LICENSE-MIT b/vendor/kstring/LICENSE-MIT new file mode 100644 index 000000000..f1be6b7af --- /dev/null +++ b/vendor/kstring/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014-2016 Ning Sun and tojson_macros contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/kstring/README.md b/vendor/kstring/README.md new file mode 100644 index 000000000..91828d01d --- /dev/null +++ b/vendor/kstring/README.md @@ -0,0 +1,58 @@ +KString +=========== + +> Key String: Optimized for map keys. + +[![Crates Status](https://img.shields.io/crates/v/kstring.svg)](https://crates.io/crates/kstring) + +## Background + +Considerations: +- Large maps +- Most keys live and drop without being used in any other way +- Most keys are relatively small (single to double digit bytes) +- Keys are immutable +- Allow zero-cost abstractions between structs and maps (e.g. no allocating + when dealing with struct field names) + +Ramifications: +- Inline small strings rather than going to the heap. +- Preserve `&'static str` across strings (`KString`), + references (`KStringRef`), and lifetime abstractions (`KStringCow`) to avoid + allocating for struct field names. +- Use `Box<str>` rather than `String` to use less memory. + +Features +- `max_inline`: Instead of aligning the inline-string for performance (15 bytes + length on 64-bit), use the full width (22 bytes on 64-bit) +- `arc`: Instead of using `Box<str>`, use `Arc<str>`. Note: allocations are fast enough that this can actually slow things down for small enough strings. + +Alternatives +- [`smol_str`](https://crates.io/crates/smol_str) + - Size of String + - Always uses `Arc` instead of `Box` + - Always inlines 22 bytes + - Whitespace-only optimizations +- [`smartstring`](https://crates.io/crates/smartstring) + - Size of String + - Allows mutability at the cost of relying on implementation details of `String` + - Always inlines 23 bytes +- [`compact_str`](https://crates.io/crates/compact_str) + - Size of String + - Always uses `Arc` instead of `Box` + - Inlines 22-23 bytes, depending on implementation + +## License + +Licensed under either of + + * Apache License, Version 2.0, (http://www.apache.org/licenses/LICENSE-2.0) + * MIT license (http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed as above, without any additional terms or +conditions. diff --git a/vendor/kstring/benches/access.rs b/vendor/kstring/benches/access.rs new file mode 100644 index 000000000..a9b92d3d6 --- /dev/null +++ b/vendor/kstring/benches/access.rs @@ -0,0 +1,134 @@ +#![allow( + clippy::clone_on_copy, + clippy::useless_conversion, + clippy::clone_double_ref +)] + +use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput}; + +type StringCow<'s> = std::borrow::Cow<'s, str>; + +#[cfg(not(feature = "unstable_bench_subset"))] +pub static FIXTURES: &[&str] = &[ + "", + "0", + "01", + "012", + "0123", + "01234", + "012345", + "0123456", + "01234567", + "012345678", + "0123456789", + "01234567890123456789", + "0123456789012345678901234567890123456789", + "01234567890123456789012345678901234567890123456789012345678901234567890123456789", +]; + +#[cfg(feature = "unstable_bench_subset")] +pub static FIXTURES: &[&str] = &[ + "0123456789", + "01234567890123456789012345678901234567890123456789012345678901234567890123456789", +]; + +// Note: this is meant to measure the overhead for accessing the underlying str. We shouldn't try +// to optimize *just* the case being measured here. +fn bench_access(c: &mut Criterion) { + let mut group = c.benchmark_group("access"); + for fixture in FIXTURES { + let len = fixture.len(); + group.throughput(Throughput::Bytes(len as u64)); + group.bench_with_input( + BenchmarkId::new("StringCow::Borrowed", len), + &len, + |b, _| { + let uut = StringCow::Borrowed(*fixture); + let uut = criterion::black_box(uut); + b.iter(|| uut.is_empty()) + }, + ); + group.bench_with_input(BenchmarkId::new("StringCow::Owned", len), &len, |b, _| { + let uut = StringCow::Owned(String::from(*fixture)); + let uut = criterion::black_box(uut); + b.iter(|| uut.is_empty()) + }); + group.bench_with_input( + BenchmarkId::new("KString::from_static", len), + &len, + |b, _| { + let uut = kstring::KString::from_static(*fixture); + let uut = criterion::black_box(uut); + b.iter(|| uut.is_empty()) + }, + ); + group.bench_with_input(BenchmarkId::new("KString::from_ref", len), &len, |b, _| { + let uut = kstring::KString::from_ref(*fixture); + let uut = criterion::black_box(uut); + b.iter(|| uut.is_empty()) + }); + group.bench_with_input( + BenchmarkId::new("KString::from_string", len), + &len, + |b, _| { + let uut = kstring::KString::from_string(String::from(*fixture)); + let uut = criterion::black_box(uut); + b.iter(|| uut.is_empty()) + }, + ); + #[cfg(not(feature = "unstable_bench_subset"))] + group.bench_with_input( + BenchmarkId::new("KStringCow::from_static", len), + &len, + |b, _| { + let uut = kstring::KStringCow::from_static(*fixture); + let uut = criterion::black_box(uut); + b.iter(|| uut.is_empty()) + }, + ); + #[cfg(not(feature = "unstable_bench_subset"))] + group.bench_with_input( + BenchmarkId::new("KStringCow::from_ref", len), + &len, + |b, _| { + let uut = kstring::KStringCow::from_ref(*fixture); + let uut = criterion::black_box(uut); + b.iter(|| uut.is_empty()) + }, + ); + #[cfg(not(feature = "unstable_bench_subset"))] + group.bench_with_input( + BenchmarkId::new("KStringCow::from_string", len), + &len, + |b, _| { + let uut = kstring::KStringCow::from_string(String::from(*fixture)); + let uut = criterion::black_box(uut); + b.iter(|| uut.is_empty()) + }, + ); + #[cfg(not(feature = "unstable_bench_subset"))] + group.bench_with_input( + BenchmarkId::new("KStringRef::from_static", len), + &len, + |b, _| { + let uut = kstring::KStringRef::from_static(*fixture); + let uut = criterion::black_box(uut); + b.iter(|| uut.is_empty()) + }, + ); + #[cfg(not(feature = "unstable_bench_subset"))] + group.bench_with_input( + BenchmarkId::new("KStringRef::from_ref", len), + &len, + |b, _| { + let uut = kstring::KStringRef::from_ref(*fixture); + let uut = criterion::black_box(uut); + b.iter(|| uut.is_empty()) + }, + ); + } + group.finish(); +} + +criterion_group!(benches, bench_access); +criterion_main!(benches); diff --git a/vendor/kstring/benches/clone.rs b/vendor/kstring/benches/clone.rs new file mode 100644 index 000000000..b0740bad9 --- /dev/null +++ b/vendor/kstring/benches/clone.rs @@ -0,0 +1,139 @@ +#![allow( + clippy::clone_on_copy, + clippy::useless_conversion, + clippy::clone_double_ref +)] + +use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput}; + +type StringCow<'s> = std::borrow::Cow<'s, str>; + +#[cfg(not(feature = "unstable_bench_subset"))] +pub static FIXTURES: &[&str] = &[ + // Empty handling + "", + // Barely used + "1", + // kstring's max small-string size + "123456789012345", + // Boundary conditions for most small-string optimizations + "1234567890123456789012", + "12345678901234567890123", + "123456789012345678901234", + "1234567890123456789012345", + // Small heap + "1234567890123456789012345678901234567890123456789012345678901234", + // Large heap + "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", +]; + +#[cfg(feature = "unstable_bench_subset")] +pub static FIXTURES: &[&str] = &[ + "0123456789", + "01234567890123456789012345678901234567890123456789012345678901234567890123456789", +]; + +fn bench_clone(c: &mut Criterion) { + let mut group = c.benchmark_group("clone"); + for fixture in FIXTURES { + let len = fixture.len(); + group.throughput(Throughput::Bytes(len as u64)); + group.bench_with_input( + BenchmarkId::new("StringCow::Borrowed", len), + &len, + |b, _| { + let uut = StringCow::Borrowed(*fixture); + let uut = criterion::black_box(uut); + b.iter(|| uut.clone()) + }, + ); + group.bench_with_input(BenchmarkId::new("StringCow::Owned", len), &len, |b, _| { + let fixture = String::from(*fixture); + let uut = StringCow::Owned(fixture); + let uut = criterion::black_box(uut); + b.iter(|| uut.clone()) + }); + group.bench_with_input( + BenchmarkId::new("KString::from_static", len), + &len, + |b, _| { + let uut = kstring::KString::from_static(*fixture); + let uut = criterion::black_box(uut); + b.iter(|| uut.clone()) + }, + ); + group.bench_with_input(BenchmarkId::new("KString::from_ref", len), &len, |b, _| { + let fixture = String::from(*fixture); + let uut = kstring::KString::from_ref(&fixture); + let uut = criterion::black_box(uut); + b.iter(|| uut.clone()) + }); + group.bench_with_input( + BenchmarkId::new("KString::from_string", len), + &len, + |b, _| { + let fixture = String::from(*fixture); + let uut = kstring::KString::from_string(fixture); + let uut = criterion::black_box(uut); + b.iter(|| uut.clone()) + }, + ); + #[cfg(not(feature = "unstable_bench_subset"))] + group.bench_with_input( + BenchmarkId::new("KStringCow::from_static", len), + &len, + |b, _| { + let uut = kstring::KStringCow::from_static(*fixture); + let uut = criterion::black_box(uut); + b.iter(|| uut.clone()) + }, + ); + #[cfg(not(feature = "unstable_bench_subset"))] + group.bench_with_input( + BenchmarkId::new("KStringCow::from_ref", len), + &len, + |b, _| { + let fixture = String::from(*fixture); + let uut = kstring::KStringCow::from_ref(&fixture); + let uut = criterion::black_box(uut); + b.iter(|| uut.clone()) + }, + ); + #[cfg(not(feature = "unstable_bench_subset"))] + group.bench_with_input( + BenchmarkId::new("KStringCow::from_string", len), + &len, + |b, _| { + let fixture = String::from(*fixture); + let uut = kstring::KStringCow::from_string(fixture); + let uut = criterion::black_box(uut); + b.iter(|| uut.clone()) + }, + ); + #[cfg(not(feature = "unstable_bench_subset"))] + group.bench_with_input( + BenchmarkId::new("KStringRef::from_static", len), + &len, + |b, _| { + let uut = kstring::KStringRef::from_static(*fixture); + let uut = criterion::black_box(uut); + b.iter(|| uut.clone()) + }, + ); + #[cfg(not(feature = "unstable_bench_subset"))] + group.bench_with_input( + BenchmarkId::new("KStringRef::from_ref", len), + &len, + |b, _| { + let fixture = String::from(*fixture); + let uut = kstring::KStringRef::from_ref(&fixture); + let uut = criterion::black_box(uut); + b.iter(|| uut.clone()) + }, + ); + } + group.finish(); +} + +criterion_group!(benches, bench_clone); +criterion_main!(benches); diff --git a/vendor/kstring/examples/bench.rs b/vendor/kstring/examples/bench.rs new file mode 100644 index 000000000..8d467da52 --- /dev/null +++ b/vendor/kstring/examples/bench.rs @@ -0,0 +1,18 @@ +fn main() { + let mut args = std::env::args(); + let _ = args.next(); + let method = args.next().unwrap_or_else(|| String::from("from_ref")); + let sample = args.next().unwrap_or_else(|| String::from("0123456789")); + let count = args + .next() + .unwrap_or_else(|| String::from("10000000")) + .parse::<usize>() + .unwrap(); + #[allow(clippy::redundant_closure)] // Needed for consistent type + let method = match method.as_str() { + "from_ref" => |s| kstring::KString::from_ref(s), + "from_string" => |s| kstring::KString::from_string(String::from(s)), + _ => panic!("{:?} unsupported, try `from_ref`, `from_string`", method), + }; + (0..count).map(|_| method(&sample)).last(); +} diff --git a/vendor/kstring/src/backend.rs b/vendor/kstring/src/backend.rs new file mode 100644 index 000000000..3827082f1 --- /dev/null +++ b/vendor/kstring/src/backend.rs @@ -0,0 +1,97 @@ +#[cfg(feature = "arc")] +pub(crate) type DefaultStr = crate::backend::ArcStr; +#[cfg(not(feature = "arc"))] +pub(crate) type DefaultStr = crate::backend::BoxedStr; + +/// Fast allocations, O(n) clones +pub type BoxedStr = Box<str>; +static_assertions::assert_eq_size!(DefaultStr, BoxedStr); + +/// Cross-thread, O(1) clones +pub type ArcStr = std::sync::Arc<str>; +static_assertions::assert_eq_size!(DefaultStr, ArcStr); + +/// O(1) clones +pub type RcStr = std::rc::Rc<str>; +static_assertions::assert_eq_size!(DefaultStr, RcStr); + +/// Abstract over different type of heap-allocated strings +pub trait HeapStr: std::fmt::Debug + Clone + private::Sealed { + fn from_str(other: &str) -> Self; + fn from_string(other: String) -> Self; + fn from_boxed_str(other: BoxedStr) -> Self; + fn as_str(&self) -> &str; +} + +impl HeapStr for BoxedStr { + #[inline] + fn from_str(other: &str) -> Self { + other.into() + } + + #[inline] + fn from_string(other: String) -> Self { + other.into_boxed_str() + } + + #[inline] + fn from_boxed_str(other: BoxedStr) -> Self { + other + } + + #[inline] + fn as_str(&self) -> &str { + self + } +} + +impl HeapStr for ArcStr { + #[inline] + fn from_str(other: &str) -> Self { + other.into() + } + + #[inline] + fn from_string(other: String) -> Self { + other.into_boxed_str().into() + } + + #[inline] + fn from_boxed_str(other: BoxedStr) -> Self { + other.into() + } + + #[inline] + fn as_str(&self) -> &str { + self + } +} + +impl HeapStr for RcStr { + #[inline] + fn from_str(other: &str) -> Self { + other.into() + } + + #[inline] + fn from_string(other: String) -> Self { + other.into_boxed_str().into() + } + + #[inline] + fn from_boxed_str(other: BoxedStr) -> Self { + other.into() + } + + #[inline] + fn as_str(&self) -> &str { + self + } +} + +pub(crate) mod private { + pub trait Sealed {} + impl Sealed for super::BoxedStr {} + impl Sealed for super::ArcStr {} + impl Sealed for super::RcStr {} +} diff --git a/vendor/kstring/src/lib.rs b/vendor/kstring/src/lib.rs new file mode 100644 index 000000000..dc1ffd608 --- /dev/null +++ b/vendor/kstring/src/lib.rs @@ -0,0 +1,78 @@ +//! Key String: Optimized for map keys. +//! +//! # Examples +//! +//! String creation +//! ```rust +//! // Explicit +//! let literal = kstring::KString::from_static("literal"); +//! // Implicit +//! let literal = kstring::KString::from("literal"); +//! +//! // Explicit +//! let inline = kstring::KString::try_inline("stack").unwrap(); +//! let inline = kstring::KString::from_ref("stack"); +//! +//! let formatted: kstring::KStringCow = format!("Hello {} and {}", literal, inline).into(); +//! ``` +//! +//! # Background +//! +//! Considerations: +//! - Large maps +//! - Most keys live and drop without being used in any other way +//! - Most keys are relatively small (single to double digit bytes) +//! - Keys are immutable +//! - Allow zero-cost abstractions between structs and maps (e.g. no allocating +//! when dealing with struct field names) +//! +//! Ramifications: +//! - Inline small strings rather than going to the heap. +//! - Preserve `&'static str` across strings ([`KString`]), +//! references ([`KStringRef`]), and lifetime abstractions ([`KStringCow`]) to avoid +//! allocating for struct field names. +//! - Use `Box<str>` rather than `String` to use less memory. +//! +//! # Feature Flags +//! +#![cfg_attr(feature = "document-features", doc = document_features::document_features!())] +#![cfg_attr(feature = "safe", forbid(unsafe_code))] + +#[cfg(not(feature = "std"))] +compile_error!("`std` feature is required; reserved for future `no_std` support"); + +mod stack; +mod string; +mod string_cow; +mod string_ref; + +pub mod backend; + +pub use stack::StackString; +pub use string::*; +pub use string_cow::*; +pub use string_ref::*; + +#[cfg(test)] +mod test { + #[test] + fn test_size() { + println!( + "String: {}", + std::mem::size_of::<crate::string::StdString>() + ); + println!( + "Box<str>: {}", + std::mem::size_of::<crate::backend::DefaultStr>() + ); + println!( + "Box<Box<str>>: {}", + std::mem::size_of::<Box<crate::backend::DefaultStr>>() + ); + println!("str: {}", std::mem::size_of::<&'static str>()); + println!( + "Cow: {}", + std::mem::size_of::<std::borrow::Cow<'static, str>>() + ); + } +} diff --git a/vendor/kstring/src/stack.rs b/vendor/kstring/src/stack.rs new file mode 100644 index 000000000..93e2f0722 --- /dev/null +++ b/vendor/kstring/src/stack.rs @@ -0,0 +1,457 @@ +use std::fmt; + +pub(crate) type Len = u8; + +/// Fixed-size stack-allocated string +#[derive(Copy, Clone)] +pub struct StackString<const CAPACITY: usize> { + len: Len, + buffer: StrBuffer<CAPACITY>, +} + +impl<const CAPACITY: usize> StackString<CAPACITY> { + pub const CAPACITY: usize = CAPACITY; + pub const EMPTY: Self = Self::empty(); + + const fn empty() -> Self { + Self { + len: 0, + buffer: StrBuffer::empty(), + } + } + + /// Create a `StackString` from a `&str`, if it'll fit within `Self::CAPACITY` + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = kstring::StackString::<3>::try_new("foo"); + /// assert_eq!(s.as_deref(), Some("foo")); + /// let s = kstring::StackString::<3>::try_new("foobar"); + /// assert_eq!(s, None); + /// ``` + #[inline] + #[must_use] + pub fn try_new(s: &str) -> Option<Self> { + let len = s.as_bytes().len(); + if len <= Self::CAPACITY { + #[cfg(feature = "unsafe")] + let stack = { + unsafe { + // SAFETY: We've confirmed `len` is within size + Self::new_unchecked(s) + } + }; + #[cfg(not(feature = "unsafe"))] + let stack = { Self::new(s) }; + Some(stack) + } else { + None + } + } + + /// Create a `StackString` from a `&str` + /// + /// # Panic + /// + /// Calling this function with a string larger than `Self::CAPACITY` will panic + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = kstring::StackString::<3>::new("foo"); + /// assert_eq!(s, "foo"); + /// ``` + #[inline] + #[must_use] + pub fn new(s: &str) -> Self { + let len = s.as_bytes().len() as u8; + debug_assert!(Self::CAPACITY <= Len::MAX.into()); + let buffer = StrBuffer::new(s); + Self { len, buffer } + } + + /// Create a `StackString` from a `&str` + /// + /// # Safety + /// + /// Calling this function with a string larger than `Self::CAPACITY` is undefined behavior. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = unsafe { + /// // SAFETY: Literal is short-enough + /// kstring::StackString::<3>::new_unchecked("foo") + /// }; + /// assert_eq!(s, "foo"); + /// ``` + #[inline] + #[must_use] + #[cfg(feature = "unsafe")] + pub unsafe fn new_unchecked(s: &str) -> Self { + let len = s.as_bytes().len() as u8; + debug_assert!(Self::CAPACITY <= Len::MAX.into()); + let buffer = StrBuffer::new_unchecked(s); + Self { len, buffer } + } + + /// Extracts a string slice containing the entire `StackString`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = kstring::StackString::<3>::try_new("foo").unwrap(); + /// + /// assert_eq!("foo", s.as_str()); + /// ``` + #[inline] + #[must_use] + pub fn as_str(&self) -> &str { + let len = self.len as usize; + #[cfg(feature = "unsafe")] + unsafe { + // SAFETY: Constructors guarantee that `buffer[..len]` is a `str`, + // and we don't mutate the data afterwards. + self.buffer.as_str_unchecked(len) + } + #[cfg(not(feature = "unsafe"))] + self.buffer.as_str(len) + } + + /// Converts a `StackString` into a mutable string slice. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let mut s = kstring::StackString::<6>::try_new("foobar").unwrap(); + /// let s_mut_str = s.as_mut_str(); + /// + /// s_mut_str.make_ascii_uppercase(); + /// + /// assert_eq!("FOOBAR", s_mut_str); + /// ``` + #[inline] + #[must_use] + pub fn as_mut_str(&mut self) -> &mut str { + let len = self.len as usize; + #[cfg(feature = "unsafe")] + unsafe { + // SAFETY: Constructors guarantee that `buffer[..len]` is a `str`, + // and we don't mutate the data afterwards. + self.buffer.as_mut_str_unchecked(len) + } + #[cfg(not(feature = "unsafe"))] + self.buffer.as_mut_str(len) + } + + /// Returns the length of this `StasckString`, in bytes, not [`char`]s or + /// graphemes. In other words, it might not be what a human considers the + /// length of the string. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let a = kstring::StackString::<3>::try_new("foo").unwrap(); + /// assert_eq!(a.len(), 3); + /// + /// let fancy_f = kstring::StackString::<4>::try_new("Æ’oo").unwrap(); + /// assert_eq!(fancy_f.len(), 4); + /// assert_eq!(fancy_f.chars().count(), 3); + /// ``` + #[inline] + #[must_use] + pub fn len(&self) -> usize { + self.len as usize + } + + /// Returns `true` if this `StackString` has a length of zero, and `false` otherwise. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let mut v = kstring::StackString::<20>::EMPTY; + /// assert!(v.is_empty()); + /// + /// let a = kstring::StackString::<3>::try_new("foo").unwrap(); + /// assert!(!a.is_empty()); + /// ``` + #[inline] + #[must_use] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Truncates this `StackString`, removing all contents. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let mut s = kstring::StackString::<3>::try_new("foo").unwrap(); + /// + /// s.clear(); + /// + /// assert!(s.is_empty()); + /// assert_eq!(0, s.len()); + /// ``` + #[inline] + pub fn clear(&mut self) { + self.len = 0; + } + + /// Shortens this `StackString` to the specified length. + /// + /// If `new_len` is greater than the string's current length, this has no + /// effect. + /// + /// Note that this method has no effect on the allocated capacity + /// of the string + /// + /// # Panics + /// + /// Panics if `new_len` does not lie on a [`char`] boundary. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let mut s = kstring::StackString::<5>::try_new("hello").unwrap(); + /// + /// s.truncate(2); + /// + /// assert_eq!(s, "he"); + /// ``` + #[inline] + pub fn truncate(&mut self, new_len: usize) { + if new_len <= self.len() { + assert!(self.is_char_boundary(new_len)); + self.len = new_len as u8; + } + } +} + +impl<const CAPACITY: usize> Default for StackString<CAPACITY> { + fn default() -> Self { + Self::empty() + } +} + +impl<const CAPACITY: usize> std::ops::Deref for StackString<CAPACITY> { + type Target = str; + + #[inline] + fn deref(&self) -> &str { + self.as_str() + } +} + +impl<const CAPACITY: usize> Eq for StackString<CAPACITY> {} + +impl<const C1: usize, const C2: usize> PartialEq<StackString<C1>> for StackString<C2> { + #[inline] + fn eq(&self, other: &StackString<C1>) -> bool { + PartialEq::eq(self.as_str(), other.as_str()) + } +} + +impl<const CAPACITY: usize> PartialEq<str> for StackString<CAPACITY> { + #[inline] + fn eq(&self, other: &str) -> bool { + PartialEq::eq(self.as_str(), other) + } +} + +impl<'s, const CAPACITY: usize> PartialEq<&'s str> for StackString<CAPACITY> { + #[inline] + fn eq(&self, other: &&str) -> bool { + PartialEq::eq(self.as_str(), *other) + } +} + +impl<const CAPACITY: usize> PartialEq<String> for StackString<CAPACITY> { + #[inline] + fn eq(&self, other: &String) -> bool { + PartialEq::eq(self.as_str(), other.as_str()) + } +} + +impl<const CAPACITY: usize> Ord for StackString<CAPACITY> { + #[inline] + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.as_str().cmp(other.as_str()) + } +} + +impl<const C1: usize, const C2: usize> PartialOrd<StackString<C1>> for StackString<C2> { + #[inline] + fn partial_cmp(&self, other: &StackString<C1>) -> Option<std::cmp::Ordering> { + self.as_str().partial_cmp(other.as_str()) + } +} + +impl<const CAPACITY: usize> PartialOrd<str> for StackString<CAPACITY> { + #[inline] + fn partial_cmp(&self, other: &str) -> Option<std::cmp::Ordering> { + self.as_str().partial_cmp(other) + } +} + +impl<'s, const CAPACITY: usize> PartialOrd<&'s str> for StackString<CAPACITY> { + #[inline] + fn partial_cmp(&self, other: &&str) -> Option<std::cmp::Ordering> { + self.as_str().partial_cmp(other) + } +} + +impl<const CAPACITY: usize> PartialOrd<String> for StackString<CAPACITY> { + #[inline] + fn partial_cmp(&self, other: &String) -> Option<std::cmp::Ordering> { + self.as_str().partial_cmp(other.as_str()) + } +} + +impl<const CAPACITY: usize> std::hash::Hash for StackString<CAPACITY> { + #[inline] + fn hash<H: std::hash::Hasher>(&self, state: &mut H) { + self.as_str().hash(state); + } +} + +impl<const CAPACITY: usize> fmt::Debug for StackString<CAPACITY> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self.as_str(), f) + } +} + +impl<const CAPACITY: usize> fmt::Display for StackString<CAPACITY> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self.as_str(), f) + } +} + +impl<const CAPACITY: usize> AsRef<str> for StackString<CAPACITY> { + #[inline] + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl<const CAPACITY: usize> AsRef<[u8]> for StackString<CAPACITY> { + #[inline] + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl<const CAPACITY: usize> AsRef<std::ffi::OsStr> for StackString<CAPACITY> { + #[inline] + fn as_ref(&self) -> &std::ffi::OsStr { + (&**self).as_ref() + } +} + +impl<const CAPACITY: usize> AsRef<std::path::Path> for StackString<CAPACITY> { + #[inline] + fn as_ref(&self) -> &std::path::Path { + std::path::Path::new(self) + } +} + +impl<const CAPACITY: usize> std::borrow::Borrow<str> for StackString<CAPACITY> { + #[inline] + fn borrow(&self) -> &str { + self.as_str() + } +} + +#[derive(Copy, Clone)] +#[repr(transparent)] +pub(crate) struct StrBuffer<const CAPACITY: usize>([u8; CAPACITY]); + +impl<const CAPACITY: usize> StrBuffer<CAPACITY> { + pub(crate) const fn empty() -> Self { + let array = [0; CAPACITY]; + StrBuffer(array) + } + + #[inline] + pub(crate) fn new(s: &str) -> Self { + let len = s.as_bytes().len(); + debug_assert!(len <= CAPACITY); + let mut buffer = Self::default(); + if let Some(buffer) = buffer.0.get_mut(..len) { + buffer.copy_from_slice(s.as_bytes()); + } else { + panic!("`{}` is larger than capacity {}", s, CAPACITY); + } + buffer + } + + #[inline] + #[cfg(not(feature = "unsafe"))] + pub(crate) fn as_str(&self, len: usize) -> &str { + let slice = self.0.get(..len).unwrap(); + std::str::from_utf8(slice).unwrap() + } + + #[inline] + #[cfg(not(feature = "unsafe"))] + pub(crate) fn as_mut_str(&mut self, len: usize) -> &mut str { + let slice = self.0.get_mut(..len).unwrap(); + std::str::from_utf8_mut(slice).unwrap() + } +} + +impl<const CAPACITY: usize> StrBuffer<CAPACITY> { + #[inline] + #[cfg(feature = "unsafe")] + pub(crate) unsafe fn new_unchecked(s: &str) -> Self { + let len = s.as_bytes().len(); + debug_assert!(len <= CAPACITY); + let mut buffer = Self::default(); + buffer + .0 + .get_unchecked_mut(..len) + .copy_from_slice(s.as_bytes()); + buffer + } + + #[inline] + #[cfg(feature = "unsafe")] + pub(crate) unsafe fn as_str_unchecked(&self, len: usize) -> &str { + let slice = self.0.get_unchecked(..len); + std::str::from_utf8_unchecked(slice) + } + + #[inline] + #[cfg(feature = "unsafe")] + pub(crate) unsafe fn as_mut_str_unchecked(&mut self, len: usize) -> &mut str { + let slice = self.0.get_unchecked_mut(..len); + std::str::from_utf8_unchecked_mut(slice) + } +} + +impl<const CAPACITY: usize> Default for StrBuffer<CAPACITY> { + fn default() -> Self { + Self::empty() + } +} diff --git a/vendor/kstring/src/string.rs b/vendor/kstring/src/string.rs new file mode 100644 index 000000000..ed39d188a --- /dev/null +++ b/vendor/kstring/src/string.rs @@ -0,0 +1,865 @@ +use std::{borrow::Cow, fmt}; + +use crate::stack::StackString; +use crate::KStringCowBase; +use crate::KStringRef; + +pub(crate) type StdString = std::string::String; + +/// A UTF-8 encoded, immutable string. +pub type KString = KStringBase<crate::backend::DefaultStr>; + +/// A UTF-8 encoded, immutable string. +#[derive(Clone)] +#[repr(transparent)] +pub struct KStringBase<B> { + inner: KStringInner<B>, +} + +impl<B> KStringBase<B> { + pub const EMPTY: Self = KStringBase::from_static(""); + + /// Create a new empty `KStringBase`. + #[inline] + #[must_use] + pub fn new() -> Self { + Self::EMPTY + } + + /// Create a reference to a `'static` data. + #[inline] + #[must_use] + pub const fn from_static(other: &'static str) -> Self { + Self { + inner: KStringInner::from_static(other), + } + } + + /// Create an inline string, if possible + #[inline] + #[must_use] + pub fn try_inline(other: &str) -> Option<Self> { + KStringInner::try_inline(other).map(|inner| Self { inner }) + } +} + +impl<B: crate::backend::HeapStr> KStringBase<B> { + /// Create an owned `KStringBase`. + #[inline] + #[must_use] + pub fn from_boxed(other: crate::backend::BoxedStr) -> Self { + Self { + inner: KStringInner::from_boxed(other), + } + } + + /// Create an owned `KStringBase`. + #[inline] + #[must_use] + pub fn from_string(other: StdString) -> Self { + Self { + inner: KStringInner::from_string(other), + } + } + + /// Create an owned `KStringBase` optimally from a reference. + #[inline] + #[must_use] + pub fn from_ref(other: &str) -> Self { + Self { + inner: KStringInner::from_ref(other), + } + } + + /// Get a reference to the `KStringBase`. + #[inline] + #[must_use] + pub fn as_ref(&self) -> KStringRef<'_> { + self.inner.as_ref() + } + + /// Extracts a string slice containing the entire `KStringBase`. + #[inline] + #[must_use] + pub fn as_str(&self) -> &str { + self.inner.as_str() + } + + /// Convert to a mutable string type, cloning the data if necessary. + #[inline] + #[must_use] + pub fn into_string(self) -> StdString { + String::from(self.into_boxed_str()) + } + + /// Convert to a mutable string type, cloning the data if necessary. + #[inline] + #[must_use] + pub fn into_boxed_str(self) -> crate::backend::BoxedStr { + self.inner.into_boxed_str() + } + + /// Convert to a Cow str + #[inline] + #[must_use] + pub fn into_cow_str(self) -> Cow<'static, str> { + self.inner.into_cow_str() + } +} + +impl<B: crate::backend::HeapStr> std::ops::Deref for KStringBase<B> { + type Target = str; + + #[inline] + fn deref(&self) -> &str { + self.as_str() + } +} + +impl<B: crate::backend::HeapStr> Eq for KStringBase<B> {} + +impl<'s, B: crate::backend::HeapStr> PartialEq<KStringBase<B>> for KStringBase<B> { + #[inline] + fn eq(&self, other: &Self) -> bool { + PartialEq::eq(self.as_str(), other.as_str()) + } +} + +impl<'s, B: crate::backend::HeapStr> PartialEq<str> for KStringBase<B> { + #[inline] + fn eq(&self, other: &str) -> bool { + PartialEq::eq(self.as_str(), other) + } +} + +impl<'s, B: crate::backend::HeapStr> PartialEq<&'s str> for KStringBase<B> { + #[inline] + fn eq(&self, other: &&str) -> bool { + PartialEq::eq(self.as_str(), *other) + } +} + +impl<'s, B: crate::backend::HeapStr> PartialEq<String> for KStringBase<B> { + #[inline] + fn eq(&self, other: &StdString) -> bool { + PartialEq::eq(self.as_str(), other.as_str()) + } +} + +impl<B: crate::backend::HeapStr> Ord for KStringBase<B> { + #[inline] + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.as_str().cmp(other.as_str()) + } +} + +impl<B: crate::backend::HeapStr> PartialOrd for KStringBase<B> { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { + self.as_str().partial_cmp(other.as_str()) + } +} + +impl<B: crate::backend::HeapStr> std::hash::Hash for KStringBase<B> { + #[inline] + fn hash<H: std::hash::Hasher>(&self, state: &mut H) { + self.as_str().hash(state); + } +} + +impl<B: crate::backend::HeapStr> fmt::Debug for KStringBase<B> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.as_str().fmt(f) + } +} + +impl<B: crate::backend::HeapStr> fmt::Display for KStringBase<B> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self.as_str(), f) + } +} + +impl<B: crate::backend::HeapStr> AsRef<str> for KStringBase<B> { + #[inline] + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl<B: crate::backend::HeapStr> AsRef<[u8]> for KStringBase<B> { + #[inline] + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl<B: crate::backend::HeapStr> AsRef<std::ffi::OsStr> for KStringBase<B> { + #[inline] + fn as_ref(&self) -> &std::ffi::OsStr { + (&**self).as_ref() + } +} + +impl<B: crate::backend::HeapStr> AsRef<std::path::Path> for KStringBase<B> { + #[inline] + fn as_ref(&self) -> &std::path::Path { + std::path::Path::new(self) + } +} + +impl<B: crate::backend::HeapStr> std::borrow::Borrow<str> for KStringBase<B> { + #[inline] + fn borrow(&self) -> &str { + self.as_str() + } +} + +impl<B: crate::backend::HeapStr> Default for KStringBase<B> { + #[inline] + fn default() -> Self { + Self::new() + } +} + +impl<'s, B: crate::backend::HeapStr> From<KStringRef<'s>> for KStringBase<B> { + #[inline] + fn from(other: KStringRef<'s>) -> Self { + other.to_owned() + } +} + +impl<'s, B: crate::backend::HeapStr> From<&'s KStringRef<'s>> for KStringBase<B> { + #[inline] + fn from(other: &'s KStringRef<'s>) -> Self { + other.to_owned() + } +} + +impl<'s, B: crate::backend::HeapStr> From<KStringCowBase<'s, B>> for KStringBase<B> { + #[inline] + fn from(other: KStringCowBase<'s, B>) -> Self { + other.into_owned() + } +} + +impl<'s, B: crate::backend::HeapStr> From<&'s KStringCowBase<'s, B>> for KStringBase<B> { + #[inline] + fn from(other: &'s KStringCowBase<'s, B>) -> Self { + other.clone().into_owned() + } +} + +impl<B: crate::backend::HeapStr> From<StdString> for KStringBase<B> { + #[inline] + fn from(other: StdString) -> Self { + Self::from_string(other) + } +} + +impl<'s, B: crate::backend::HeapStr> From<&'s StdString> for KStringBase<B> { + #[inline] + fn from(other: &'s StdString) -> Self { + Self::from_ref(other) + } +} + +impl<B: crate::backend::HeapStr> From<crate::backend::BoxedStr> for KStringBase<B> { + #[inline] + fn from(other: crate::backend::BoxedStr) -> Self { + Self::from_boxed(other) + } +} + +impl<'s, B: crate::backend::HeapStr> From<&'s crate::backend::BoxedStr> for KStringBase<B> { + #[inline] + fn from(other: &'s crate::backend::BoxedStr) -> Self { + Self::from_ref(other) + } +} + +impl<B: crate::backend::HeapStr> From<&'static str> for KStringBase<B> { + #[inline] + fn from(other: &'static str) -> Self { + Self::from_static(other) + } +} + +impl<B: crate::backend::HeapStr> std::str::FromStr for KStringBase<B> { + type Err = std::convert::Infallible; + #[inline] + fn from_str(s: &str) -> Result<Self, Self::Err> { + Ok(Self::from_ref(s)) + } +} + +#[cfg(feature = "serde")] +impl<B: crate::backend::HeapStr> serde::Serialize for KStringBase<B> { + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + serializer.serialize_str(self.as_str()) + } +} + +#[cfg(feature = "serde")] +impl<'de, B: crate::backend::HeapStr> serde::Deserialize<'de> for KStringBase<B> { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_string(StringVisitor(std::marker::PhantomData)) + } +} + +#[cfg(feature = "serde")] +struct StringVisitor<B>(std::marker::PhantomData<B>); + +#[cfg(feature = "serde")] +impl<'de, B: crate::backend::HeapStr> serde::de::Visitor<'de> for StringVisitor<B> { + type Value = KStringBase<B>; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("a string") + } + + fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> + where + E: serde::de::Error, + { + Ok(Self::Value::from_ref(v)) + } + + fn visit_string<E>(self, v: String) -> Result<Self::Value, E> + where + E: serde::de::Error, + { + Ok(Self::Value::from_string(v)) + } + + fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E> + where + E: serde::de::Error, + { + match std::str::from_utf8(v) { + Ok(s) => Ok(Self::Value::from_ref(s)), + Err(_) => Err(serde::de::Error::invalid_value( + serde::de::Unexpected::Bytes(v), + &self, + )), + } + } + + fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E> + where + E: serde::de::Error, + { + match String::from_utf8(v) { + Ok(s) => Ok(Self::Value::from_string(s)), + Err(e) => Err(serde::de::Error::invalid_value( + serde::de::Unexpected::Bytes(&e.into_bytes()), + &self, + )), + } + } +} + +use inner::KStringInner; + +#[cfg(not(feature = "unsafe"))] +mod inner { + use super::*; + + pub(super) enum KStringInner<B> { + Singleton(&'static str), + Inline(StackString<CAPACITY>), + Owned(B), + } + + impl<B> KStringInner<B> { + /// Create a reference to a `'static` data. + #[inline] + pub const fn from_static(other: &'static str) -> Self { + Self::Singleton(other) + } + + #[inline] + pub fn try_inline(other: &str) -> Option<Self> { + StackString::try_new(other).map(Self::Inline) + } + } + + impl<B: crate::backend::HeapStr> KStringInner<B> { + #[inline] + pub(super) fn from_boxed(other: crate::backend::BoxedStr) -> Self { + #[allow(clippy::useless_conversion)] + Self::Owned(B::from_boxed_str(other)) + } + + #[inline] + pub(super) fn from_string(other: StdString) -> Self { + if (0..=CAPACITY).contains(&other.len()) { + let inline = { StackString::new(other.as_str()) }; + Self::Inline(inline) + } else { + Self::from_boxed(other.into_boxed_str()) + } + } + + #[inline] + pub(super) fn from_ref(other: &str) -> Self { + if (0..=CAPACITY).contains(&other.len()) { + let inline = { StackString::new(other) }; + Self::Inline(inline) + } else { + Self::Owned(B::from_str(other)) + } + } + + #[inline] + pub(super) fn as_ref(&self) -> KStringRef<'_> { + match self { + Self::Singleton(s) => KStringRef::from_static(s), + Self::Inline(s) => KStringRef::from_ref(s.as_str()), + Self::Owned(s) => KStringRef::from_ref(s.as_str()), + } + } + + #[inline] + pub(super) fn as_str(&self) -> &str { + match self { + Self::Singleton(s) => s, + Self::Inline(s) => s.as_str(), + Self::Owned(s) => s.as_str(), + } + } + + #[inline] + pub(super) fn into_boxed_str(self) -> crate::backend::BoxedStr { + match self { + Self::Singleton(s) => crate::backend::BoxedStr::from(s), + Self::Inline(s) => crate::backend::BoxedStr::from(s.as_str()), + Self::Owned(s) => crate::backend::BoxedStr::from(s.as_str()), + } + } + + /// Convert to a Cow str + #[inline] + pub(super) fn into_cow_str(self) -> Cow<'static, str> { + match self { + Self::Singleton(s) => Cow::Borrowed(s), + Self::Inline(s) => Cow::Owned(s.as_str().into()), + Self::Owned(s) => Cow::Owned(s.as_str().into()), + } + } + } + + // Explicit to avoid inlining which cuts clone times in half. + // + // An automatically derived `clone()` has 10ns overhead while the explicit `Deref`/`as_str` has + // none of that. Being explicit and removing the `#[inline]` attribute dropped the overhead to + // 5ns. + // + // My only guess is that the `clone()` calls we delegate to are just that much bigger than + // `as_str()` that, when combined with a jump table, is blowing the icache, slowing things down. + impl<B: Clone> Clone for KStringInner<B> { + fn clone(&self) -> Self { + match self { + Self::Singleton(s) => Self::Singleton(s), + Self::Inline(s) => Self::Inline(*s), + Self::Owned(s) => Self::Owned(s.clone()), + } + } + } + + #[allow(unused)] + const LEN_SIZE: usize = std::mem::size_of::<crate::stack::Len>(); + + #[allow(unused)] + const TAG_SIZE: usize = std::mem::size_of::<u8>(); + + #[allow(unused)] + const MAX_CAPACITY: usize = + std::mem::size_of::<crate::string::StdString>() - TAG_SIZE - LEN_SIZE; + + // Performance seems to slow down when trying to occupy all of the padding left by `String`'s + // discriminant. The question is whether faster len=1-16 "allocations" outweighs going to the heap + // for len=17-22. + #[allow(unused)] + const ALIGNED_CAPACITY: usize = std::mem::size_of::<crate::backend::DefaultStr>() - LEN_SIZE; + + #[cfg(feature = "max_inline")] + const CAPACITY: usize = MAX_CAPACITY; + #[cfg(not(feature = "max_inline"))] + const CAPACITY: usize = ALIGNED_CAPACITY; +} + +#[cfg(feature = "unsafe")] +mod inner { + use super::*; + + pub(super) union KStringInner<B> { + tag: TagVariant, + singleton: SingletonVariant, + owned: std::mem::ManuallyDrop<OwnedVariant<B>>, + inline: InlineVariant, + } + + impl<B> KStringInner<B> { + /// Create a reference to a `'static` data. + #[inline] + pub const fn from_static(other: &'static str) -> Self { + Self { + singleton: SingletonVariant::new(other), + } + } + + #[inline] + pub fn try_inline(other: &str) -> Option<Self> { + StackString::try_new(other).map(|inline| Self { + inline: InlineVariant::new(inline), + }) + } + + #[inline] + const fn tag(&self) -> Tag { + unsafe { + // SAFETY: `tag` is in the same spot in each variant + self.tag.tag + } + } + } + + impl<B: crate::backend::HeapStr> KStringInner<B> { + #[inline] + pub(super) fn from_boxed(other: crate::backend::BoxedStr) -> Self { + #[allow(clippy::useless_conversion)] + let payload = B::from_boxed_str(other); + Self { + owned: std::mem::ManuallyDrop::new(OwnedVariant::new(payload)), + } + } + + #[inline] + pub(super) fn from_string(other: StdString) -> Self { + if (0..=CAPACITY).contains(&other.len()) { + let payload = unsafe { + // SAFETY: range check ensured this is always safe + StackString::new_unchecked(other.as_str()) + }; + Self { + inline: InlineVariant::new(payload), + } + } else { + Self::from_boxed(other.into_boxed_str()) + } + } + + #[inline] + pub(super) fn from_ref(other: &str) -> Self { + if (0..=CAPACITY).contains(&other.len()) { + let payload = unsafe { + // SAFETY: range check ensured this is always safe + StackString::new_unchecked(other) + }; + Self { + inline: InlineVariant::new(payload), + } + } else { + #[allow(clippy::useless_conversion)] + let payload = B::from_str(other); + Self { + owned: std::mem::ManuallyDrop::new(OwnedVariant::new(payload)), + } + } + } + + #[inline] + pub(super) fn as_ref(&self) -> KStringRef<'_> { + let tag = self.tag(); + unsafe { + // SAFETY: `tag` ensures access to correct variant + if tag.is_singleton() { + KStringRef::from_static(self.singleton.payload) + } else if tag.is_owned() { + KStringRef::from_ref(self.owned.payload.as_str()) + } else { + debug_assert!(tag.is_inline()); + KStringRef::from_ref(self.inline.payload.as_str()) + } + } + } + + #[inline] + pub(super) fn as_str(&self) -> &str { + let tag = self.tag(); + unsafe { + // SAFETY: `tag` ensures access to correct variant + if tag.is_singleton() { + self.singleton.payload + } else if tag.is_owned() { + self.owned.payload.as_str() + } else { + debug_assert!(tag.is_inline()); + self.inline.payload.as_str() + } + } + } + + #[inline] + pub(super) fn into_boxed_str(self) -> crate::backend::BoxedStr { + let tag = self.tag(); + unsafe { + // SAFETY: `tag` ensures access to correct variant + if tag.is_singleton() { + crate::backend::BoxedStr::from(self.singleton.payload) + } else if tag.is_owned() { + crate::backend::BoxedStr::from(self.owned.payload.as_str()) + } else { + debug_assert!(tag.is_inline()); + crate::backend::BoxedStr::from(self.inline.payload.as_ref()) + } + } + } + + /// Convert to a Cow str + #[inline] + pub(super) fn into_cow_str(self) -> Cow<'static, str> { + let tag = self.tag(); + unsafe { + // SAFETY: `tag` ensures access to correct variant + if tag.is_singleton() { + Cow::Borrowed(self.singleton.payload) + } else if tag.is_owned() { + Cow::Owned(self.owned.payload.as_str().into()) + } else { + debug_assert!(tag.is_inline()); + Cow::Owned(self.inline.payload.as_str().into()) + } + } + } + } + + // Explicit to avoid inlining which cuts clone times in half. + // + // An automatically derived `clone()` has 10ns overhead while the explicit `Deref`/`as_str` has + // none of that. Being explicit and removing the `#[inline]` attribute dropped the overhead to + // 5ns. + // + // My only guess is that the `clone()` calls we delegate to are just that much bigger than + // `as_str()` that, when combined with a jump table, is blowing the icache, slowing things down. + impl<B: Clone> Clone for KStringInner<B> { + fn clone(&self) -> Self { + let tag = self.tag(); + if tag.is_owned() { + unsafe { + // SAFETY: `tag` ensures access to correct variant + Self { + owned: std::mem::ManuallyDrop::new(OwnedVariant::new( + self.owned.payload.clone(), + )), + } + } + } else { + unsafe { + // SAFETY: `tag` ensures access to correct variant + // SAFETY: non-owned types are copyable + std::mem::transmute_copy(self) + } + } + } + } + + impl<B> Drop for KStringInner<B> { + fn drop(&mut self) { + let tag = self.tag(); + if tag.is_owned() { + unsafe { + // SAFETY: `tag` ensures we are using the right variant + std::mem::ManuallyDrop::drop(&mut self.owned) + } + } + } + } + + #[allow(unused)] + const LEN_SIZE: usize = std::mem::size_of::<crate::stack::Len>(); + + #[allow(unused)] + const TAG_SIZE: usize = std::mem::size_of::<Tag>(); + + #[allow(unused)] + const PAYLOAD_SIZE: usize = std::mem::size_of::<crate::backend::DefaultStr>(); + type Payload = Padding<PAYLOAD_SIZE>; + + #[allow(unused)] + const TARGET_SIZE: usize = std::mem::size_of::<Target>(); + type Target = crate::string::StdString; + + #[allow(unused)] + const MAX_CAPACITY: usize = TARGET_SIZE - LEN_SIZE - TAG_SIZE; + + // Performance seems to slow down when trying to occupy all of the padding left by `String`'s + // discriminant. The question is whether faster len=1-16 "allocations" outweighs going to the heap + // for len=17-22. + #[allow(unused)] + const ALIGNED_CAPACITY: usize = PAYLOAD_SIZE - LEN_SIZE; + + #[cfg(feature = "max_inline")] + const CAPACITY: usize = MAX_CAPACITY; + #[cfg(not(feature = "max_inline"))] + const CAPACITY: usize = ALIGNED_CAPACITY; + + const PAYLOAD_PAD_SIZE: usize = TARGET_SIZE - PAYLOAD_SIZE - TAG_SIZE; + const INLINE_PAD_SIZE: usize = TARGET_SIZE - CAPACITY - LEN_SIZE - TAG_SIZE; + + #[derive(Copy, Clone)] + #[repr(C)] + struct TagVariant { + payload: Payload, + pad: Padding<PAYLOAD_PAD_SIZE>, + tag: Tag, + } + static_assertions::assert_eq_size!(Target, TagVariant); + + #[derive(Copy, Clone)] + #[repr(C)] + struct SingletonVariant { + payload: &'static str, + pad: Padding<PAYLOAD_PAD_SIZE>, + tag: Tag, + } + static_assertions::assert_eq_size!(Payload, &'static str); + static_assertions::assert_eq_size!(Target, SingletonVariant); + + impl SingletonVariant { + #[inline] + const fn new(payload: &'static str) -> Self { + Self { + payload, + pad: Padding::new(), + tag: Tag::SINGLETON, + } + } + } + + impl std::fmt::Debug for SingletonVariant { + #[inline] + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.payload.fmt(f) + } + } + + #[derive(Clone)] + #[repr(C)] + struct OwnedVariant<B> { + payload: B, + pad: Padding<PAYLOAD_PAD_SIZE>, + tag: Tag, + } + static_assertions::assert_eq_size!(Payload, crate::backend::DefaultStr); + static_assertions::assert_eq_size!(Target, OwnedVariant<crate::backend::DefaultStr>); + + impl<B> OwnedVariant<B> { + #[inline] + const fn new(payload: B) -> Self { + Self { + payload, + pad: Padding::new(), + tag: Tag::OWNED, + } + } + } + + impl<B: crate::backend::HeapStr> std::fmt::Debug for OwnedVariant<B> { + #[inline] + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.payload.fmt(f) + } + } + + #[derive(Copy, Clone)] + #[repr(C)] + struct InlineVariant { + payload: StackString<CAPACITY>, + pad: Padding<INLINE_PAD_SIZE>, + tag: Tag, + } + static_assertions::assert_eq_size!(Target, InlineVariant); + + impl InlineVariant { + #[inline] + const fn new(payload: StackString<CAPACITY>) -> Self { + Self { + payload, + pad: Padding::new(), + tag: Tag::INLINE, + } + } + } + + impl std::fmt::Debug for InlineVariant { + #[inline] + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.payload.fmt(f) + } + } + + #[derive(Copy, Clone, PartialEq, Eq)] + #[repr(transparent)] + struct Tag(u8); + + impl Tag { + const SINGLETON: Tag = Tag(0); + const OWNED: Tag = Tag(u8::MAX); + const INLINE: Tag = Tag(1); + + #[inline] + const fn is_singleton(self) -> bool { + self.0 == Self::SINGLETON.0 + } + + #[inline] + const fn is_owned(self) -> bool { + self.0 == Self::OWNED.0 + } + + #[inline] + const fn is_inline(self) -> bool { + !self.is_singleton() && !self.is_owned() + } + } + + #[derive(Copy, Clone)] + #[repr(transparent)] + struct Padding<const L: usize>([std::mem::MaybeUninit<u8>; L]); + + impl<const L: usize> Padding<L> { + const fn new() -> Self { + let padding = unsafe { + // SAFETY: Padding, never actually used + std::mem::MaybeUninit::uninit().assume_init() + }; + Self(padding) + } + } + + impl<const L: usize> Default for Padding<L> { + fn default() -> Self { + Self::new() + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_size() { + println!("KString: {}", std::mem::size_of::<KString>()); + } +} diff --git a/vendor/kstring/src/string_cow.rs b/vendor/kstring/src/string_cow.rs new file mode 100644 index 000000000..6a1b4b89a --- /dev/null +++ b/vendor/kstring/src/string_cow.rs @@ -0,0 +1,383 @@ +use std::{borrow::Cow, fmt}; + +use crate::KStringBase; +use crate::KStringRef; +use crate::KStringRefInner; + +type StdString = std::string::String; +type BoxedStr = Box<str>; + +/// A reference to a UTF-8 encoded, immutable string. +pub type KStringCow<'s> = KStringCowBase<'s, crate::backend::DefaultStr>; + +/// A reference to a UTF-8 encoded, immutable string. +#[derive(Clone)] +#[repr(transparent)] +pub struct KStringCowBase<'s, B = crate::backend::DefaultStr> { + pub(crate) inner: KStringCowInner<'s, B>, +} + +#[derive(Clone)] +pub(crate) enum KStringCowInner<'s, B> { + Borrowed(&'s str), + Owned(KStringBase<B>), +} + +impl<'s, B> KStringCowBase<'s, B> { + /// Create a new empty `KStringCowBase`. + #[inline] + #[must_use] + pub const fn new() -> Self { + Self::from_static("") + } + + /// Create a reference to a `'static` data. + #[inline] + #[must_use] + pub const fn from_static(other: &'static str) -> Self { + Self { + inner: KStringCowInner::Owned(KStringBase::from_static(other)), + } + } +} + +impl<'s, B: crate::backend::HeapStr> KStringCowBase<'s, B> { + /// Create an owned `KStringCowBase`. + #[inline] + #[must_use] + pub fn from_boxed(other: BoxedStr) -> Self { + Self { + inner: KStringCowInner::Owned(KStringBase::from_boxed(other)), + } + } + + /// Create an owned `KStringCowBase`. + #[inline] + #[must_use] + pub fn from_string(other: StdString) -> Self { + Self { + inner: KStringCowInner::Owned(KStringBase::from_string(other)), + } + } + + /// Create a reference to a borrowed data. + #[inline] + #[must_use] + pub fn from_ref(other: &'s str) -> Self { + Self { + inner: KStringCowInner::Borrowed(other), + } + } + + /// Get a reference to the `KStringBase`. + #[inline] + #[must_use] + pub fn as_ref(&self) -> KStringRef<'_> { + self.inner.as_ref() + } + + /// Clone the data into an owned-type. + #[inline] + #[must_use] + pub fn into_owned(self) -> KStringBase<B> { + self.inner.into_owned() + } + + /// Extracts a string slice containing the entire `KStringCowBase`. + #[inline] + #[must_use] + pub fn as_str(&self) -> &str { + self.inner.as_str() + } + + /// Convert to a mutable string type, cloning the data if necessary. + #[inline] + #[must_use] + pub fn into_string(self) -> StdString { + String::from(self.into_boxed_str()) + } + + /// Convert to a mutable string type, cloning the data if necessary. + #[inline] + #[must_use] + pub fn into_boxed_str(self) -> BoxedStr { + self.inner.into_boxed_str() + } + + /// Convert to a Cow str + #[inline] + #[must_use] + pub fn into_cow_str(self) -> Cow<'s, str> { + self.inner.into_cow_str() + } +} + +impl<'s, B: crate::backend::HeapStr> KStringCowInner<'s, B> { + #[inline] + fn as_ref(&self) -> KStringRef<'_> { + match self { + Self::Borrowed(s) => KStringRef::from_ref(s), + Self::Owned(s) => s.as_ref(), + } + } + + #[inline] + fn into_owned(self) -> KStringBase<B> { + match self { + Self::Borrowed(s) => KStringBase::from_ref(s), + Self::Owned(s) => s, + } + } + + #[inline] + fn as_str(&self) -> &str { + match self { + Self::Borrowed(s) => s, + Self::Owned(s) => s.as_str(), + } + } + + #[inline] + fn into_boxed_str(self) -> BoxedStr { + match self { + Self::Borrowed(s) => BoxedStr::from(s), + Self::Owned(s) => s.into_boxed_str(), + } + } + + /// Convert to a Cow str + #[inline] + fn into_cow_str(self) -> Cow<'s, str> { + match self { + Self::Borrowed(s) => Cow::Borrowed(s), + Self::Owned(s) => s.into_cow_str(), + } + } +} + +impl<'s, B: crate::backend::HeapStr> std::ops::Deref for KStringCowBase<'s, B> { + type Target = str; + + #[inline] + fn deref(&self) -> &str { + self.as_str() + } +} + +impl<'s, B: crate::backend::HeapStr> Eq for KStringCowBase<'s, B> {} + +impl<'s, B: crate::backend::HeapStr> PartialEq<KStringCowBase<'s, B>> for KStringCowBase<'s, B> { + #[inline] + fn eq(&self, other: &KStringCowBase<'s, B>) -> bool { + PartialEq::eq(self.as_str(), other.as_str()) + } +} + +impl<'s, B: crate::backend::HeapStr> PartialEq<str> for KStringCowBase<'s, B> { + #[inline] + fn eq(&self, other: &str) -> bool { + PartialEq::eq(self.as_str(), other) + } +} + +impl<'s, B: crate::backend::HeapStr> PartialEq<&'s str> for KStringCowBase<'s, B> { + #[inline] + fn eq(&self, other: &&str) -> bool { + PartialEq::eq(self.as_str(), *other) + } +} + +impl<'s, B: crate::backend::HeapStr> PartialEq<String> for KStringCowBase<'s, B> { + #[inline] + fn eq(&self, other: &StdString) -> bool { + PartialEq::eq(self.as_str(), other.as_str()) + } +} + +impl<'s, B: crate::backend::HeapStr> Ord for KStringCowBase<'s, B> { + #[inline] + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.as_str().cmp(other.as_str()) + } +} + +impl<'s, B: crate::backend::HeapStr> PartialOrd for KStringCowBase<'s, B> { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { + self.as_str().partial_cmp(other.as_str()) + } +} + +impl<'s, B: crate::backend::HeapStr> std::hash::Hash for KStringCowBase<'s, B> { + #[inline] + fn hash<H: std::hash::Hasher>(&self, state: &mut H) { + self.as_str().hash(state); + } +} + +impl<'s, B: crate::backend::HeapStr> fmt::Debug for KStringCowBase<'s, B> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.as_str().fmt(f) + } +} + +impl<'s, B: crate::backend::HeapStr> fmt::Display for KStringCowBase<'s, B> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self.as_str(), f) + } +} + +impl<'s, B: crate::backend::HeapStr> AsRef<str> for KStringCowBase<'s, B> { + #[inline] + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl<'s, B: crate::backend::HeapStr> AsRef<[u8]> for KStringCowBase<'s, B> { + #[inline] + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl<'s, B: crate::backend::HeapStr> AsRef<std::ffi::OsStr> for KStringCowBase<'s, B> { + #[inline] + fn as_ref(&self) -> &std::ffi::OsStr { + (&**self).as_ref() + } +} + +impl<'s, B: crate::backend::HeapStr> AsRef<std::path::Path> for KStringCowBase<'s, B> { + #[inline] + fn as_ref(&self) -> &std::path::Path { + std::path::Path::new(self) + } +} + +impl<'s, B: crate::backend::HeapStr> std::borrow::Borrow<str> for KStringCowBase<'s, B> { + #[inline] + fn borrow(&self) -> &str { + self.as_str() + } +} + +impl<'s, B> Default for KStringCowBase<'s, B> { + #[inline] + fn default() -> Self { + Self::new() + } +} + +impl<'s, B: crate::backend::HeapStr> From<KStringBase<B>> for KStringCowBase<'s, B> { + #[inline] + fn from(other: KStringBase<B>) -> Self { + let inner = KStringCowInner::Owned(other); + Self { inner } + } +} + +impl<'s, B: crate::backend::HeapStr> From<&'s KStringBase<B>> for KStringCowBase<'s, B> { + #[inline] + fn from(other: &'s KStringBase<B>) -> Self { + let other = other.as_ref(); + other.into() + } +} + +impl<'s, B: crate::backend::HeapStr> From<KStringRef<'s>> for KStringCowBase<'s, B> { + #[inline] + fn from(other: KStringRef<'s>) -> Self { + match other.inner { + KStringRefInner::Borrowed(s) => Self::from_ref(s), + KStringRefInner::Singleton(s) => Self::from_static(s), + } + } +} + +impl<'s, B: crate::backend::HeapStr> From<&'s KStringRef<'s>> for KStringCowBase<'s, B> { + #[inline] + fn from(other: &'s KStringRef<'s>) -> Self { + match other.inner { + KStringRefInner::Borrowed(s) => Self::from_ref(s), + KStringRefInner::Singleton(s) => Self::from_static(s), + } + } +} + +impl<'s, B: crate::backend::HeapStr> From<StdString> for KStringCowBase<'s, B> { + #[inline] + fn from(other: StdString) -> Self { + Self::from_string(other) + } +} + +impl<'s, B: crate::backend::HeapStr> From<&'s StdString> for KStringCowBase<'s, B> { + #[inline] + fn from(other: &'s StdString) -> Self { + Self::from_ref(other.as_str()) + } +} + +impl<'s, B: crate::backend::HeapStr> From<BoxedStr> for KStringCowBase<'s, B> { + #[inline] + fn from(other: BoxedStr) -> Self { + // Since the memory is already allocated, don't bother moving it into a FixedString + Self::from_boxed(other) + } +} + +impl<'s, B: crate::backend::HeapStr> From<&'s BoxedStr> for KStringCowBase<'s, B> { + #[inline] + fn from(other: &'s BoxedStr) -> Self { + Self::from_ref(other) + } +} + +impl<'s, B: crate::backend::HeapStr> From<&'s str> for KStringCowBase<'s, B> { + #[inline] + fn from(other: &'s str) -> Self { + Self::from_ref(other) + } +} + +impl<B: crate::backend::HeapStr> std::str::FromStr for KStringCowBase<'_, B> { + type Err = std::convert::Infallible; + #[inline] + fn from_str(s: &str) -> Result<Self, Self::Err> { + Ok(Self::from_string(s.into())) + } +} + +#[cfg(feature = "serde")] +impl<'s, B: crate::backend::HeapStr> serde::Serialize for KStringCowBase<'s, B> { + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + serializer.serialize_str(self.as_str()) + } +} + +#[cfg(feature = "serde")] +impl<'de, 's, B: crate::backend::HeapStr> serde::Deserialize<'de> for KStringCowBase<'s, B> { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: serde::Deserializer<'de>, + { + KStringBase::deserialize(deserializer).map(|s| s.into()) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_size() { + println!("KStringCow: {}", std::mem::size_of::<KStringCow<'static>>()); + } +} diff --git a/vendor/kstring/src/string_ref.rs b/vendor/kstring/src/string_ref.rs new file mode 100644 index 000000000..a79b9d46c --- /dev/null +++ b/vendor/kstring/src/string_ref.rs @@ -0,0 +1,277 @@ +use std::fmt; + +use crate::KStringBase; +use crate::KStringCowBase; + +type StdString = std::string::String; +type BoxedStr = Box<str>; + +/// A reference to a UTF-8 encoded, immutable string. +#[derive(Copy, Clone)] +#[repr(transparent)] +pub struct KStringRef<'s> { + pub(crate) inner: KStringRefInner<'s>, +} + +#[derive(Copy, Clone, Debug)] +pub(crate) enum KStringRefInner<'s> { + Borrowed(&'s str), + Singleton(&'static str), +} + +impl<'s> KStringRef<'s> { + /// Create a new empty `KStringBase`. + #[inline] + #[must_use] + pub const fn new() -> Self { + Self::from_static("") + } + + /// Create a reference to a `'static` data. + #[inline] + #[must_use] + pub const fn from_static(other: &'static str) -> Self { + Self { + inner: KStringRefInner::Singleton(other), + } + } + + /// Create a reference to a borrowed data. + #[inline] + #[must_use] + pub fn from_ref(other: &'s str) -> Self { + Self { + inner: KStringRefInner::Borrowed(other), + } + } + + /// Clone the data into an owned-type. + #[inline] + #[must_use] + #[allow(clippy::wrong_self_convention)] + pub fn to_owned<B: crate::backend::HeapStr>(&self) -> KStringBase<B> { + self.inner.to_owned() + } + + /// Extracts a string slice containing the entire `KStringRef`. + #[inline] + #[must_use] + pub fn as_str(&self) -> &str { + self.inner.as_str() + } + + /// Convert to a mutable string type, cloning the data if necessary. + #[inline] + #[must_use] + pub fn into_mut(self) -> StdString { + self.inner.into_mut() + } +} + +impl<'s> KStringRefInner<'s> { + #[inline] + #[allow(clippy::wrong_self_convention)] + fn to_owned<B: crate::backend::HeapStr>(&self) -> KStringBase<B> { + match self { + Self::Borrowed(s) => KStringBase::from_ref(s), + Self::Singleton(s) => KStringBase::from_static(s), + } + } + + #[inline] + fn as_str(&self) -> &str { + match self { + Self::Borrowed(s) => s, + Self::Singleton(s) => s, + } + } + + #[inline] + fn into_mut(self) -> StdString { + self.as_str().to_owned() + } +} + +impl<'s> std::ops::Deref for KStringRef<'s> { + type Target = str; + + #[inline] + fn deref(&self) -> &str { + self.as_str() + } +} + +impl<'s> Eq for KStringRef<'s> {} + +impl<'s> PartialEq<KStringRef<'s>> for KStringRef<'s> { + #[inline] + fn eq(&self, other: &KStringRef<'s>) -> bool { + PartialEq::eq(self.as_str(), other.as_str()) + } +} + +impl<'s> PartialEq<str> for KStringRef<'s> { + #[inline] + fn eq(&self, other: &str) -> bool { + PartialEq::eq(self.as_str(), other) + } +} + +impl<'s> PartialEq<&'s str> for KStringRef<'s> { + #[inline] + fn eq(&self, other: &&str) -> bool { + PartialEq::eq(self.as_str(), *other) + } +} + +impl<'s> PartialEq<String> for KStringRef<'s> { + #[inline] + fn eq(&self, other: &StdString) -> bool { + PartialEq::eq(self.as_str(), other.as_str()) + } +} + +impl<'s> Ord for KStringRef<'s> { + #[inline] + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.as_str().cmp(other.as_str()) + } +} + +impl<'s> PartialOrd for KStringRef<'s> { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { + self.as_str().partial_cmp(other.as_str()) + } +} + +impl<'s> std::hash::Hash for KStringRef<'s> { + #[inline] + fn hash<H: std::hash::Hasher>(&self, state: &mut H) { + self.as_str().hash(state); + } +} + +impl<'s> fmt::Debug for KStringRef<'s> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.inner, f) + } +} + +impl<'s> fmt::Display for KStringRef<'s> { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self.as_str(), f) + } +} + +impl<'s> AsRef<str> for KStringRef<'s> { + #[inline] + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl<'s> AsRef<[u8]> for KStringRef<'s> { + #[inline] + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl<'s> AsRef<std::ffi::OsStr> for KStringRef<'s> { + #[inline] + fn as_ref(&self) -> &std::ffi::OsStr { + (&**self).as_ref() + } +} + +impl<'s> AsRef<std::path::Path> for KStringRef<'s> { + #[inline] + fn as_ref(&self) -> &std::path::Path { + std::path::Path::new(self) + } +} + +impl<'s> std::borrow::Borrow<str> for KStringRef<'s> { + #[inline] + fn borrow(&self) -> &str { + self.as_str() + } +} + +impl<'s> Default for KStringRef<'s> { + #[inline] + fn default() -> Self { + Self::new() + } +} + +impl<'s, B: crate::backend::HeapStr> From<&'s KStringBase<B>> for KStringRef<'s> { + #[inline] + fn from(other: &'s KStringBase<B>) -> Self { + other.as_ref() + } +} + +impl<'s, B: crate::backend::HeapStr> From<&'s KStringCowBase<'s, B>> for KStringRef<'s> { + #[inline] + fn from(other: &'s KStringCowBase<'s, B>) -> Self { + other.as_ref() + } +} + +impl<'s> From<&'s StdString> for KStringRef<'s> { + #[inline] + fn from(other: &'s StdString) -> Self { + KStringRef::from_ref(other.as_str()) + } +} + +impl<'s> From<&'s BoxedStr> for KStringRef<'s> { + #[inline] + fn from(other: &'s BoxedStr) -> Self { + Self::from_ref(other) + } +} + +impl<'s> From<&'s str> for KStringRef<'s> { + #[inline] + fn from(other: &'s str) -> Self { + KStringRef::from_ref(other) + } +} + +#[cfg(feature = "serde")] +impl<'s> serde::Serialize for KStringRef<'s> { + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + serializer.serialize_str(self.as_str()) + } +} + +#[cfg(feature = "serde")] +impl<'de: 's, 's> serde::Deserialize<'de> for KStringRef<'s> { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: serde::Deserializer<'de>, + { + let s: &'s str = serde::Deserialize::deserialize(deserializer)?; + let s = KStringRef::from_ref(s); + Ok(s) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_size() { + println!("KStringRef: {}", std::mem::size_of::<KStringRef<'static>>()); + } +} |