diff options
Diffstat (limited to 'vendor/icu_list')
-rw-r--r-- | vendor/icu_list/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | vendor/icu_list/Cargo.lock | 1064 | ||||
-rw-r--r-- | vendor/icu_list/Cargo.toml | 114 | ||||
-rw-r--r-- | vendor/icu_list/LICENSE | 51 | ||||
-rw-r--r-- | vendor/icu_list/README.md | 69 | ||||
-rw-r--r-- | vendor/icu_list/examples/and_list.rs | 29 | ||||
-rw-r--r-- | vendor/icu_list/src/error.rs | 27 | ||||
-rw-r--r-- | vendor/icu_list/src/lib.rs | 122 | ||||
-rw-r--r-- | vendor/icu_list/src/list_formatter.rs | 319 | ||||
-rw-r--r-- | vendor/icu_list/src/provider.rs | 465 | ||||
-rw-r--r-- | vendor/icu_list/src/string_matcher.rs | 213 |
11 files changed, 2474 insertions, 0 deletions
diff --git a/vendor/icu_list/.cargo-checksum.json b/vendor/icu_list/.cargo-checksum.json new file mode 100644 index 000000000..31667c731 --- /dev/null +++ b/vendor/icu_list/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.lock":"f650478383a2f1a7aed551b2d4650d83a2e8cc3d44c749a0e4fcfc649130b9da","Cargo.toml":"ac843eda0523eadb2d7c3bb39ea34ca5c45648f2e00c1aca87607a427f583e73","LICENSE":"4ad7541d66a407234e2c84902124cef325c29f3e966353efdb800bedb8b8da21","README.md":"33b424bdceea5edc4d3638592b007bf825e25a96e7fe9101a3ad04ea63637150","examples/and_list.rs":"2cf046f8af9892949db8c8b259ac060b9de5781a5941bec5d346cf82e9371774","src/error.rs":"3cf8a7962af6b43a91d9227e4d97824e4b2852d3d50fc00fb29c779768c1b915","src/lib.rs":"c0bd00a3d83d4285d33cef2af12bd9cae380ad9c81702ba7552ce14283e9651d","src/list_formatter.rs":"a5f6f9c8bf35c6e1d4cb712a73b31454c0d081572bbc0efd9997bf6013346825","src/provider.rs":"1ca4026dbc00c901763a41a4b4ad0083c32888b95d11f464a9e3389c7d976fec","src/string_matcher.rs":"6ce2a72cd61e3d87715dafb396d8e6ea4189a3e7dcb84d4188657a477b67b1e6"},"package":"c40218275f081c4493f190357c5395647b06734c2dc3dcb41cc099a0f60168b1"}
\ No newline at end of file diff --git a/vendor/icu_list/Cargo.lock b/vendor/icu_list/Cargo.lock new file mode 100644 index 000000000..8d049ce78 --- /dev/null +++ b/vendor/icu_list/Cargo.lock @@ -0,0 +1,1064 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" +dependencies = [ + "memchr", +] + +[[package]] +name = "atomic-polyfill" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c041a8d9751a520ee19656232a18971f18946a7900f1520ee4400002244dd89" +dependencies = [ + "critical-section", +] + +[[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 = "bare-metal" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" +dependencies = [ + "rustc_version 0.2.3", +] + +[[package]] +name = "bare-metal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603" + +[[package]] +name = "bit_field" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4" + +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" + +[[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 0.1.10", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[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 = "cobs" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" + +[[package]] +name = "cortex-m" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70858629a458fdfd39f9675c4dc309411f2a3f83bede76988d81bf1a0ecee9e0" +dependencies = [ + "bare-metal 0.2.5", + "bitfield", + "embedded-hal", + "volatile-register", +] + +[[package]] +name = "criterion" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" +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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "critical-section" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95da181745b56d4bd339530ec393508910c909c784e8962d15d722bacf0bcbcd" +dependencies = [ + "bare-metal 1.0.0", + "cfg-if", + "cortex-m", + "riscv", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "once_cell", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[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 = "databake" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87777d6d7bde863ba217aa87521dc857239de1f36d66aac46fd173fb0495858" +dependencies = [ + "databake-derive", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "databake-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "905c7a060fc0c84c0452d97473b1177dd7a5cbc7670cfbae4a7fe22e42f6432e" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "deduplicating_array" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7f0807b2feeeda87369e8b4cf467f250f39841c8f9427bf3a972b878588937" +dependencies = [ + "serde", +] + +[[package]] +name = "displaydoc" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "either" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" + +[[package]] +name = "embedded-hal" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" +dependencies = [ + "nb 0.1.3", + "void", +] + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + +[[package]] +name = "heapless" +version = "0.7.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743" +dependencies = [ + "atomic-polyfill", + "hash32", + "rustc_version 0.4.0", + "serde", + "spin", + "stable_deref_trait", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "icu_benchmark_macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c867656f2d9c90b13709ac88e710a9d6afe33998c1dfa22384bab8804e8b3d4" + +[[package]] +name = "icu_list" +version = "1.0.0" +dependencies = [ + "criterion", + "databake", + "deduplicating_array", + "displaydoc", + "icu_benchmark_macros", + "icu_locid", + "icu_provider", + "postcard", + "regex-automata 0.2.0", + "serde", + "serde_json", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34b3de5d99a0e275fe6193b9586dbf37364daebc0d39c89b5cf8376a53b789e8" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", +] + +[[package]] +name = "icu_provider" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629bc2b6591ed9e4467d8a0fa2a597b70cff64ff8170e54a3f0f3257b99873f" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "serde", + "stable_deref_trait", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38cf6f5b65cf81f0b4298da647101acbfe6ae0e25263f92bd7a22597e9d6d606" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" + +[[package]] +name = "js-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.133" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f80d65747a3e43d1596c7c5492d95d5edddaabd45a7fcdb02b95f644164966" + +[[package]] +name = "litemap" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f34a3f4798fac63fb48cf277eefa38f94d3443baff555bb98e4f56bc9092368e" + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.0.0", +] + +[[package]] +name = "nb" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +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 = "once_cell" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" + +[[package]] +name = "plotters-svg" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "postcard" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c2b180dc0bade59f03fd005cb967d3f1e5f69b13922dad0cd6e047cb8af2363" +dependencies = [ + "cobs", + "heapless", + "serde", +] + +[[package]] +name = "proc-macro2" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd7356a8122b6c4a24a82b278680c73357984ca2fc79a0f9fa6dea7dced7c58" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rayon" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "regex" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" +dependencies = [ + "aho-corasick", + "memchr", + "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-automata" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9368763f5a9b804326f3af749e16f9abf378d227bcdee7634b13d8f17793782" +dependencies = [ + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" + +[[package]] +name = "riscv" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6907ccdd7a31012b70faf2af85cd9e5ba97657cc3987c4f13f8e4d2c2a088aba" +dependencies = [ + "bare-metal 1.0.0", + "bit_field", + "riscv-target", +] + +[[package]] +name = "riscv-target" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88aa938cda42a0cf62a20cfe8d139ff1af20c2e681212b5b34adb5a58333f222" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.14", +] + +[[package]] +name = "ryu" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" +dependencies = [ + "serde_derive", +] + +[[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.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" +dependencies = [ + "itoa 1.0.3", + "ryu", + "serde", +] + +[[package]] +name = "spin" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09" +dependencies = [ + "lock_api", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "syn" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "tinystr" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8aeafdfd935e4a7fe16a91ab711fa52d54df84f9c8f7ca5837a9d1d902ef4c2" +dependencies = [ + "displaydoc", +] + +[[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-ident" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "vcell" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "volatile-register" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ee8f19f9d74293faf70901bc20ad067dc1ad390d2cbf1e3f75f721ffee908b6" +dependencies = [ + "vcell", +] + +[[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 = "wasm-bindgen" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" + +[[package]] +name = "web-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +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" + +[[package]] +name = "writeable" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8e6ab4f5da1b24daf2c590cfac801bacb27b15b4f050e84eb60149ea726f06b" + +[[package]] +name = "yoke" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fe1d55ca72c32d573bfbd5cb2f0ca65a497854c44762957a6d3da96041a5184" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c2c5bb7c929b85c1b9ec69091b0d835f0878b4fd9eb67973b25936e06c4374" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79e9355fccf72b04b7deaa99ce7a0f6630530acf34045391b74460fcd714de54" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8785f47d6062c1932866147f91297286a9f350b3070e9d9f0b6078e37d623c1a" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d919a74c17749ccb17beaf6405562e413cd94e98ba52ca1e64bbe7eefbd8b8" +dependencies = [ + "serde", + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490e5f878c2856225e884c35927e7ea6db3c24cdb7229b72542c7526ad7ed49e" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] diff --git a/vendor/icu_list/Cargo.toml b/vendor/icu_list/Cargo.toml new file mode 100644 index 000000000..805f2aea4 --- /dev/null +++ b/vendor/icu_list/Cargo.toml @@ -0,0 +1,114 @@ +# 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 = "icu_list" +version = "1.0.0" +authors = ["The ICU4X Project Developers"] +include = [ + "src/**/*", + "examples/**/*", + "benches/**/*", + "tests/**/*", + "Cargo.toml", + "LICENSE", + "README.md", +] +description = "ECMA-402 ListFormatter" +readme = "README.md" +categories = ["internationalization"] +license = "Unicode-DFS-2016" +repository = "https://github.com/unicode-org/icu4x" +resolver = "2" + +[lib] +path = "src/lib.rs" + +[[example]] +name = "and_list" + +[dependencies.databake] +version = "0.1.0" +features = ["derive"] +optional = true + +[dependencies.deduplicating_array] +version = "0.1" +optional = true + +[dependencies.displaydoc] +version = "0.2.3" +default-features = false + +[dependencies.icu_locid] +version = "1.0.0" + +[dependencies.icu_provider] +version = "1.0.0" +features = ["macros"] + +[dependencies.regex-automata] +version = "0.2" +default-features = false + +[dependencies.serde] +version = "1.0" +features = [ + "derive", + "alloc", +] +optional = true +default-features = false + +[dependencies.writeable] +version = "0.5" + +[dependencies.zerovec] +version = "0.9" +features = ["yoke"] + +[dev-dependencies.criterion] +version = "0.3.3" + +[dev-dependencies.icu_benchmark_macros] +version = "0.7" + +[dev-dependencies.postcard] +version = "1.0.0" +features = ["use-std"] + +[dev-dependencies.serde_json] +version = "1" + +[features] +bench = [] +datagen = [ + "serde", + "std", + "databake", +] +serde = [ + "dep:serde", + "icu_provider/serde", + "zerovec/serde", + "deduplicating_array", +] +serde_human = [ + "serde", + "regex-automata/alloc", +] +std = [ + "icu_provider/std", + "icu_locid/std", + "regex-automata/std", + "regex-automata/alloc", +] diff --git a/vendor/icu_list/LICENSE b/vendor/icu_list/LICENSE new file mode 100644 index 000000000..9858d01ab --- /dev/null +++ b/vendor/icu_list/LICENSE @@ -0,0 +1,51 @@ +UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE + +See Terms of Use <https://www.unicode.org/copyright.html> +for definitions of Unicode Inc.’s Data Files and Software. + +NOTICE TO USER: Carefully read the following legal agreement. +BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S +DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), +YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +TERMS AND CONDITIONS OF THIS AGREEMENT. +IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE +THE DATA FILES OR SOFTWARE. + +COPYRIGHT AND PERMISSION NOTICE + +Copyright © 1991-2022 Unicode, Inc. All rights reserved. +Distributed under the Terms of Use in https://www.unicode.org/copyright.html. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Unicode data files and any associated documentation +(the "Data Files") or Unicode software and any associated documentation +(the "Software") to deal in the Data Files or Software +without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, and/or sell copies of +the Data Files or Software, and to permit persons to whom the Data Files +or Software are furnished to do so, provided that either +(a) this copyright and permission notice appear with all copies +of the Data Files or Software, or +(b) this copyright and permission notice appear in associated +Documentation. + +THE DATA FILES AND SOFTWARE ARE 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 OF THIRD PARTY RIGHTS. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS +NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL +DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THE DATA FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in these Data Files or Software without prior +written authorization of the copyright holder. + +— + +Portions of ICU4X may have been adapted from ICU4C and/or ICU4J. +ICU 1.8.1 to ICU 57.1 © 1995-2016 International Business Machines Corporation and others. diff --git a/vendor/icu_list/README.md b/vendor/icu_list/README.md new file mode 100644 index 000000000..d17e8a8d7 --- /dev/null +++ b/vendor/icu_list/README.md @@ -0,0 +1,69 @@ +# icu_list [![crates.io](https://img.shields.io/crates/v/icu_list)](https://crates.io/crates/icu_list) + +Formatting lists in a locale-sensitive way. + +This module is published as its own crate ([`icu_list`](https://docs.rs/icu_list/latest/icu_list/)) +and as part of the [`icu`](https://docs.rs/icu/latest/icu/) crate. See the latter for more details on the ICU4X project. + +## Examples + +### Formatting *and* lists in Spanish + +```rust +# +let list_formatter = ListFormatter::try_new_and_with_length_unstable( + &icu_testdata::unstable(), + &locale!("es").into(), + ListLength::Wide, +) +.expect("Data should load successfully"); + +assert_writeable_eq!( + list_formatter.format(["España", "Suiza"].iter()), + "España y Suiza", +); + +// The Spanish 'y' sometimes becomes an 'e': +assert_writeable_eq!( + list_formatter.format(["España", "Suiza", "Italia"].iter()), + "España, Suiza e Italia", +); +``` + +### Formatting *or* lists in Thai + +```rust +# +let list_formatter = ListFormatter::try_new_or_with_length_unstable( + &icu_testdata::unstable(), + &locale!("th").into(), + ListLength::Short, +) +.expect("Data should load successfully"); + +// We can use any Writeables as inputs +assert_writeable_eq!(list_formatter.format(1..=3), "1, 2 หรือ 3",); +``` + +### Formatting unit lists in English + +```rust +# +let list_formatter = ListFormatter::try_new_unit_with_length_unstable( + &icu_testdata::unstable(), + &locale!("en").into(), + ListLength::Wide, +) +.expect("Data should load successfully"); + +assert_writeable_eq!( + list_formatter.format(["1ft", "2in"].iter()), + "1ft, 2in", +); +``` +Note: this last example is not fully internationalized. See [icu4x/2192](https://github.com/unicode-org/icu4x/issues/2192) +for full unit handling. + +## More Information + +For more information on development, authorship, contributing etc. please visit [`ICU4X home page`](https://github.com/unicode-org/icu4x). diff --git a/vendor/icu_list/examples/and_list.rs b/vendor/icu_list/examples/and_list.rs new file mode 100644 index 000000000..9d869d9fb --- /dev/null +++ b/vendor/icu_list/examples/and_list.rs @@ -0,0 +1,29 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +#![no_main] // https://github.com/unicode-org/icu4x/issues/395 + +icu_benchmark_macros::static_setup!(); + +use icu_list::{ListFormatter, ListLength}; +use icu_locid::locale; + +#[no_mangle] +fn main(_argc: isize, _argv: *const *const u8) -> isize { + icu_benchmark_macros::main_setup!(); + + let list_formatter = ListFormatter::try_new_and_with_length_unstable( + &icu_testdata::unstable(), + &locale!("es").into(), + ListLength::Wide, + ) + .unwrap(); + + println!( + "{}", + list_formatter.format(["España", "Francia", "Suiza", "Italia"].iter()) + ); + + 0 +} diff --git a/vendor/icu_list/src/error.rs b/vendor/icu_list/src/error.rs new file mode 100644 index 000000000..d8622b03a --- /dev/null +++ b/vendor/icu_list/src/error.rs @@ -0,0 +1,27 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +use core::fmt::Debug; +use displaydoc::Display; +use icu_provider::prelude::DataError; + +#[cfg(feature = "std")] +impl std::error::Error for ListError {} + +/// A list of error outcomes for various operations in the `icu_timezone` crate. +/// +/// Re-exported as [`Error`](crate::Error). +#[derive(Display, Debug, Copy, Clone, PartialEq)] +#[non_exhaustive] +pub enum ListError { + /// An error originating inside of the [data provider](icu_provider). + #[displaydoc("{0}")] + Data(DataError), +} + +impl From<DataError> for ListError { + fn from(e: DataError) -> Self { + Self::Data(e) + } +} diff --git a/vendor/icu_list/src/lib.rs b/vendor/icu_list/src/lib.rs new file mode 100644 index 000000000..18f2156a6 --- /dev/null +++ b/vendor/icu_list/src/lib.rs @@ -0,0 +1,122 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +//! Formatting lists in a locale-sensitive way. +//! +//! This module is published as its own crate ([`icu_list`](https://docs.rs/icu_list/latest/icu_list/)) +//! and as part of the [`icu`](https://docs.rs/icu/latest/icu/) crate. See the latter for more details on the ICU4X project. +//! +//! # Examples +//! +//! ## Formatting *and* lists in Spanish +//! +//! ``` +//! # use icu::list::{ListFormatter, ListLength}; +//! # use icu::locid::locale; +//! # use writeable::*; +//! # +//! let list_formatter = ListFormatter::try_new_and_with_length_unstable( +//! &icu_testdata::unstable(), +//! &locale!("es").into(), +//! ListLength::Wide, +//! ) +//! .expect("Data should load successfully"); +//! +//! assert_writeable_eq!( +//! list_formatter.format(["España", "Suiza"].iter()), +//! "España y Suiza", +//! ); +//! +//! // The Spanish 'y' sometimes becomes an 'e': +//! assert_writeable_eq!( +//! list_formatter.format(["España", "Suiza", "Italia"].iter()), +//! "España, Suiza e Italia", +//! ); +//! ``` +//! +//! ## Formatting *or* lists in Thai +//! +//! ``` +//! # use icu::list::{ListFormatter, ListLength}; +//! # use icu::locid::locale; +//! # use writeable::*; +//! # +//! let list_formatter = ListFormatter::try_new_or_with_length_unstable( +//! &icu_testdata::unstable(), +//! &locale!("th").into(), +//! ListLength::Short, +//! ) +//! .expect("Data should load successfully"); +//! +//! // We can use any Writeables as inputs +//! assert_writeable_eq!(list_formatter.format(1..=3), "1, 2 หรือ 3",); +//! ``` +//! +//! ## Formatting unit lists in English +//! +//! ``` +//! # use icu::list::{ListFormatter, ListLength}; +//! # use icu::locid::locale; +//! # use writeable::*; +//! # +//! let list_formatter = ListFormatter::try_new_unit_with_length_unstable( +//! &icu_testdata::unstable(), +//! &locale!("en").into(), +//! ListLength::Wide, +//! ) +//! .expect("Data should load successfully"); +//! +//! assert_writeable_eq!( +//! list_formatter.format(["1ft", "2in"].iter()), +//! "1ft, 2in", +//! ); +//! ``` +//! Note: this last example is not fully internationalized. See [icu4x/2192](https://github.com/unicode-org/icu4x/issues/2192) +//! for full unit handling. + +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr( + not(test), + deny( + clippy::indexing_slicing, + clippy::unwrap_used, + clippy::expect_used, + clippy::panic, + clippy::exhaustive_structs, + clippy::exhaustive_enums, + // TODO(#2266): enable missing_debug_implementations, + ) +)] +#![warn(missing_docs)] + +extern crate alloc; + +mod error; +mod list_formatter; +mod string_matcher; + +pub mod provider; + +pub use list_formatter::*; + +pub use error::ListError; + +#[doc(inline)] +pub use ListError as Error; + +/// Represents the style of a list. See the +/// [CLDR spec](https://unicode.org/reports/tr35/tr35-general.html#ListPatterns) +/// for an explanation of the different styles. +#[derive(Copy, Clone, PartialEq, Debug)] +#[non_exhaustive] +pub enum ListLength { + /// A typical list + Wide, + /// A shorter list + Short, + /// The shortest type of list + Narrow, + // *Important*: When adding a variant here, make sure the code in + // ListFormatterPatterns::{start, middle, end, pair} stays panic-free! +} diff --git a/vendor/icu_list/src/list_formatter.rs b/vendor/icu_list/src/list_formatter.rs new file mode 100644 index 000000000..36f5fbb7b --- /dev/null +++ b/vendor/icu_list/src/list_formatter.rs @@ -0,0 +1,319 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +use crate::provider::{AndListV1Marker, ErasedListV1Marker, OrListV1Marker, UnitListV1Marker}; +use crate::ListError; +use crate::ListLength; +use core::fmt::{self, Write}; +use icu_provider::prelude::*; +use writeable::*; + +/// A formatter that renders sequences of items in an i18n-friendly way. See the +/// [crate-level documentation](crate) for more details. +pub struct ListFormatter { + data: DataPayload<ErasedListV1Marker>, + length: ListLength, +} + +macro_rules! constructor { + ($name: ident, $name_any: ident, $name_buffer: ident, $marker: ty, $doc: literal) => { + #[doc = concat!("Creates a new [`ListFormatter`] that produces a ", $doc, "-type list.\n\nSee the [CLDR spec]", + "(https://unicode.org/reports/tr35/tr35-general.html#ListPatterns) for an explanation of the different types.\n\n", + "[📚 Help choosing a constructor](icu_provider::constructors)\n\n", + "<div class=\"stab unstable\">⚠️ The bounds on this function may change over time, including in SemVer minor releases.</div>")] + pub fn $name<D: DataProvider<$marker> + ?Sized>( + data_provider: &D, + locale: &DataLocale, + length: ListLength, + ) -> Result<Self, ListError> { + let data = data_provider + .load(DataRequest { + locale, + metadata: Default::default(), + })? + .take_payload()?.cast(); + Ok(Self { data, length }) + } + icu_provider::gen_any_buffer_constructors!( + locale: include, + style: ListLength, + error: ListError, + functions: [ + Self::$name, + $name_any, + $name_buffer + ] + ); + }; +} + +impl ListFormatter { + constructor!( + try_new_and_with_length_unstable, + try_new_and_with_length_with_any_provider, + try_new_and_with_length_with_buffer_provider, + AndListV1Marker, + "and" + ); + constructor!( + try_new_or_with_length_unstable, + try_new_or_with_length_with_any_provider, + try_new_or_with_length_with_buffer_provider, + OrListV1Marker, + "or" + ); + constructor!( + try_new_unit_with_length_unstable, + try_new_unit_with_length_with_any_provider, + try_new_unit_with_length_with_buffer_provider, + UnitListV1Marker, + "unit" + ); + + /// Returns a [`Writeable`] composed of the input [`Writeable`]s and the language-dependent + /// formatting. The first layer of parts contains [`parts::ELEMENT`] for input + /// elements, and [`parts::LITERAL`] for list literals. + pub fn format<'a, W: Writeable + 'a, I: Iterator<Item = W> + Clone + 'a>( + &'a self, + values: I, + ) -> FormattedList<'a, W, I> { + FormattedList { + formatter: self, + values, + } + } + + /// Returns a [`String`] composed of the input [`Writeable`]s and the language-dependent + /// formatting. + pub fn format_to_string<W: Writeable, I: Iterator<Item = W> + Clone>( + &self, + values: I, + ) -> alloc::string::String { + self.format(values).write_to_string().into_owned() + } +} + +/// The [`Part`]s used by [`ListFormatter`]. +pub mod parts { + use writeable::Part; + + /// The [`Part`] used by [`FormattedList`](super::FormattedList) to mark the part of the string that is an element. + pub const ELEMENT: Part = Part { + category: "list", + value: "element", + }; + + /// The [`Part`] used by [`FormattedList`](super::FormattedList) to mark the part of the string that is a list literal, + /// such as ", " or " and ". + pub const LITERAL: Part = Part { + category: "list", + value: "literal", + }; +} + +/// The [`Writeable`] implementation that is returned by [`ListFormatter::format`]. See +/// the [`writeable`] crate for how to consume this. +pub struct FormattedList<'a, W: Writeable + 'a, I: Iterator<Item = W> + Clone + 'a> { + formatter: &'a ListFormatter, + values: I, +} + +impl<'a, W: Writeable + 'a, I: Iterator<Item = W> + Clone + 'a> Writeable + for FormattedList<'a, W, I> +{ + fn write_to_parts<V: PartsWrite + ?Sized>(&self, sink: &mut V) -> fmt::Result { + macro_rules! literal { + ($lit:ident) => { + sink.with_part(parts::LITERAL, |l| l.write_str($lit)) + }; + } + macro_rules! value { + ($val:expr) => { + sink.with_part(parts::ELEMENT, |e| $val.write_to_parts(e)) + }; + } + + let mut values = self.values.clone(); + + if let Some(first) = values.next() { + if let Some(second) = values.next() { + if let Some(third) = values.next() { + // Start(values[0], middle(..., middle(values[n-3], End(values[n-2], values[n-1]))...)) = + // start_before + values[0] + start_between + (values[1..n-3] + middle_between)* + + // values[n-2] + end_between + values[n-1] + end_after + + let (start_before, start_between, _) = self + .formatter + .data + .get() + .start(self.formatter.length) + .parts(&second); + + literal!(start_before)?; + value!(first)?; + literal!(start_between)?; + value!(second)?; + + let mut next = third; + + for next_next in values { + let (_, between, _) = self + .formatter + .data + .get() + .middle(self.formatter.length) + .parts(&next); + literal!(between)?; + value!(next)?; + next = next_next; + } + + let (_, end_between, end_after) = self + .formatter + .data + .get() + .end(self.formatter.length) + .parts(&next); + literal!(end_between)?; + value!(next)?; + literal!(end_after) + } else { + // Pair(values[0], values[1]) = pair_before + values[0] + pair_between + values[1] + pair_after + let (before, between, after) = self + .formatter + .data + .get() + .pair(self.formatter.length) + .parts(&second); + literal!(before)?; + value!(first)?; + literal!(between)?; + value!(second)?; + literal!(after) + } + } else { + value!(first) + } + } else { + Ok(()) + } + } + + fn writeable_length_hint(&self) -> LengthHint { + let mut count = 0; + let item_length = self + .values + .clone() + .map(|w| { + count += 1; + w.writeable_length_hint() + }) + .sum::<LengthHint>(); + item_length + + self + .formatter + .data + .get() + .size_hint(self.formatter.length, count) + } +} + +impl<'a, W: Writeable + 'a, I: Iterator<Item = W> + Clone + 'a> core::fmt::Display + for FormattedList<'a, W, I> +{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + self.write_to(f) + } +} + +#[cfg(all(test, feature = "datagen"))] +mod tests { + use super::*; + use writeable::{assert_writeable_eq, assert_writeable_parts_eq}; + + fn formatter(length: ListLength) -> ListFormatter { + ListFormatter { + data: DataPayload::from_owned(crate::provider::test::test_patterns()), + length, + } + } + + #[test] + fn test_slices() { + let formatter = formatter(ListLength::Wide); + let values = ["one", "two", "three", "four", "five"]; + + assert_writeable_eq!(formatter.format(values[0..0].iter()), ""); + assert_writeable_eq!(formatter.format(values[0..1].iter()), "one"); + assert_writeable_eq!(formatter.format(values[0..2].iter()), "$one;two+"); + assert_writeable_eq!(formatter.format(values[0..3].iter()), "@one:two.three!"); + assert_writeable_eq!( + formatter.format(values[0..4].iter()), + "@one:two,three.four!" + ); + + assert_writeable_parts_eq!( + formatter.format(values.iter()), + "@one:two,three,four.five!", + [ + (0, 1, parts::LITERAL), + (1, 4, parts::ELEMENT), + (4, 5, parts::LITERAL), + (5, 8, parts::ELEMENT), + (8, 9, parts::LITERAL), + (9, 14, parts::ELEMENT), + (14, 15, parts::LITERAL), + (15, 19, parts::ELEMENT), + (19, 20, parts::LITERAL), + (20, 24, parts::ELEMENT), + (24, 25, parts::LITERAL) + ] + ); + } + + #[test] + fn test_into_iterator() { + let formatter = formatter(ListLength::Wide); + + let mut vecdeque = std::collections::vec_deque::VecDeque::<u8>::new(); + vecdeque.push_back(10); + vecdeque.push_front(48); + + assert_writeable_parts_eq!( + formatter.format(vecdeque.iter()), + "$48;10+", + [ + (0, 1, parts::LITERAL), + (1, 3, parts::ELEMENT), + (3, 4, parts::LITERAL), + (4, 6, parts::ELEMENT), + (6, 7, parts::LITERAL), + ] + ); + } + + #[test] + fn test_iterator() { + let formatter = formatter(ListLength::Wide); + + assert_writeable_parts_eq!( + formatter.format(core::iter::repeat(5).take(2)), + "$5;5+", + [ + (0, 1, parts::LITERAL), + (1, 2, parts::ELEMENT), + (2, 3, parts::LITERAL), + (3, 4, parts::ELEMENT), + (4, 5, parts::LITERAL), + ] + ); + } + + #[test] + fn test_conditional() { + let formatter = formatter(ListLength::Narrow); + + assert_writeable_eq!(formatter.format(["Beta", "Alpha"].iter()), "Beta :o Alpha"); + } +} diff --git a/vendor/icu_list/src/provider.rs b/vendor/icu_list/src/provider.rs new file mode 100644 index 000000000..27f3e4fec --- /dev/null +++ b/vendor/icu_list/src/provider.rs @@ -0,0 +1,465 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +// Provider structs must be stable +#![allow(clippy::exhaustive_structs, clippy::exhaustive_enums)] + +//! Data provider struct definitions for this ICU4X component. +//! +//! Read more about data providers: [`icu_provider`] + +use crate::ListLength; +use alloc::borrow::Cow; +use icu_provider::DataMarker; +use icu_provider::{yoke, zerofrom}; +use writeable::{LengthHint, Writeable}; + +pub use crate::string_matcher::StringMatcher; + +/// Symbols and metadata required for [`ListFormatter`](crate::ListFormatter). +#[icu_provider::data_struct( + AndListV1Marker = "list/and@1", + OrListV1Marker = "list/or@1", + UnitListV1Marker = "list/unit@1" +)] +#[derive(Clone, Debug)] +#[cfg_attr( + feature = "datagen", + derive(serde::Serialize, databake::Bake), + databake(path = icu_list::provider), +)] +pub struct ListFormatterPatternsV1<'data>( + #[cfg_attr(feature = "datagen", serde(with = "deduplicating_array"))] + /// The patterns in the order start, middle, end, pair, short_start, short_middle, + /// short_end, short_pair, narrow_start, narrow_middle, narrow_end, narrow_pair, + pub [ConditionalListJoinerPattern<'data>; 12], +); + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for ListFormatterPatternsV1<'de> { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: serde::de::Deserializer<'de>, + { + #[cfg(not(feature = "serde_human"))] + if deserializer.is_human_readable() { + use serde::de::Error; + return Err(D::Error::custom( + "Deserializing human-readable ListFormatter data requires the 'serde_human' feature", + )); + } + + Ok(ListFormatterPatternsV1(deduplicating_array::deserialize( + deserializer, + )?)) + } +} + +pub(crate) struct ErasedListV1Marker; + +impl DataMarker for ErasedListV1Marker { + type Yokeable = ListFormatterPatternsV1<'static>; +} + +impl<'data> ListFormatterPatternsV1<'data> { + pub(crate) fn start(&self, style: ListLength) -> &ConditionalListJoinerPattern<'data> { + #![allow(clippy::indexing_slicing)] // style as usize < 3 + &self.0[4 * (style as usize)] + } + + pub(crate) fn middle(&self, style: ListLength) -> &ConditionalListJoinerPattern<'data> { + #![allow(clippy::indexing_slicing)] // style as usize < 3 + &self.0[4 * (style as usize) + 1] + } + + pub(crate) fn end(&self, style: ListLength) -> &ConditionalListJoinerPattern<'data> { + #![allow(clippy::indexing_slicing)] // style as usize < 3 + &self.0[4 * (style as usize) + 2] + } + + pub(crate) fn pair(&self, style: ListLength) -> &ConditionalListJoinerPattern<'data> { + #![allow(clippy::indexing_slicing)] // style as usize < 3 + &self.0[4 * (style as usize) + 3] + } + + /// The range of the number of bytes required by the list literals to join a + /// list of length `len`. If none of the patterns are conditional, this is exact. + pub(crate) fn size_hint(&self, style: ListLength, len: usize) -> LengthHint { + match len { + 0 | 1 => LengthHint::exact(0), + 2 => self.pair(style).size_hint(), + n => { + self.start(style).size_hint() + + self.middle(style).size_hint() * (n - 3) + + self.end(style).size_hint() + } + } + } +} + +/// A pattern that can behave conditionally on the next element. +#[derive(Clone, Debug, PartialEq, yoke::Yokeable, zerofrom::ZeroFrom)] +#[cfg_attr( + feature = "datagen", + derive(serde::Serialize, databake::Bake), + databake(path = icu_list::provider), +)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize))] +pub struct ConditionalListJoinerPattern<'data> { + /// The default pattern + #[cfg_attr(feature = "serde", serde(borrow))] + pub default: ListJoinerPattern<'data>, + /// And optional special case + #[cfg_attr(feature = "serde", serde(borrow))] + pub special_case: Option<SpecialCasePattern<'data>>, +} + +/// The special case of a [`ConditionalListJoinerPattern`] +#[derive(Clone, Debug, PartialEq, yoke::Yokeable, zerofrom::ZeroFrom)] +#[cfg_attr( + feature = "datagen", + derive(serde::Serialize, databake::Bake), + databake(path = icu_list::provider), +)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize))] +pub struct SpecialCasePattern<'data> { + /// The condition on the following element + #[cfg_attr(feature = "serde", serde(borrow))] + pub condition: StringMatcher<'data>, + /// The pattern if the condition matches + #[cfg_attr(feature = "serde", serde(borrow))] + pub pattern: ListJoinerPattern<'data>, +} + +/// A pattern containing two numeric placeholders ("{0}, and {1}.") +#[derive(Clone, Debug, PartialEq, yoke::Yokeable, zerofrom::ZeroFrom)] +#[cfg_attr(feature = "datagen", derive(serde::Serialize))] +pub struct ListJoinerPattern<'data> { + /// The pattern string without the placeholders + string: Cow<'data, str>, + /// The index of the first placeholder. Always <= index_1. + // Always 0 for CLDR data, so we don't need to serialize it. + // In-memory we have free space for it as index_1 doesn't + // fill a word. + #[cfg_attr(feature = "datagen", serde(skip))] + index_0: u8, + /// The index of the second placeholder. Always < string.len(). + index_1: u8, +} + +#[cfg(feature = "serde")] +impl<'de: 'data, 'data> serde::Deserialize<'de> for ListJoinerPattern<'data> { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: serde::Deserializer<'de>, + { + #[derive(serde::Deserialize)] + struct Dummy<'data> { + #[cfg_attr(feature = "serde", serde(borrow))] + string: Cow<'data, str>, + index_1: u8, + } + let Dummy { string, index_1 } = Dummy::deserialize(deserializer)?; + + if index_1 as usize > string.len() { + use serde::de::Error; + Err(D::Error::custom("invalid index_1")) + } else { + Ok(ListJoinerPattern { + string, + index_0: 0, + index_1, + }) + } + } +} + +impl<'a> ListJoinerPattern<'a> { + /// Constructs a [`ListJoinerPattern`] from raw parts. Used by databake. + /// + /// # Safety + /// index_1 may be at most string.len() + pub const unsafe fn from_parts_unchecked(string: &'a str, index_1: u8) -> Self { + Self { + string: Cow::Borrowed(string), + index_0: 0, + index_1, + } + } +} + +pub(crate) type PatternParts<'a> = (&'a str, &'a str, &'a str); + +impl<'a> ConditionalListJoinerPattern<'a> { + pub(crate) fn parts<'b, W: Writeable + ?Sized>( + &'a self, + following_value: &'b W, + ) -> PatternParts<'a> { + match &self.special_case { + Some(SpecialCasePattern { condition, pattern }) + // TODO: Implement lookahead instead of materializing here. + if condition.test(&*following_value.write_to_string()) => + { + pattern.borrow_tuple() + } + _ => self.default.borrow_tuple(), + } + } + + /// The expected length of this pattern + pub fn size_hint(&'a self) -> LengthHint { + let mut hint = self.default.size_hint(); + if let Some(special_case) = &self.special_case { + hint |= special_case.pattern.size_hint() + } + hint + } +} + +impl<'data> ListJoinerPattern<'data> { + fn borrow_tuple(&'data self) -> PatternParts<'data> { + #![allow(clippy::indexing_slicing)] // by invariant + let index_0 = self.index_0 as usize; + let index_1 = self.index_1 as usize; + ( + &self.string[0..index_0], + &self.string[index_0..index_1], + &self.string[index_1..], + ) + } + + fn size_hint(&self) -> LengthHint { + LengthHint::exact(self.string.len()) + } +} + +#[cfg(feature = "datagen")] +mod datagen { + #![allow(clippy::indexing_slicing)] // datagen + + use super::*; + use icu_provider::DataError; + + impl<'data> ListFormatterPatternsV1<'data> { + /// The patterns in the order start, middle, end, pair, short_start, short_middle, + /// short_end, short_pair, narrow_start, narrow_middle, narrow_end, narrow_pair, + pub fn try_new(patterns: [&str; 12]) -> Result<Self, DataError> { + Ok(Self([ + ListJoinerPattern::from_str(patterns[0], true, false)?.into(), + ListJoinerPattern::from_str(patterns[1], false, false)?.into(), + ListJoinerPattern::from_str(patterns[2], false, true)?.into(), + ListJoinerPattern::from_str(patterns[3], true, true)?.into(), + ListJoinerPattern::from_str(patterns[4], true, false)?.into(), + ListJoinerPattern::from_str(patterns[5], false, false)?.into(), + ListJoinerPattern::from_str(patterns[6], false, true)?.into(), + ListJoinerPattern::from_str(patterns[7], true, true)?.into(), + ListJoinerPattern::from_str(patterns[8], true, false)?.into(), + ListJoinerPattern::from_str(patterns[9], false, false)?.into(), + ListJoinerPattern::from_str(patterns[10], false, true)?.into(), + ListJoinerPattern::from_str(patterns[11], true, true)?.into(), + ])) + } + + /// Adds a special case to all `pattern`s that will evaluate to + /// `alternative_pattern` when `regex` matches the following element. + /// The regex is interpreted case-insensitive and anchored to the beginning, but + /// to improve efficiency does not search for full matches. If a full match is + /// required, use `$`. + pub fn make_conditional( + &mut self, + pattern: &str, + regex: &StringMatcher<'static>, + alternative_pattern: &str, + ) -> Result<(), DataError> { + let old = ListJoinerPattern::from_str(pattern, true, true)?; + for i in 0..12 { + if self.0[i].default == old { + self.0[i].special_case = Some(SpecialCasePattern { + condition: regex.clone(), + pattern: ListJoinerPattern::from_str( + alternative_pattern, + i % 4 == 0 || i % 4 == 3, // allow_prefix = start or pair + i % 4 == 2 || i % 4 == 3, // allow_suffix = end or pair + )?, + }); + } + } + Ok(()) + } + } + + impl<'data> ListJoinerPattern<'data> { + /// Construct the pattern from a CLDR pattern string + pub fn from_str( + pattern: &str, + allow_prefix: bool, + allow_suffix: bool, + ) -> Result<Self, DataError> { + match (pattern.find("{0}"), pattern.find("{1}")) { + (Some(index_0), Some(index_1)) + if index_0 < index_1 + && (allow_prefix || index_0 == 0) + && (allow_suffix || index_1 == pattern.len() - 3) => + { + if (index_0 > 0 && !cfg!(test)) || index_1 - 3 >= 256 { + return Err(DataError::custom( + "Found valid pattern that cannot be stored in ListFormatterPatternsV1", + ) + .with_debug_context(pattern)); + } + Ok(ListJoinerPattern { + string: Cow::Owned(alloc::format!( + "{}{}{}", + &pattern[0..index_0], + &pattern[index_0 + 3..index_1], + &pattern[index_1 + 3..] + )), + index_0: index_0 as u8, + index_1: (index_1 - 3) as u8, + }) + } + _ => Err(DataError::custom("Invalid list pattern").with_debug_context(pattern)), + } + } + } + + impl<'data> From<ListJoinerPattern<'data>> for ConditionalListJoinerPattern<'data> { + fn from(default: ListJoinerPattern<'data>) -> Self { + Self { + default, + special_case: None, + } + } + } + + impl databake::Bake for ListJoinerPattern<'_> { + fn bake(&self, env: &databake::CrateEnv) -> databake::TokenStream { + env.insert("icu_list"); + let string = (&*self.string).bake(env); + let index_1 = self.index_1.bake(env); + // Safe because our own data is safe + databake::quote! { unsafe { + ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(#string, #index_1) + }} + } + } +} + +#[cfg(all(test, feature = "datagen"))] +pub(crate) mod test { + use super::*; + + pub fn test_patterns() -> ListFormatterPatternsV1<'static> { + let mut patterns = ListFormatterPatternsV1::try_new([ + // Wide: general + "@{0}:{1}", + "{0},{1}", + "{0}.{1}!", + "${0};{1}+", + // Short: different pattern lengths + "{0}1{1}", + "{0}12{1}", + "{0}12{1}34", + "{0}123{1}456", + // Narrow: conditionals + "{0}: {1}", + "{0}, {1}", + "{0}. {1}", + "{0}. {1}", + ]) + .unwrap(); + patterns + .make_conditional("{0}. {1}", &StringMatcher::new("A").unwrap(), "{0} :o {1}") + .unwrap(); + patterns + } + + #[test] + fn rejects_bad_patterns() { + assert!(ListJoinerPattern::from_str("{0} and", true, true).is_err()); + assert!(ListJoinerPattern::from_str("and {1}", true, true).is_err()); + assert!(ListJoinerPattern::from_str("{1} and {0}", true, true).is_err()); + assert!(ListJoinerPattern::from_str("{1{0}}", true, true).is_err()); + assert!(ListJoinerPattern::from_str("{0\u{202e}} and {1}", true, true).is_err()); + assert!(ListJoinerPattern::from_str("{{0}} {{1}}", true, true).is_ok()); + + assert!(ListJoinerPattern::from_str("{0} and {1} ", true, true).is_ok()); + assert!(ListJoinerPattern::from_str("{0} and {1} ", true, false).is_err()); + assert!(ListJoinerPattern::from_str(" {0} and {1}", true, true).is_ok()); + assert!(ListJoinerPattern::from_str(" {0} and {1}", false, true).is_err()); + } + + #[test] + fn produces_correct_parts() { + assert_eq!( + test_patterns().pair(ListLength::Wide).parts(""), + ("$", ";", "+") + ); + } + + #[test] + fn produces_correct_parts_conditionally() { + assert_eq!( + test_patterns().end(ListLength::Narrow).parts("A"), + ("", " :o ", "") + ); + assert_eq!( + test_patterns().end(ListLength::Narrow).parts("a"), + ("", " :o ", "") + ); + assert_eq!( + test_patterns().end(ListLength::Narrow).parts("ab"), + ("", " :o ", "") + ); + assert_eq!( + test_patterns().end(ListLength::Narrow).parts("B"), + ("", ". ", "") + ); + assert_eq!( + test_patterns().end(ListLength::Narrow).parts("BA"), + ("", ". ", "") + ); + } + + #[test] + fn size_hint_works() { + let pattern = test_patterns(); + + assert_eq!( + pattern.size_hint(ListLength::Short, 0), + LengthHint::exact(0) + ); + assert_eq!( + pattern.size_hint(ListLength::Short, 1), + LengthHint::exact(0) + ); + + // pair pattern "{0}123{1}456" + assert_eq!( + pattern.size_hint(ListLength::Short, 2), + LengthHint::exact(6) + ); + + // patterns "{0}1{1}", "{0}12{1}" (x197), and "{0}12{1}34" + assert_eq!( + pattern.size_hint(ListLength::Short, 200), + LengthHint::exact(1 + 2 * 197 + 4) + ); + + // patterns "{0}: {1}", "{0}, {1}" (x197), and "{0} :o {1}" or "{0}. {1}" + assert_eq!( + pattern.size_hint(ListLength::Narrow, 200), + LengthHint::exact(2 + 197 * 2) + LengthHint::between(2, 4) + ); + } + + #[test] + fn databake() { + databake::test_bake!( + ListJoinerPattern, + const: unsafe { crate::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8) }, + icu_list + ); + } +} diff --git a/vendor/icu_list/src/string_matcher.rs b/vendor/icu_list/src/string_matcher.rs new file mode 100644 index 000000000..ba4833605 --- /dev/null +++ b/vendor/icu_list/src/string_matcher.rs @@ -0,0 +1,213 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +use alloc::borrow::Cow; +#[cfg(any(feature = "serde_human", feature = "datagen"))] +use alloc::string::ToString; +use icu_provider::{yoke, zerofrom}; +use regex_automata::dfa::sparse::DFA; +use regex_automata::dfa::Automaton; + +/// A precompiled regex +#[derive(Clone, Debug, yoke::Yokeable, zerofrom::ZeroFrom)] +#[allow(clippy::exhaustive_structs)] // not a public API +pub struct StringMatcher<'data> { + // Safety: These always represent a valid DFA (DFA::from_bytes(dfa_bytes).is_ok()) + dfa_bytes: Cow<'data, [u8]>, + pattern: Option<Cow<'data, str>>, +} + +impl PartialEq for StringMatcher<'_> { + fn eq(&self, other: &Self) -> bool { + self.dfa_bytes == other.dfa_bytes + } +} + +#[cfg(feature = "datagen")] +impl databake::Bake for StringMatcher<'_> { + fn bake(&self, env: &databake::CrateEnv) -> databake::TokenStream { + env.insert("icu_list"); + let bytes = (&&*self.dfa_bytes).bake(env); + // Safe because our own data is safe + databake::quote! { + unsafe { ::icu_list::provider::StringMatcher::from_dfa_bytes_unchecked(#bytes) } + } + } +} + +#[cfg(feature = "datagen")] +impl serde::Serialize for StringMatcher<'_> { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::ser::Serializer, + { + if serializer.is_human_readable() { + self.pattern + .as_ref() + .map(|pattern| pattern.serialize(serializer)) + .unwrap_or_else(|| { + use serde::ser::Error; + Err(S::Error::custom( + "cannot serialize a deserialized bincode StringMatcher to JSON", + )) + }) + } else { + self.dfa_bytes.serialize(serializer) + } + } +} + +#[cfg(feature = "serde")] +impl<'de: 'data, 'data> serde::Deserialize<'de> for StringMatcher<'data> { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: serde::de::Deserializer<'de>, + { + use icu_provider::serde::borrow_de_utils::CowBytesWrap; + + #[cfg(feature = "serde_human")] + if deserializer.is_human_readable() { + use serde::de::Error; + return StringMatcher::new(<&str>::deserialize(deserializer)?) + .map_err(|e| D::Error::custom(e.to_string())); + } + + if cfg!(target_endian = "big") { + // TODO: Convert LE to BE. For now we just behave like the + // accept-nothing DFA on BE systems. + return Ok(StringMatcher { + dfa_bytes: Cow::Borrowed(&[]), + pattern: None, + }); + } + + let dfa_bytes = <CowBytesWrap<'de>>::deserialize(deserializer)?.0; + + // Verify safety invariant + DFA::from_bytes(&dfa_bytes).map_err(|e| { + use serde::de::Error; + D::Error::custom(alloc::format!("Invalid DFA bytes: {}", e)) + })?; + + Ok(StringMatcher { + dfa_bytes, + pattern: None, + }) + } +} + +impl<'data> StringMatcher<'data> { + /// Creates a `StringMatcher` from a serialized DFA. Used internally by databake. + /// + /// # Safety + /// + /// `dfa_bytes` has to be a valid DFA (regex_automata::dfa::sparse::DFA::from_bytes(dfa_bytes).is_ok()) + pub const unsafe fn from_dfa_bytes_unchecked(dfa_bytes: &'data [u8]) -> Self { + Self { + dfa_bytes: Cow::Borrowed(dfa_bytes), + pattern: None, + } + } + + /// Creates a `StringMatcher` from regex. + #[cfg(any(feature = "datagen", feature = "serde_human",))] + pub fn new(pattern: &str) -> Result<Self, icu_provider::DataError> { + use regex_automata::{ + dfa::dense::{Builder, Config}, + SyntaxConfig, + }; + + let mut builder = Builder::new(); + let dfa = builder + .syntax(SyntaxConfig::new().case_insensitive(true)) + .configure(Config::new().anchored(true).minimize(true)) + .build(pattern) + .map_err(|_| { + icu_provider::DataError::custom("Cannot build DFA").with_display_context(&pattern) + })? + .to_sparse() + .map_err(|_| { + icu_provider::DataError::custom("Cannot sparsify DFA") + .with_display_context(&pattern) + })?; + + Ok(Self { + dfa_bytes: dfa.to_bytes_little_endian().into(), + pattern: Some(pattern.to_string().into()), + }) + } + + #[allow(clippy::unwrap_used)] // by invariant + pub(crate) fn test(&self, string: &str) -> bool { + cfg!(target_endian = "little") + && matches!( + // Safe due to struct invariant. + unsafe { DFA::from_bytes_unchecked(&self.dfa_bytes).unwrap().0 } + .find_earliest_fwd(string.as_bytes()), + Ok(Some(_)) + ) + } +} + +#[cfg(all(test, feature = "datagen"))] +mod test { + use super::*; + + #[test] + fn test_string_matcher() { + let matcher = StringMatcher::new("abc.*").unwrap(); + assert!(!matcher.test("ab")); + assert!(matcher.test("abc")); + assert!(matcher.test("abcde")); + } + + #[test] + fn test_postcard_serialization() { + let matcher = StringMatcher::new("abc*").unwrap(); + + let mut bytes = postcard::to_stdvec(&matcher).unwrap(); + assert_eq!( + postcard::from_bytes::<StringMatcher>(&bytes).unwrap(), + matcher + ); + + // A corrupted byte leads to an error + bytes[17] ^= 255; + assert!(postcard::from_bytes::<StringMatcher>(&bytes).is_err()); + bytes[17] ^= 255; + + // An extra byte leads to an error + bytes.insert(123, 40); + assert!(postcard::from_bytes::<StringMatcher>(&bytes).is_err()); + bytes.remove(123); + + // Missing bytes lead to an error + assert!(postcard::from_bytes::<StringMatcher>(&bytes[0..bytes.len() - 5]).is_err()); + } + + #[test] + #[cfg(feature = "serde_human")] + fn test_json_serialization() { + let matcher = StringMatcher::new("abc*").unwrap(); + + let json = serde_json::to_string(&matcher).unwrap(); + assert_eq!( + serde_json::from_str::<StringMatcher>(&json).unwrap(), + matcher + ); + assert!(serde_json::from_str::<StringMatcher>(".*[").is_err()); + } + + #[test] + #[ignore] // https://github.com/rust-lang/rust/issues/98906 + fn databake() { + databake::test_bake!( + StringMatcher, + const: unsafe { + crate::provider::StringMatcher::from_dfa_bytes_unchecked(&[49u8, 50u8, 51u8, ]) + }, + icu_list + ); + } +} |