litemap-0.7.4/.cargo_vcs_info.json0000644000000001530000000000100124760ustar { "git": { "sha1": "6bd4893cc44c2ca2718de47a119a31cc40045fe5" }, "path_in_vcs": "utils/litemap" }litemap-0.7.4/Cargo.lock0000644000000574070000000000100104670ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "ahash" version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ "getrandom", "once_cell", "version_check", ] [[package]] name = "aho-corasick" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "anes" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstyle" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "autocfg" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "bincode" version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" dependencies = [ "serde", ] [[package]] name = "bitvec" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ "funty", "radium", "tap", "wyz", ] [[package]] name = "bumpalo" version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d32a994c2b3ca201d9b263612a374263f05e7adde37c4707f693dcd375076d1f" [[package]] name = "bytecheck" version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" dependencies = [ "bytecheck_derive", "ptr_meta", "simdutf8", ] [[package]] name = "bytecheck_derive" version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" dependencies = [ "proc-macro2", "quote", "syn 1.0.109", ] [[package]] name = "bytes" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[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 = "ciborium" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" dependencies = [ "ciborium-io", "ciborium-ll", "serde", ] [[package]] name = "ciborium-io" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" [[package]] name = "ciborium-ll" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ "ciborium-io", "half", ] [[package]] name = "clap" version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d5f1946157a96594eb2d2c10eb7ad9a2b27518cb3000209dec700c35df9197d" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78116e32a042dd73c2901f0dc30790d20ff3447f3e3472fad359e8c3d282bcd6" dependencies = [ "anstyle", "clap_lex", ] [[package]] name = "clap_lex" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" [[package]] name = "cobs" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" [[package]] name = "criterion" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" dependencies = [ "anes", "cast", "ciborium", "clap", "criterion-plot", "is-terminal", "itertools", "num-traits", "once_cell", "oorandom", "plotters", "rayon", "regex", "serde", "serde_derive", "serde_json", "tinytemplate", "walkdir", ] [[package]] name = "criterion-plot" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", "itertools", ] [[package]] name = "crossbeam-deque" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "databake" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff6ee9e2d2afb173bcdeee45934c89ec341ab26f91c9933774fc15c2b58f83ef" dependencies = [ "proc-macro2", "quote", ] [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "embedded-io" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" [[package]] name = "embedded-io" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" [[package]] name = "funty" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "getrandom" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", "wasi", ] [[package]] name = "half" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" dependencies = [ "cfg-if", "crunchy", ] [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ "ahash", ] [[package]] name = "hermit-abi" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" [[package]] name = "is-terminal" version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" dependencies = [ "hermit-abi", "libc", "windows-sys 0.52.0", ] [[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 = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "540654e97a3f4470a492cd30ff187bc95d89557a903a2bbf112e2fae98104ef2" [[package]] name = "js-sys" version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] [[package]] name = "libc" version = "0.2.164" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" [[package]] name = "litemap" version = "0.7.4" dependencies = [ "bincode", "criterion", "databake", "postcard", "rkyv", "serde", "serde_json", "yoke", ] [[package]] name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "once_cell" version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "oorandom" version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "plotters" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ "num-traits", "plotters-backend", "plotters-svg", "wasm-bindgen", "web-sys", ] [[package]] name = "plotters-backend" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" [[package]] name = "plotters-svg" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" dependencies = [ "plotters-backend", ] [[package]] name = "postcard" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f7f0a8d620d71c457dd1d47df76bb18960378da56af4527aaa10f515eee732e" dependencies = [ "cobs", "embedded-io 0.4.0", "embedded-io 0.6.1", "serde", ] [[package]] name = "proc-macro2" version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] [[package]] name = "ptr_meta" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" dependencies = [ "ptr_meta_derive", ] [[package]] name = "ptr_meta_derive" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" dependencies = [ "proc-macro2", "quote", "syn 1.0.109", ] [[package]] name = "quote" version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "radium" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rayon" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", ] [[package]] name = "rayon-core" version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", ] [[package]] name = "regex" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rend" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" dependencies = [ "bytecheck", ] [[package]] name = "rkyv" version = "0.7.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" dependencies = [ "bitvec", "bytecheck", "bytes", "hashbrown", "ptr_meta", "rend", "rkyv_derive", "seahash", "tinyvec", "uuid", ] [[package]] name = "rkyv_derive" version = "0.7.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" dependencies = [ "proc-macro2", "quote", "syn 1.0.109", ] [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[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 = "seahash" version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" [[package]] name = "serde" version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", "syn 2.0.89", ] [[package]] name = "serde_json" version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", "memchr", "ryu", "serde", ] [[package]] name = "simdutf8" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[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.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "syn" version = "2.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "synstructure" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", "syn 2.0.89", ] [[package]] name = "tap" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[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 = "tinyvec" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] [[package]] name = "tinyvec_macros" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "unicode-ident" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "uuid" version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "walkdir" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", ] [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", "syn 2.0.89", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", "syn 2.0.89", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "web-sys" version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] name = "winapi-util" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ "windows-sys 0.59.0", ] [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets", ] [[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "wyz" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" dependencies = [ "tap", ] [[package]] name = "yoke" version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ "stable_deref_trait", "yoke-derive", "zerofrom", ] [[package]] name = "yoke-derive" version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", "syn 2.0.89", "synstructure", ] [[package]] name = "zerofrom" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", "syn 2.0.89", "synstructure", ] litemap-0.7.4/Cargo.toml0000644000000055460000000000100105070ustar # 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 = "2021" rust-version = "1.71.1" name = "litemap" version = "0.7.4" authors = ["The ICU4X Project Developers"] build = false include = [ "data/**/*", "src/**/*", "examples/**/*", "benches/**/*", "tests/**/*", "Cargo.toml", "LICENSE", "README.md", ] autobins = false autoexamples = false autotests = false autobenches = false description = "A key-value Map implementation based on a flat, sorted Vec." documentation = "https://docs.rs/litemap" readme = "README.md" keywords = [ "sorted", "vec", "map", "hashmap", "btreemap", ] license = "Unicode-3.0" repository = "https://github.com/unicode-org/icu4x" [package.metadata.cargo-all-features] denylist = ["bench"] [package.metadata.docs.rs] all-features = true [package.metadata.workspaces] independent = true [lib] name = "litemap" path = "src/lib.rs" bench = false [[example]] name = "language_names_hash_map" path = "examples/language_names_hash_map.rs" [[example]] name = "language_names_lite_map" path = "examples/language_names_lite_map.rs" [[example]] name = "litemap_bincode" path = "examples/litemap_bincode.rs" required-features = ["serde"] [[example]] name = "litemap_postcard" path = "examples/litemap_postcard.rs" required-features = ["serde"] [[test]] name = "rkyv" path = "tests/rkyv.rs" [[test]] name = "serde" path = "tests/serde.rs" required-features = ["serde"] [[test]] name = "store" path = "tests/store.rs" required-features = ["testing"] [[bench]] name = "litemap" path = "benches/litemap.rs" harness = false required-features = ["serde"] [dependencies.databake] version = "0.2.0" optional = true default-features = false [dependencies.serde] version = "1.0.110" features = ["alloc"] optional = true default-features = false [dependencies.yoke] version = "0.7.5" features = ["derive"] optional = true default-features = false [dev-dependencies.bincode] version = "1.3.1" [dev-dependencies.postcard] version = "1.0.1" features = ["use-std"] default-features = false [dev-dependencies.rkyv] version = "0.7" features = ["validation"] [dev-dependencies.serde] version = "1.0.110" default-features = false [dev-dependencies.serde_json] version = "1.0.45" [features] alloc = [] bench = ["serde"] databake = ["dep:databake"] default = ["alloc"] serde = ["dep:serde"] testing = ["alloc"] yoke = ["dep:yoke"] [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies.criterion] version = "0.5.0" litemap-0.7.4/Cargo.toml.orig000064400000000000000000000041271046102023000141620ustar 00000000000000# 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 ). [package] name = "litemap" version = "0.7.4" keywords = ["sorted", "vec", "map", "hashmap", "btreemap"] description = "A key-value Map implementation based on a flat, sorted Vec." documentation = "https://docs.rs/litemap" authors.workspace = true edition.workspace = true include.workspace = true license.workspace = true repository.workspace = true rust-version.workspace = true [package.metadata.workspaces] independent = true [package.metadata.docs.rs] all-features = true [dependencies] databake = { workspace = true, optional = true } serde = { workspace = true, optional = true, features = ["alloc"]} yoke = { workspace = true, features = ["derive"], optional = true } [dev-dependencies] bincode = { workspace = true } icu_benchmark_macros = { path = "../../tools/benchmark/macros" } icu_locale_core = { path = "../../components/locale_core" } postcard = { workspace = true, features = ["use-std"] } rkyv = { workspace = true, features = ["validation"] } serde = { workspace = true } serde_json = { workspace = true } [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] criterion = { workspace = true } [features] bench = ["serde"] default = ["alloc"] alloc = [] databake = ["dep:databake"] serde = ["dep:serde"] yoke = ["dep:yoke"] # Enables the `testing` module with tools for testing custom stores. testing = ["alloc"] [package.metadata.cargo-all-features] # Bench feature gets tested separately and is only relevant for CI denylist = ["bench"] [lib] bench = false # This option is required for Benchmark CI [[test]] name = "serde" required-features = ["serde"] [[test]] name = "store" required-features = ["testing"] [[example]] name = "litemap_bincode" path = "examples/litemap_bincode.rs" required-features = ["serde"] [[example]] name = "litemap_postcard" path = "examples/litemap_postcard.rs" required-features = ["serde"] [[bench]] name = "litemap" harness = false required-features = ["serde"] litemap-0.7.4/LICENSE000064400000000000000000000042231046102023000122750ustar 00000000000000UNICODE LICENSE V3 COPYRIGHT AND PERMISSION NOTICE Copyright © 2020-2024 Unicode, Inc. NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR 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. Permission is hereby granted, free of charge, to any person obtaining a copy of data files and any associated documentation (the "Data Files") or 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. SPDX-License-Identifier: Unicode-3.0 — 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. litemap-0.7.4/README.md000064400000000000000000000027561046102023000125600ustar 00000000000000# litemap [![crates.io](https://img.shields.io/crates/v/litemap)](https://crates.io/crates/litemap) ## `litemap` `litemap` is a crate providing [`LiteMap`], a highly simplistic "flat" key-value map based off of a single sorted vector. The goal of this crate is to provide a map that is good enough for small sizes, and does not carry the binary size impact of [`HashMap`](std::collections::HashMap) or [`BTreeMap`](alloc::collections::BTreeMap). If binary size is not a concern, [`std::collections::BTreeMap`] may be a better choice for your use case. It behaves very similarly to [`LiteMap`] for less than 12 elements, and upgrades itself gracefully for larger inputs. ### Pluggable Backends By default, [`LiteMap`] is backed by a [`Vec`]; however, it can be backed by any appropriate random-access data store, giving that data store a map-like interface. See the [`store`] module for more details. ### Const construction [`LiteMap`] supports const construction from any store that is const-constructible, such as a static slice, via [`LiteMap::from_sorted_store_unchecked()`]. This also makes [`LiteMap`] suitable for use with [`databake`]. See [`impl Bake for LiteMap`] for more details. [`impl Bake for LiteMap`]: ./struct.LiteMap.html#impl-Bake-for-LiteMap [`Vec`]: alloc::vec::Vec ## More Information For more information on development, authorship, contributing etc. please visit [`ICU4X home page`](https://github.com/unicode-org/icu4x). litemap-0.7.4/benches/litemap.rs000064400000000000000000000076161046102023000147110ustar 00000000000000// 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 criterion::{black_box, criterion_group, criterion_main, Criterion}; use litemap::LiteMap; const DATA: [(&str, &str); 16] = [ ("ar", "Arabic"), ("bn", "Bangla"), ("ccp", "Chakma"), ("chr", "Cherokee"), ("el", "Greek"), ("en", "English"), ("eo", "Esperanto"), ("es", "Spanish"), ("fr", "French"), ("iu", "Inuktitut"), ("ja", "Japanese"), ("ru", "Russian"), ("sr", "Serbian"), ("th", "Thai"), ("tr", "Turkish"), ("zh", "Chinese"), ]; const POSTCARD: [u8; 176] = [ 16, 2, 97, 114, 6, 65, 114, 97, 98, 105, 99, 2, 98, 110, 6, 66, 97, 110, 103, 108, 97, 3, 99, 99, 112, 6, 67, 104, 97, 107, 109, 97, 3, 99, 104, 114, 8, 67, 104, 101, 114, 111, 107, 101, 101, 2, 101, 108, 5, 71, 114, 101, 101, 107, 2, 101, 110, 7, 69, 110, 103, 108, 105, 115, 104, 2, 101, 111, 9, 69, 115, 112, 101, 114, 97, 110, 116, 111, 2, 101, 115, 7, 83, 112, 97, 110, 105, 115, 104, 2, 102, 114, 6, 70, 114, 101, 110, 99, 104, 2, 105, 117, 9, 73, 110, 117, 107, 116, 105, 116, 117, 116, 2, 106, 97, 8, 74, 97, 112, 97, 110, 101, 115, 101, 2, 114, 117, 7, 82, 117, 115, 115, 105, 97, 110, 2, 115, 114, 7, 83, 101, 114, 98, 105, 97, 110, 2, 116, 104, 4, 84, 104, 97, 105, 2, 116, 114, 7, 84, 117, 114, 107, 105, 115, 104, 2, 122, 104, 7, 67, 104, 105, 110, 101, 115, 101, ]; /// Run this function to print new data to the console. #[allow(dead_code)] fn generate() { let map = build_litemap(false); let buf = postcard::to_stdvec(&map).unwrap(); println!("{buf:?}"); } fn large_litemap_postcard_bytes() -> Vec { postcard::to_stdvec(&build_litemap(true)).unwrap() } fn overview_bench(c: &mut Criterion) { // Uncomment the following line to re-generate the binary data. // generate(); bench_deserialize(c); bench_deserialize_large(c); bench_lookup(c); bench_lookup_large(c); } fn build_litemap(large: bool) -> LiteMap { let mut map: LiteMap = LiteMap::new(); for (key, value) in DATA.into_iter() { if large { for n in 0..8192 { map.insert(format!("{key}{n}"), value.to_owned()); } } else { map.insert(key.to_owned(), value.to_owned()); } } map } fn bench_deserialize(c: &mut Criterion) { c.bench_function("litemap/deserialize/small", |b| { b.iter(|| { let map: LiteMap = postcard::from_bytes(black_box(&POSTCARD)).unwrap(); assert_eq!(map.get("iu"), Some(&"Inuktitut".to_owned())); }) }); } fn bench_deserialize_large(c: &mut Criterion) { let buf = large_litemap_postcard_bytes(); c.bench_function("litemap/deseralize/large", |b| { b.iter(|| { let map: LiteMap = postcard::from_bytes(black_box(&buf)).unwrap(); assert_eq!(map.get("iu3333"), Some(&"Inuktitut".to_owned())); }); }); } fn bench_lookup(c: &mut Criterion) { let map: LiteMap = postcard::from_bytes(&POSTCARD).unwrap(); c.bench_function("litemap/lookup/small", |b| { b.iter(|| { assert_eq!(map.get(black_box("iu")), Some(&"Inuktitut".to_owned())); assert_eq!(map.get(black_box("zz")), None); }); }); } fn bench_lookup_large(c: &mut Criterion) { let buf = large_litemap_postcard_bytes(); let map: LiteMap = postcard::from_bytes(&buf).unwrap(); c.bench_function("litemap/lookup/large", |b| { b.iter(|| { assert_eq!(map.get(black_box("iu3333")), Some(&"Inuktitut".to_owned())); assert_eq!(map.get(black_box("zz")), None); }); }); } criterion_group!(benches, overview_bench); criterion_main!(benches); litemap-0.7.4/examples/language_names_hash_map.rs000064400000000000000000000023621046102023000202640ustar 00000000000000// 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 ). // LiteMap is intended as a small and low-memory drop-in replacement for HashMap. // // This example does not use LiteMap. The reader may compare this HashMap example to the // LiteMap example to showcase analogous operations between HashMap and LiteMap. #![no_main] // https://github.com/unicode-org/icu4x/issues/395 icu_benchmark_macros::instrument!(); use icu_locale_core::subtags::{language, Language}; use std::collections::HashMap; const DATA: [(Language, &str); 11] = [ (language!("ar"), "Arabic"), (language!("bn"), "Bangla"), (language!("ccp"), "Chakma"), (language!("en"), "English"), (language!("es"), "Spanish"), (language!("fr"), "French"), (language!("ja"), "Japanese"), (language!("ru"), "Russian"), (language!("sr"), "Serbian"), (language!("th"), "Thai"), (language!("tr"), "Turkish"), ]; fn main() { let map = HashMap::::from_iter(DATA); assert!(map.len() == 11); assert!(map.get(&language!("th")) == Some(&"Thai")); assert!(!map.contains_key(&language!("de"))); } litemap-0.7.4/examples/language_names_lite_map.rs000064400000000000000000000023031046102023000202710ustar 00000000000000// 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 ). // LiteMap is intended as a small and low-memory drop-in replacement for HashMap. // // The reader may compare this LiteMap example with the HashMap example to see analogous // operations between LiteMap and HashMap. #![no_main] // https://github.com/unicode-org/icu4x/issues/395 icu_benchmark_macros::instrument!(); use icu_locale_core::subtags::{language, Language}; use litemap::LiteMap; const DATA: [(Language, &str); 11] = [ (language!("ar"), "Arabic"), (language!("bn"), "Bangla"), (language!("ccp"), "Chakma"), (language!("en"), "English"), (language!("es"), "Spanish"), (language!("fr"), "French"), (language!("ja"), "Japanese"), (language!("ru"), "Russian"), (language!("sr"), "Serbian"), (language!("th"), "Thai"), (language!("tr"), "Turkish"), ]; fn main() { let map = LiteMap::::from_iter(DATA); assert!(map.len() == 11); assert!(map.get(&language!("th")) == Some(&"Thai")); assert!(map.get(&language!("de")).is_none()); } litemap-0.7.4/examples/litemap_bincode.rs000064400000000000000000000045121046102023000165730ustar 00000000000000// 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 ). // LiteMap is intended as a small and low-memory drop-in replacement for // HashMap. This example demonstrates how it works with Serde. #![no_main] // https://github.com/unicode-org/icu4x/issues/395 icu_benchmark_macros::instrument!(); use litemap::LiteMap; const DATA: [(&str, &str); 11] = [ ("ar", "Arabic"), ("bn", "Bangla"), ("ccp", "Chakma"), ("en", "English"), ("es", "Spanish"), ("fr", "French"), ("ja", "Japanese"), ("ru", "Russian"), ("sr", "Serbian"), ("th", "Thai"), ("tr", "Turkish"), ]; #[allow(dead_code)] const BINCODE: [u8; 278] = [ 11, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 97, 114, 6, 0, 0, 0, 0, 0, 0, 0, 65, 114, 97, 98, 105, 99, 2, 0, 0, 0, 0, 0, 0, 0, 98, 110, 6, 0, 0, 0, 0, 0, 0, 0, 66, 97, 110, 103, 108, 97, 3, 0, 0, 0, 0, 0, 0, 0, 99, 99, 112, 6, 0, 0, 0, 0, 0, 0, 0, 67, 104, 97, 107, 109, 97, 2, 0, 0, 0, 0, 0, 0, 0, 101, 110, 7, 0, 0, 0, 0, 0, 0, 0, 69, 110, 103, 108, 105, 115, 104, 2, 0, 0, 0, 0, 0, 0, 0, 101, 115, 7, 0, 0, 0, 0, 0, 0, 0, 83, 112, 97, 110, 105, 115, 104, 2, 0, 0, 0, 0, 0, 0, 0, 102, 114, 6, 0, 0, 0, 0, 0, 0, 0, 70, 114, 101, 110, 99, 104, 2, 0, 0, 0, 0, 0, 0, 0, 106, 97, 8, 0, 0, 0, 0, 0, 0, 0, 74, 97, 112, 97, 110, 101, 115, 101, 2, 0, 0, 0, 0, 0, 0, 0, 114, 117, 7, 0, 0, 0, 0, 0, 0, 0, 82, 117, 115, 115, 105, 97, 110, 2, 0, 0, 0, 0, 0, 0, 0, 115, 114, 7, 0, 0, 0, 0, 0, 0, 0, 83, 101, 114, 98, 105, 97, 110, 2, 0, 0, 0, 0, 0, 0, 0, 116, 104, 4, 0, 0, 0, 0, 0, 0, 0, 84, 104, 97, 105, 2, 0, 0, 0, 0, 0, 0, 0, 116, 114, 7, 0, 0, 0, 0, 0, 0, 0, 84, 117, 114, 107, 105, 115, 104, ]; /// Run this function to print new data to the console. #[allow(dead_code)] fn generate() { let mut map = LiteMap::new_vec(); for (lang, name) in DATA.iter() { map.try_append(lang, name).ok_or(()).unwrap_err(); } let buf = bincode::serialize(&map).unwrap(); println!("{buf:?}"); } fn main() { // Uncomment the following line to re-generate the binary data. // generate(); let map: LiteMap<&str, &str> = bincode::deserialize(&BINCODE).unwrap(); assert_eq!(map.get("tr"), Some(&"Turkish")); } litemap-0.7.4/examples/litemap_postcard.rs000064400000000000000000000035021046102023000170050ustar 00000000000000// 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 ). // LiteMap is intended as a small and low-memory drop-in replacement for // HashMap. This example demonstrates how it works with Serde. #![no_main] // https://github.com/unicode-org/icu4x/issues/395 icu_benchmark_macros::instrument!(); use litemap::LiteMap; const DATA: [(&str, &str); 11] = [ ("ar", "Arabic"), ("bn", "Bangla"), ("ccp", "Chakma"), ("en", "English"), ("es", "Spanish"), ("fr", "French"), ("ja", "Japanese"), ("ru", "Russian"), ("sr", "Serbian"), ("th", "Thai"), ("tr", "Turkish"), ]; const POSTCARD: [u8; 117] = [ 11, 2, 97, 114, 6, 65, 114, 97, 98, 105, 99, 2, 98, 110, 6, 66, 97, 110, 103, 108, 97, 3, 99, 99, 112, 6, 67, 104, 97, 107, 109, 97, 2, 101, 110, 7, 69, 110, 103, 108, 105, 115, 104, 2, 101, 115, 7, 83, 112, 97, 110, 105, 115, 104, 2, 102, 114, 6, 70, 114, 101, 110, 99, 104, 2, 106, 97, 8, 74, 97, 112, 97, 110, 101, 115, 101, 2, 114, 117, 7, 82, 117, 115, 115, 105, 97, 110, 2, 115, 114, 7, 83, 101, 114, 98, 105, 97, 110, 2, 116, 104, 4, 84, 104, 97, 105, 2, 116, 114, 7, 84, 117, 114, 107, 105, 115, 104, ]; /// Run this function to print new data to the console. #[allow(dead_code)] fn generate() { let mut map = LiteMap::new_vec(); for (lang, name) in DATA.iter() { map.try_append(lang, name).ok_or(()).unwrap_err(); } let buf = postcard::to_stdvec(&map).unwrap(); println!("{buf:?}"); } fn main() { // Uncomment the following line to re-generate the binary data. // generate(); let map: LiteMap<&str, &str> = postcard::from_bytes(&POSTCARD).unwrap(); assert_eq!(map.get("tr"), Some(&"Turkish")); } litemap-0.7.4/src/databake.rs000064400000000000000000000047641046102023000141730ustar 00000000000000// 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::LiteMap; use databake::*; /// Bakes a LiteMap into Rust code for fast runtime construction from data. Use this impl during /// code generation, such as in a `build.rs` script. /// /// For the most efficient bake, bake the [`LiteMap`] with a slice store. Use functions such as /// the following for converting an allocated [`LiteMap`] to a borrowing [`LiteMap`]: /// /// - [`LiteMap::to_borrowed_keys()`] /// - [`LiteMap::to_borrowed_values()`] /// - [`LiteMap::to_borrowed_keys_values()`] /// - [`LiteMap::as_sliced()`] /// /// # Examples /// /// ``` /// use databake::*; /// use litemap::LiteMap; /// /// // Construct the LiteMap fully owned and allocated: /// let mut litemap_alloc: LiteMap> = LiteMap::new_vec(); /// litemap_alloc.insert(1usize, "one".to_string()); /// litemap_alloc.insert(2usize, "two".to_string()); /// litemap_alloc.insert(10usize, "ten".to_string()); /// /// // Convert to a borrowed type for baking: /// let litemap_str: LiteMap> = /// litemap_alloc.to_borrowed_values(); /// let litemap_slice: LiteMap = litemap_str.as_sliced(); /// /// // The bake will now work for const construction: /// let mut ctx = Default::default(); /// println!( /// "const FOO: LiteMap = {};", /// litemap_slice.bake(&mut ctx) /// ); /// ``` impl Bake for LiteMap where S: Bake, { fn bake(&self, env: &CrateEnv) -> TokenStream { env.insert("litemap"); let store = self.values.bake(env); quote! { litemap::LiteMap::from_sorted_store_unchecked(#store) } } } #[test] fn test_baked_map() { // Const construction: test_bake!( LiteMap, const, crate::LiteMap::from_sorted_store_unchecked( &[ (1usize, "one"), (2usize, "two"), (10usize, "ten"), ] ), litemap ); // Non-const construction: test_bake!( LiteMap>, crate::LiteMap::from_sorted_store_unchecked( alloc::vec![ (1usize, "one".to_owned()), (2usize, "two".to_owned()), (10usize, "ten".to_owned()), ] ), litemap ); } litemap-0.7.4/src/lib.rs000064400000000000000000000043751046102023000132030ustar 00000000000000// 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 ). //! # `litemap` //! //! `litemap` is a crate providing [`LiteMap`], a highly simplistic "flat" key-value map //! based off of a single sorted vector. //! //! The goal of this crate is to provide a map that is good enough for small //! sizes, and does not carry the binary size impact of [`HashMap`](std::collections::HashMap) //! or [`BTreeMap`](alloc::collections::BTreeMap). //! //! If binary size is not a concern, [`std::collections::BTreeMap`] may be a better choice //! for your use case. It behaves very similarly to [`LiteMap`] for less than 12 elements, //! and upgrades itself gracefully for larger inputs. //! //! ## Pluggable Backends //! //! By default, [`LiteMap`] is backed by a [`Vec`]; however, it can be backed by any appropriate //! random-access data store, giving that data store a map-like interface. See the [`store`] //! module for more details. //! //! ## Const construction //! //! [`LiteMap`] supports const construction from any store that is const-constructible, such as a //! static slice, via [`LiteMap::from_sorted_store_unchecked()`]. This also makes [`LiteMap`] //! suitable for use with [`databake`]. See [`impl Bake for LiteMap`] for more details. //! //! [`impl Bake for LiteMap`]: ./struct.LiteMap.html#impl-Bake-for-LiteMap //! [`Vec`]: alloc::vec::Vec // https://github.com/unicode-org/icu4x/blob/main/documents/process/boilerplate.md#library-annotations #![cfg_attr(not(test), no_std)] #![cfg_attr( not(test), deny( clippy::indexing_slicing, clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::exhaustive_structs, clippy::exhaustive_enums, missing_debug_implementations, ) )] // for intra doc links #[cfg(doc)] extern crate std; extern crate alloc; #[cfg(feature = "databake")] #[path = "databake.rs"] // to not conflict with `databake` as used in the docs mod databake_impls; mod map; #[cfg(feature = "serde")] mod serde; #[cfg(feature = "serde")] mod serde_helpers; pub mod store; #[cfg(any(test, feature = "testing"))] pub mod testing; pub use map::LiteMap; litemap-0.7.4/src/map.rs000064400000000000000000001134051046102023000132050ustar 00000000000000// 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::store::*; use alloc::borrow::Borrow; use alloc::boxed::Box; use alloc::vec::Vec; use core::cmp::Ordering; use core::iter::FromIterator; use core::marker::PhantomData; use core::mem; use core::ops::{Index, IndexMut, Range}; /// A simple "flat" map based on a sorted vector /// /// See the [module level documentation][super] for why one should use this. /// /// The API is roughly similar to that of [`std::collections::BTreeMap`]. #[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] #[cfg_attr(feature = "yoke", derive(yoke::Yokeable))] pub struct LiteMap> { pub(crate) values: S, pub(crate) _key_type: PhantomData, pub(crate) _value_type: PhantomData, } impl LiteMap { /// Construct a new [`LiteMap`] backed by Vec pub const fn new_vec() -> Self { Self { values: alloc::vec::Vec::new(), _key_type: PhantomData, _value_type: PhantomData, } } } impl LiteMap { /// Construct a new [`LiteMap`] using the given values /// /// The store must be sorted and have no duplicate keys. pub const fn from_sorted_store_unchecked(values: S) -> Self { Self { values, _key_type: PhantomData, _value_type: PhantomData, } } } impl LiteMap> { /// Convert a [`LiteMap`] into a sorted `Vec<(K, V)>`. #[inline] pub fn into_tuple_vec(self) -> Vec<(K, V)> { self.values } } impl LiteMap where S: StoreConstEmpty, { /// Create a new empty [`LiteMap`] pub const fn new() -> Self { Self { values: S::EMPTY, _key_type: PhantomData, _value_type: PhantomData, } } } impl LiteMap where S: Store, { /// The number of elements in the [`LiteMap`] pub fn len(&self) -> usize { self.values.lm_len() } /// Whether the [`LiteMap`] is empty pub fn is_empty(&self) -> bool { self.values.lm_is_empty() } /// Get the key-value pair residing at a particular index /// /// In most cases, prefer [`LiteMap::get()`] over this method. #[inline] pub fn get_indexed(&self, index: usize) -> Option<(&K, &V)> { self.values.lm_get(index) } /// Get the lowest-rank key/value pair from the `LiteMap`, if it exists. /// /// # Examples /// /// ```rust /// use litemap::LiteMap; /// /// let mut map = /// LiteMap::>::from_iter([(1, "uno"), (3, "tres")]); /// /// assert_eq!(map.first(), Some((&1, &"uno"))); /// ``` #[inline] pub fn first(&self) -> Option<(&K, &V)> { self.values.lm_get(0) } /// Get the highest-rank key/value pair from the `LiteMap`, if it exists. /// /// # Examples /// /// ```rust /// use litemap::LiteMap; /// /// let mut map = /// LiteMap::>::from_iter([(1, "uno"), (3, "tres")]); /// /// assert_eq!(map.last(), Some((&3, &"tres"))); /// ``` #[inline] pub fn last(&self) -> Option<(&K, &V)> { self.values.lm_last() } /// Returns a new [`LiteMap`] with owned keys and values. /// /// The trait bounds allow transforming most slice and string types. /// /// # Examples /// /// ``` /// use litemap::LiteMap; /// /// let mut map: LiteMap<&str, &str> = LiteMap::new_vec(); /// map.insert("one", "uno"); /// map.insert("two", "dos"); /// /// let boxed_map: LiteMap, Box> = map.to_boxed_keys_values(); /// /// assert_eq!(boxed_map.get("one"), Some(&Box::from("uno"))); /// ``` pub fn to_boxed_keys_values(&self) -> LiteMap, Box, SB> where SB: StoreMut, Box>, K: Borrow, V: Borrow, Box: for<'a> From<&'a KB>, Box: for<'a> From<&'a VB>, { let mut values = SB::lm_with_capacity(self.len()); for i in 0..self.len() { #[allow(clippy::unwrap_used)] // iterating over our own length let (k, v) = self.values.lm_get(i).unwrap(); values.lm_push(Box::from(k.borrow()), Box::from(v.borrow())) } LiteMap { values, _key_type: PhantomData, _value_type: PhantomData, } } /// Returns a new [`LiteMap`] with owned keys and cloned values. /// /// The trait bounds allow transforming most slice and string types. /// /// # Examples /// /// ``` /// use litemap::LiteMap; /// /// let mut map: LiteMap<&str, usize> = LiteMap::new_vec(); /// map.insert("one", 11); /// map.insert("two", 22); /// /// let boxed_map: LiteMap, usize> = map.to_boxed_keys(); /// /// assert_eq!(boxed_map.get("one"), Some(&11)); /// ``` pub fn to_boxed_keys(&self) -> LiteMap, V, SB> where V: Clone, SB: StoreMut, V>, K: Borrow, Box: for<'a> From<&'a KB>, { let mut values = SB::lm_with_capacity(self.len()); for i in 0..self.len() { #[allow(clippy::unwrap_used)] // iterating over our own length let (k, v) = self.values.lm_get(i).unwrap(); values.lm_push(Box::from(k.borrow()), v.clone()) } LiteMap { values, _key_type: PhantomData, _value_type: PhantomData, } } /// Returns a new [`LiteMap`] with cloned keys and owned values. /// /// The trait bounds allow transforming most slice and string types. /// /// # Examples /// /// ``` /// use litemap::LiteMap; /// /// let mut map: LiteMap = LiteMap::new_vec(); /// map.insert(11, "uno"); /// map.insert(22, "dos"); /// /// let boxed_map: LiteMap> = map.to_boxed_values(); /// /// assert_eq!(boxed_map.get(&11), Some(&Box::from("uno"))); /// ``` pub fn to_boxed_values(&self) -> LiteMap, SB> where K: Clone, SB: StoreMut>, V: Borrow, Box: for<'a> From<&'a VB>, { let mut values = SB::lm_with_capacity(self.len()); for i in 0..self.len() { #[allow(clippy::unwrap_used)] // iterating over our own length let (k, v) = self.values.lm_get(i).unwrap(); values.lm_push(k.clone(), Box::from(v.borrow())) } LiteMap { values, _key_type: PhantomData, _value_type: PhantomData, } } } impl LiteMap where K: Ord, S: Store, { /// Get the value associated with `key`, if it exists. /// /// ```rust /// use litemap::LiteMap; /// /// let mut map = LiteMap::new_vec(); /// map.insert(1, "one"); /// map.insert(2, "two"); /// assert_eq!(map.get(&1), Some(&"one")); /// assert_eq!(map.get(&3), None); /// ``` pub fn get(&self, key: &Q) -> Option<&V> where K: Borrow, Q: Ord + ?Sized, { match self.find_index(key) { #[allow(clippy::unwrap_used)] // find_index returns a valid index Ok(found) => Some(self.values.lm_get(found).unwrap().1), Err(_) => None, } } /// Binary search the map with `predicate` to find a key, returning the value. pub fn get_by(&self, predicate: impl FnMut(&K) -> Ordering) -> Option<&V> { let index = self.values.lm_binary_search_by(predicate).ok()?; self.values.lm_get(index).map(|(_, v)| v) } /// Returns whether `key` is contained in this map /// /// ```rust /// use litemap::LiteMap; /// /// let mut map = LiteMap::new_vec(); /// map.insert(1, "one"); /// map.insert(2, "two"); /// assert!(map.contains_key(&1)); /// assert!(!map.contains_key(&3)); /// ``` pub fn contains_key(&self, key: &Q) -> bool where K: Borrow, Q: Ord + ?Sized, { self.find_index(key).is_ok() } /// Obtain the index for a given key, or if the key is not found, the index /// at which it would be inserted. /// /// (The return value works equivalently to [`slice::binary_search_by()`]) /// /// The indices returned can be used with [`Self::get_indexed()`]. Prefer using /// [`Self::get()`] directly where possible. #[inline] pub fn find_index(&self, key: &Q) -> Result where K: Borrow, Q: Ord + ?Sized, { self.values.lm_binary_search_by(|k| k.borrow().cmp(key)) } } impl LiteMap where S: StoreSlice, { /// Creates a new [`LiteMap`] from a range of the current [`LiteMap`]. /// /// # Examples /// /// ``` /// use litemap::LiteMap; /// /// let mut map = LiteMap::new_vec(); /// map.insert(1, "one"); /// map.insert(2, "two"); /// map.insert(3, "three"); /// /// let mut sub_map = map.get_indexed_range(1..3).expect("valid range"); /// assert_eq!(sub_map.get(&1), None); /// assert_eq!(sub_map.get(&2), Some(&"two")); /// assert_eq!(sub_map.get(&3), Some(&"three")); /// ``` pub fn get_indexed_range(&self, range: Range) -> Option> { let subslice = self.values.lm_get_range(range)?; Some(LiteMap { values: subslice, _key_type: PhantomData, _value_type: PhantomData, }) } /// Borrows this [`LiteMap`] as one of its slice type. /// /// This can be useful in situations where you need a `LiteMap` by value but do not want /// to clone the owned version. /// /// # Examples /// /// ``` /// use litemap::LiteMap; /// /// let mut map = LiteMap::new_vec(); /// map.insert(1, "one"); /// map.insert(2, "two"); /// /// let borrowed_map = map.as_sliced(); /// assert_eq!(borrowed_map.get(&1), Some(&"one")); /// assert_eq!(borrowed_map.get(&2), Some(&"two")); /// ``` pub fn as_sliced(&self) -> LiteMap { // Won't panic: 0..self.len() is within range #[allow(clippy::unwrap_used)] let subslice = self.values.lm_get_range(0..self.len()).unwrap(); LiteMap { values: subslice, _key_type: PhantomData, _value_type: PhantomData, } } /// Borrows the backing buffer of this [`LiteMap`] as its slice type. /// /// The slice will be sorted. /// /// # Examples /// /// ``` /// use litemap::LiteMap; /// /// let mut map = LiteMap::new_vec(); /// map.insert(1, "one"); /// map.insert(2, "two"); /// /// let slice = map.as_slice(); /// assert_eq!(slice, &[(1, "one"), (2, "two")]); /// ``` pub fn as_slice(&self) -> &S::Slice { // Won't panic: 0..self.len() is within range #[allow(clippy::unwrap_used)] self.values.lm_get_range(0..self.len()).unwrap() } } impl<'a, K: 'a, V: 'a, S> LiteMap where S: Store, { /// Returns a new [`LiteMap`] with keys and values borrowed from this one. /// /// # Examples /// /// ``` /// use litemap::LiteMap; /// /// let mut map: LiteMap, String> = LiteMap::new_vec(); /// map.insert(Box::new(1), "one".to_string()); /// map.insert(Box::new(2), "two".to_string()); /// /// let borrowed_map: LiteMap<&usize, &str> = map.to_borrowed_keys_values(); /// /// assert_eq!(borrowed_map.get(&1), Some(&"one")); /// ``` pub fn to_borrowed_keys_values( &'a self, ) -> LiteMap<&'a KB, &'a VB, SB> where K: Borrow, V: Borrow, SB: StoreMut<&'a KB, &'a VB>, { let mut values = SB::lm_with_capacity(self.len()); for i in 0..self.len() { #[allow(clippy::unwrap_used)] // iterating over our own length let (k, v) = self.values.lm_get(i).unwrap(); values.lm_push(k.borrow(), v.borrow()) } LiteMap { values, _key_type: PhantomData, _value_type: PhantomData, } } /// Returns a new [`LiteMap`] with keys borrowed from this one and cloned values. /// /// # Examples /// /// ``` /// use litemap::LiteMap; /// /// let mut map: LiteMap, String> = LiteMap::new_vec(); /// map.insert(Box::new(1), "one".to_string()); /// map.insert(Box::new(2), "two".to_string()); /// /// let borrowed_map: LiteMap<&usize, String> = map.to_borrowed_keys(); /// /// assert_eq!(borrowed_map.get(&1), Some(&"one".to_string())); /// ``` pub fn to_borrowed_keys(&'a self) -> LiteMap<&'a KB, V, SB> where K: Borrow, V: Clone, SB: StoreMut<&'a KB, V>, { let mut values = SB::lm_with_capacity(self.len()); for i in 0..self.len() { #[allow(clippy::unwrap_used)] // iterating over our own length let (k, v) = self.values.lm_get(i).unwrap(); values.lm_push(k.borrow(), v.clone()) } LiteMap { values, _key_type: PhantomData, _value_type: PhantomData, } } /// Returns a new [`LiteMap`] with values borrowed from this one and cloned keys. /// /// # Examples /// /// ``` /// use litemap::LiteMap; /// /// let mut map: LiteMap, String> = LiteMap::new_vec(); /// map.insert(Box::new(1), "one".to_string()); /// map.insert(Box::new(2), "two".to_string()); /// /// let borrowed_map: LiteMap, &str> = map.to_borrowed_values(); /// /// assert_eq!(borrowed_map.get(&1), Some(&"one")); /// ``` pub fn to_borrowed_values(&'a self) -> LiteMap where K: Clone, V: Borrow, SB: StoreMut, { let mut values = SB::lm_with_capacity(self.len()); for i in 0..self.len() { #[allow(clippy::unwrap_used)] // iterating over our own length let (k, v) = self.values.lm_get(i).unwrap(); values.lm_push(k.clone(), v.borrow()) } LiteMap { values, _key_type: PhantomData, _value_type: PhantomData, } } } impl LiteMap where S: StoreMut, { /// Construct a new [`LiteMap`] with a given capacity pub fn with_capacity(capacity: usize) -> Self { Self { values: S::lm_with_capacity(capacity), _key_type: PhantomData, _value_type: PhantomData, } } /// Remove all elements from the [`LiteMap`] pub fn clear(&mut self) { self.values.lm_clear() } /// Reserve capacity for `additional` more elements to be inserted into /// the [`LiteMap`] to avoid frequent reallocations. /// /// See [`Vec::reserve()`] for more information. /// /// [`Vec::reserve()`]: alloc::vec::Vec::reserve pub fn reserve(&mut self, additional: usize) { self.values.lm_reserve(additional) } } impl LiteMap where K: Ord, S: StoreMut, { /// Get the value associated with `key`, if it exists, as a mutable reference. /// /// ```rust /// use litemap::LiteMap; /// /// let mut map = LiteMap::new_vec(); /// map.insert(1, "one"); /// map.insert(2, "two"); /// if let Some(mut v) = map.get_mut(&1) { /// *v = "uno"; /// } /// assert_eq!(map.get(&1), Some(&"uno")); /// ``` pub fn get_mut(&mut self, key: &Q) -> Option<&mut V> where K: Borrow, Q: Ord + ?Sized, { match self.find_index(key) { #[allow(clippy::unwrap_used)] // find_index returns a valid index Ok(found) => Some(self.values.lm_get_mut(found).unwrap().1), Err(_) => None, } } /// Appends `value` with `key` to the end of the underlying vector, returning /// `key` and `value` _if it failed_. Useful for extending with an existing /// sorted list. /// ```rust /// use litemap::LiteMap; /// /// let mut map = LiteMap::new_vec(); /// assert!(map.try_append(1, "uno").is_none()); /// assert!(map.try_append(3, "tres").is_none()); /// /// assert!( /// matches!(map.try_append(3, "tres-updated"), Some((3, "tres-updated"))), /// "append duplicate of last key", /// ); /// /// assert!( /// matches!(map.try_append(2, "dos"), Some((2, "dos"))), /// "append out of order" /// ); /// /// assert_eq!(map.get(&1), Some(&"uno")); /// /// // contains the original value for the key: 3 /// assert_eq!(map.get(&3), Some(&"tres")); /// /// // not appended since it wasn't in order /// assert_eq!(map.get(&2), None); /// ``` #[must_use] pub fn try_append(&mut self, key: K, value: V) -> Option<(K, V)> { if let Some(last) = self.values.lm_last() { if last.0 >= &key { return Some((key, value)); } } self.values.lm_push(key, value); None } /// Insert `value` with `key`, returning the existing value if it exists. /// /// ```rust /// use litemap::LiteMap; /// /// let mut map = LiteMap::new_vec(); /// map.insert(1, "one"); /// map.insert(2, "two"); /// assert_eq!(map.get(&1), Some(&"one")); /// assert_eq!(map.get(&3), None); /// ``` pub fn insert(&mut self, key: K, value: V) -> Option { self.insert_save_key(key, value).map(|(_, v)| v) } /// Version of [`Self::insert()`] that returns both the key and the old value. fn insert_save_key(&mut self, key: K, value: V) -> Option<(K, V)> { match self.values.lm_binary_search_by(|k| k.cmp(&key)) { #[allow(clippy::unwrap_used)] // Index came from binary_search Ok(found) => Some(( key, mem::replace(self.values.lm_get_mut(found).unwrap().1, value), )), Err(ins) => { self.values.lm_insert(ins, key, value); None } } } /// Attempts to insert a unique entry into the map. /// /// If `key` is not already in the map, inserts it with the corresponding `value` /// and returns `None`. /// /// If `key` is already in the map, no change is made to the map, and the key and value /// are returned back to the caller. /// /// ``` /// use litemap::LiteMap; /// /// let mut map = LiteMap::new_vec(); /// map.insert(1, "one"); /// map.insert(3, "three"); /// /// // 2 is not yet in the map... /// assert_eq!(map.try_insert(2, "two"), None); /// assert_eq!(map.len(), 3); /// /// // ...but now it is. /// assert_eq!(map.try_insert(2, "TWO"), Some((2, "TWO"))); /// assert_eq!(map.len(), 3); /// ``` pub fn try_insert(&mut self, key: K, value: V) -> Option<(K, V)> { match self.values.lm_binary_search_by(|k| k.cmp(&key)) { Ok(_) => Some((key, value)), Err(ins) => { self.values.lm_insert(ins, key, value); None } } } /// Attempts to insert a unique entry into the map. /// /// If `key` is not already in the map, invokes the closure to compute `value`, inserts /// the pair into the map, and returns a reference to the value. The closure is passed /// a reference to the `key` argument. /// /// If `key` is already in the map, a reference to the existing value is returned. /// /// Additionally, the index of the value in the map is returned. If it is not desirable /// to hold on to the mutable reference's lifetime, the index can be used to access the /// element via [`LiteMap::get_indexed()`]. /// /// The closure returns a `Result` to allow for a fallible insertion function. If the /// creation of `value` is infallible, you can use [`core::convert::Infallible`]. /// /// ``` /// use litemap::LiteMap; /// /// /// Helper function to unwrap an `Infallible` result from the insertion function /// fn unwrap_infallible(result: Result) -> T { /// result.unwrap_or_else(|never| match never {}) /// } /// /// let mut map = LiteMap::new_vec(); /// map.insert(1, "one"); /// map.insert(3, "three"); /// /// // 2 is not yet in the map... /// let result1 = unwrap_infallible( /// map.try_get_or_insert(2, |_| Ok("two")) /// ); /// assert_eq!(result1.1, &"two"); /// assert_eq!(map.len(), 3); /// /// // ...but now it is. /// let result1 = unwrap_infallible( /// map.try_get_or_insert(2, |_| Ok("TWO")) /// ); /// assert_eq!(result1.1, &"two"); /// assert_eq!(map.len(), 3); /// ``` pub fn try_get_or_insert( &mut self, key: K, value: impl FnOnce(&K) -> Result, ) -> Result<(usize, &V), E> { let idx = match self.values.lm_binary_search_by(|k| k.cmp(&key)) { Ok(idx) => idx, Err(idx) => { let value = value(&key)?; self.values.lm_insert(idx, key, value); idx } }; #[allow(clippy::unwrap_used)] // item at idx found or inserted above Ok((idx, self.values.lm_get(idx).unwrap().1)) } /// Remove the value at `key`, returning it if it exists. /// /// ```rust /// use litemap::LiteMap; /// /// let mut map = LiteMap::new_vec(); /// map.insert(1, "one"); /// map.insert(2, "two"); /// assert_eq!(map.remove(&1), Some("one")); /// assert_eq!(map.get(&1), None); /// ``` pub fn remove(&mut self, key: &Q) -> Option where K: Borrow, Q: Ord + ?Sized, { match self.values.lm_binary_search_by(|k| k.borrow().cmp(key)) { Ok(found) => Some(self.values.lm_remove(found).1), Err(_) => None, } } } impl LiteMap where K: Ord, S: StoreIntoIterator + StoreFromIterator, { /// Insert all elements from `other` into this `LiteMap`. /// /// If `other` contains keys that already exist in `self`, the values in `other` replace the /// corresponding ones in `self`, and the rejected items from `self` are returned as a new /// `LiteMap`. Otherwise, `None` is returned. /// /// The implementation of this function is optimized if `self` and `other` have no overlap. /// /// # Examples /// /// ``` /// use litemap::LiteMap; /// /// let mut map1 = LiteMap::new_vec(); /// map1.insert(1, "one"); /// map1.insert(2, "two"); /// /// let mut map2 = LiteMap::new_vec(); /// map2.insert(2, "TWO"); /// map2.insert(4, "FOUR"); /// /// let leftovers = map1.extend_from_litemap(map2); /// /// assert_eq!(map1.len(), 3); /// assert_eq!(map1.get(&1), Some("one").as_ref()); /// assert_eq!(map1.get(&2), Some("TWO").as_ref()); /// assert_eq!(map1.get(&4), Some("FOUR").as_ref()); /// /// let map3 = leftovers.expect("Duplicate keys"); /// assert_eq!(map3.len(), 1); /// assert_eq!(map3.get(&2), Some("two").as_ref()); /// ``` pub fn extend_from_litemap(&mut self, other: Self) -> Option { if self.is_empty() { self.values = other.values; return None; } if other.is_empty() { return None; } if self.last().map(|(k, _)| k) < other.first().map(|(k, _)| k) { // append other to self self.values.lm_extend_end(other.values); None } else if self.first().map(|(k, _)| k) > other.last().map(|(k, _)| k) { // prepend other to self self.values.lm_extend_start(other.values); None } else { // insert every element let leftover_tuples = other .values .lm_into_iter() .filter_map(|(k, v)| self.insert_save_key(k, v)) .collect(); let ret = LiteMap { values: leftover_tuples, _key_type: PhantomData, _value_type: PhantomData, }; if ret.is_empty() { None } else { Some(ret) } } } } impl Default for LiteMap where S: Store + Default, { fn default() -> Self { Self { values: S::default(), _key_type: PhantomData, _value_type: PhantomData, } } } impl Index<&'_ K> for LiteMap where K: Ord, S: Store, { type Output = V; fn index(&self, key: &K) -> &V { #[allow(clippy::panic)] // documented match self.get(key) { Some(v) => v, None => panic!("no entry found for key"), } } } impl IndexMut<&'_ K> for LiteMap where K: Ord, S: StoreMut, { fn index_mut(&mut self, key: &K) -> &mut V { #[allow(clippy::panic)] // documented match self.get_mut(key) { Some(v) => v, None => panic!("no entry found for key"), } } } impl FromIterator<(K, V)> for LiteMap where K: Ord, S: StoreFromIterable, { fn from_iter>(iter: I) -> Self { let values = S::lm_sort_from_iter(iter); Self::from_sorted_store_unchecked(values) } } impl<'a, K: 'a, V: 'a, S> LiteMap where S: StoreIterable<'a, K, V>, { /// Produce an ordered iterator over key-value pairs pub fn iter(&'a self) -> impl DoubleEndedIterator { self.values.lm_iter() } /// Produce an ordered iterator over keys pub fn iter_keys(&'a self) -> impl DoubleEndedIterator { self.values.lm_iter().map(|val| val.0) } /// Produce an iterator over values, ordered by their keys pub fn iter_values(&'a self) -> impl DoubleEndedIterator { self.values.lm_iter().map(|val| val.1) } } impl<'a, K: 'a, V: 'a, S> LiteMap where S: StoreIterableMut<'a, K, V>, { /// Produce an ordered mutable iterator over key-value pairs pub fn iter_mut(&'a mut self) -> impl DoubleEndedIterator { self.values.lm_iter_mut() } } impl IntoIterator for LiteMap where S: StoreIntoIterator, { type Item = (K, V); type IntoIter = S::KeyValueIntoIter; fn into_iter(self) -> Self::IntoIter { self.values.lm_into_iter() } } impl LiteMap where S: StoreMut, { /// Retains only the elements specified by the predicate. /// /// In other words, remove all elements such that `f((&k, &v))` returns `false`. /// /// # Example /// /// ```rust /// use litemap::LiteMap; /// /// let mut map = LiteMap::new_vec(); /// map.insert(1, "one"); /// map.insert(2, "two"); /// map.insert(3, "three"); /// /// // Retain elements with odd keys /// map.retain(|k, _| k % 2 == 1); /// /// assert_eq!(map.get(&1), Some(&"one")); /// assert_eq!(map.get(&2), None); /// ``` #[inline] pub fn retain(&mut self, predicate: F) where F: FnMut(&K, &V) -> bool, { self.values.lm_retain(predicate) } } impl<'a, K, V> LiteMap { /// Const version of [`LiteMap::len()`] for a slice store. /// /// Note: This function will no longer be needed if const trait behavior is stabilized. /// /// # Examples /// /// ```rust /// use litemap::LiteMap; /// /// static map: LiteMap<&str, usize, &[(&str, usize)]> = /// LiteMap::from_sorted_store_unchecked(&[("a", 11), ("b", 22)]); /// static len: usize = map.const_len(); /// assert_eq!(len, 2); /// ``` #[inline] pub const fn const_len(&self) -> usize { self.values.len() } /// Const version of [`LiteMap::is_empty()`] for a slice store. /// /// Note: This function will no longer be needed if const trait behavior is stabilized. /// /// # Examples /// /// ```rust /// use litemap::LiteMap; /// /// static map: LiteMap<&str, usize, &[(&str, usize)]> = /// LiteMap::from_sorted_store_unchecked(&[]); /// static is_empty: bool = map.const_is_empty(); /// assert!(is_empty); /// ``` #[inline] pub const fn const_is_empty(&self) -> bool { self.values.is_empty() } /// Const version of [`LiteMap::get_indexed()`] for a slice store. /// /// Note: This function will no longer be needed if const trait behavior is stabilized. /// /// # Panics /// /// Panics if the index is out of bounds. /// /// # Examples /// /// ```rust /// use litemap::LiteMap; /// /// static map: LiteMap<&str, usize, &[(&str, usize)]> = /// LiteMap::from_sorted_store_unchecked(&[("a", 11), ("b", 22)]); /// static t: &(&str, usize) = map.const_get_indexed_or_panic(0); /// assert_eq!(t.0, "a"); /// assert_eq!(t.1, 11); /// ``` #[inline] #[allow(clippy::indexing_slicing)] // documented pub const fn const_get_indexed_or_panic(&self, index: usize) -> &'a (K, V) { &self.values[index] } } const fn const_cmp_bytes(a: &[u8], b: &[u8]) -> Ordering { let (max, default) = if a.len() == b.len() { (a.len(), Ordering::Equal) } else if a.len() < b.len() { (a.len(), Ordering::Less) } else { (b.len(), Ordering::Greater) }; let mut i = 0; #[allow(clippy::indexing_slicing)] // indexes in range by above checks while i < max { if a[i] == b[i] { i += 1; continue; } else if a[i] < b[i] { return Ordering::Less; } else { return Ordering::Greater; } } default } impl<'a, V> LiteMap<&'a str, V, &'a [(&'a str, V)]> { /// Const function to get the value associated with a `&str` key, if it exists. /// /// Also returns the index of the value. /// /// Note: This function will no longer be needed if const trait behavior is stabilized. /// /// # Examples /// /// ```rust /// use litemap::LiteMap; /// /// static map: LiteMap<&str, usize, &[(&str, usize)]> = /// LiteMap::from_sorted_store_unchecked(&[ /// ("abc", 11), /// ("bcd", 22), /// ("cde", 33), /// ("def", 44), /// ("efg", 55), /// ]); /// /// static d: Option<(usize, &usize)> = map.const_get_with_index("def"); /// assert_eq!(d, Some((3, &44))); /// /// static n: Option<(usize, &usize)> = map.const_get_with_index("dng"); /// assert_eq!(n, None); /// ``` pub const fn const_get_with_index(&self, key: &str) -> Option<(usize, &'a V)> { let mut i = 0; let mut j = self.const_len(); while i < j { let mid = (i + j) / 2; #[allow(clippy::indexing_slicing)] // in range let x = &self.values[mid]; match const_cmp_bytes(key.as_bytes(), x.0.as_bytes()) { Ordering::Equal => return Some((mid, &x.1)), Ordering::Greater => i = mid + 1, Ordering::Less => j = mid, }; } None } } impl<'a, V> LiteMap<&'a [u8], V, &'a [(&'a [u8], V)]> { /// Const function to get the value associated with a `&[u8]` key, if it exists. /// /// Also returns the index of the value. /// /// Note: This function will no longer be needed if const trait behavior is stabilized. /// /// # Examples /// /// ```rust /// use litemap::LiteMap; /// /// static map: LiteMap<&[u8], usize, &[(&[u8], usize)]> = /// LiteMap::from_sorted_store_unchecked(&[ /// (b"abc", 11), /// (b"bcd", 22), /// (b"cde", 33), /// (b"def", 44), /// (b"efg", 55), /// ]); /// /// static d: Option<(usize, &usize)> = map.const_get_with_index(b"def"); /// assert_eq!(d, Some((3, &44))); /// /// static n: Option<(usize, &usize)> = map.const_get_with_index(b"dng"); /// assert_eq!(n, None); /// ``` pub const fn const_get_with_index(&self, key: &[u8]) -> Option<(usize, &'a V)> { let mut i = 0; let mut j = self.const_len(); while i < j { let mid = (i + j) / 2; #[allow(clippy::indexing_slicing)] // in range let x = &self.values[mid]; match const_cmp_bytes(key, x.0) { Ordering::Equal => return Some((mid, &x.1)), Ordering::Greater => i = mid + 1, Ordering::Less => j = mid, }; } None } } macro_rules! impl_const_get_with_index_for_integer { ($integer:ty) => { impl<'a, V> LiteMap<$integer, V, &'a [($integer, V)]> { /// Const function to get the value associated with an integer key, if it exists. /// /// Note: This function will no longer be needed if const trait behavior is stabilized. /// /// Also returns the index of the value. pub const fn const_get_with_index(&self, key: $integer) -> Option<(usize, &'a V)> { let mut i = 0; let mut j = self.const_len(); while i < j { let mid = (i + j) / 2; #[allow(clippy::indexing_slicing)] // in range let x = &self.values[mid]; if key == x.0 { return Some((mid, &x.1)); } else if key > x.0 { i = mid + 1; } else { j = mid; } } return None; } } }; } impl_const_get_with_index_for_integer!(u8); impl_const_get_with_index_for_integer!(u16); impl_const_get_with_index_for_integer!(u32); impl_const_get_with_index_for_integer!(u64); impl_const_get_with_index_for_integer!(u128); impl_const_get_with_index_for_integer!(usize); impl_const_get_with_index_for_integer!(i8); impl_const_get_with_index_for_integer!(i16); impl_const_get_with_index_for_integer!(i32); impl_const_get_with_index_for_integer!(i64); impl_const_get_with_index_for_integer!(i128); impl_const_get_with_index_for_integer!(isize); #[cfg(test)] mod test { use super::*; #[test] fn from_iterator() { let mut expected = LiteMap::with_capacity(4); expected.insert(1, "updated-one"); expected.insert(2, "original-two"); expected.insert(3, "original-three"); expected.insert(4, "updated-four"); let actual = [ (1, "original-one"), (2, "original-two"), (4, "original-four"), (4, "updated-four"), (1, "updated-one"), (3, "original-three"), ] .into_iter() .collect::>(); assert_eq!(expected, actual); } fn make_13() -> LiteMap { let mut result = LiteMap::new(); result.insert(1, "one"); result.insert(3, "three"); result } fn make_24() -> LiteMap { let mut result = LiteMap::new(); result.insert(2, "TWO"); result.insert(4, "FOUR"); result } fn make_46() -> LiteMap { let mut result = LiteMap::new(); result.insert(4, "four"); result.insert(6, "six"); result } #[test] fn extend_from_litemap_append() { let mut map = LiteMap::new(); map.extend_from_litemap(make_13()) .ok_or(()) .expect_err("Append to empty map"); map.extend_from_litemap(make_46()) .ok_or(()) .expect_err("Append to lesser map"); assert_eq!(map.len(), 4); } #[test] fn extend_from_litemap_prepend() { let mut map = LiteMap::new(); map.extend_from_litemap(make_46()) .ok_or(()) .expect_err("Prepend to empty map"); map.extend_from_litemap(make_13()) .ok_or(()) .expect_err("Prepend to lesser map"); assert_eq!(map.len(), 4); } #[test] fn extend_from_litemap_insert() { let mut map = LiteMap::new(); map.extend_from_litemap(make_13()) .ok_or(()) .expect_err("Append to empty map"); map.extend_from_litemap(make_24()) .ok_or(()) .expect_err("Insert with no conflict"); map.extend_from_litemap(make_46()) .ok_or(()) .expect("Insert with conflict"); assert_eq!(map.len(), 5); } #[test] fn test_const_cmp_bytes() { let strs = &["a", "aa", "abc", "abde", "bcd", "bcde"]; for i in 0..strs.len() { for j in 0..strs.len() { let a = strs[i].as_bytes(); let b = strs[j].as_bytes(); assert_eq!(a.cmp(b), const_cmp_bytes(a, b)); } } } #[test] fn into_iterator() { let mut map = LiteMap::<_, _, Vec<(_, _)>>::new(); map.insert(4, "four"); map.insert(6, "six"); let mut reference = vec![(6, "six"), (4, "four")]; for i in map { let r = reference.pop().unwrap(); assert_eq!(r, i); } assert!(reference.is_empty()); } } litemap-0.7.4/src/serde.rs000064400000000000000000000160161046102023000135320ustar 00000000000000// 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 super::LiteMap; use crate::store::*; use core::fmt; use core::marker::PhantomData; use serde::de::{MapAccess, SeqAccess, Visitor}; use serde::{Deserialize, Deserializer}; #[cfg(feature = "serde")] use serde::{ser::SerializeMap, Serialize, Serializer}; #[cfg(feature = "serde")] impl Serialize for LiteMap where K: Serialize, V: Serialize, R: Store + Serialize, { fn serialize(&self, serializer: S) -> Result where S: Serializer, { // Many human-readable formats don't support values other // than numbers and strings as map keys. For them, we can serialize // as a vec of tuples instead if serializer.is_human_readable() { if let Some((ref k, _)) = self.values.lm_get(0) { if !super::serde_helpers::is_num_or_string(k) { return self.values.serialize(serializer); } // continue to regular serialization } } let mut map = serializer.serialize_map(Some(self.len()))?; let mut i = 0; while i < self.values.lm_len() { #[allow(clippy::unwrap_used)] // i is in range let (k, v) = self.values.lm_get(i).unwrap(); map.serialize_entry(k, v)?; i += 1; } map.end() } } /// Modified example from https://serde.rs/deserialize-map.html #[allow(clippy::type_complexity)] struct LiteMapVisitor { marker: PhantomData LiteMap>, } impl LiteMapVisitor { fn new() -> Self { Self { marker: PhantomData, } } } impl<'de, K, V, R> Visitor<'de> for LiteMapVisitor where K: Deserialize<'de> + Ord, V: Deserialize<'de>, R: StoreMut + StoreFromIterable, { type Value = LiteMap; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a map produced by LiteMap") } fn visit_seq(self, mut access: S) -> Result where S: SeqAccess<'de>, { let mut map = LiteMap::with_capacity(access.size_hint().unwrap_or(0)); // While there are entries remaining in the input, add them // into our map. while let Some((key, value)) = access.next_element()? { // Try to append it at the end, hoping for a sorted map. // If not sorted, insert as usual. // This allows for arbitrary maps (e.g. from user JSON) // to be deserialized into LiteMap // without impacting performance in the case of deserializing // a serialized map that came from another LiteMap if let Some((key, value)) = map.try_append(key, value) { // Note: this effectively selection sorts the map, // which isn't efficient for large maps map.insert(key, value); } } Ok(map) } fn visit_map(self, mut access: M) -> Result where M: MapAccess<'de>, { let mut map = LiteMap::with_capacity(access.size_hint().unwrap_or(0)); // While there are entries remaining in the input, add them // into our map. while let Some((key, value)) = access.next_entry()? { // Try to append it at the end, hoping for a sorted map. // If not sorted, insert as usual. // This allows for arbitrary maps (e.g. from user JSON) // to be deserialized into LiteMap // without impacting performance in the case of deserializing // a serialized map that came from another LiteMap if let Some((key, value)) = map.try_append(key, value) { // Note: this effectively selection sorts the map, // which isn't efficient for large maps map.insert(key, value); } } Ok(map) } } impl<'de, K, V, R> Deserialize<'de> for LiteMap where K: Ord + Deserialize<'de>, V: Deserialize<'de>, R: StoreMut + StoreFromIterable, { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { if deserializer.is_human_readable() { // deserialize_any only works on self-describing (human-readable) // formats deserializer.deserialize_any(LiteMapVisitor::new()) } else { deserializer.deserialize_map(LiteMapVisitor::new()) } } } #[cfg(test)] mod test { use crate::LiteMap; use alloc::borrow::ToOwned; use alloc::string::String; fn get_simple_map() -> LiteMap { [ (1, "one".to_owned()), (2, "two".to_owned()), (4, "four".to_owned()), (5, "five".to_owned()), ] .into_iter() .collect() } fn get_tuple_map() -> LiteMap<(u32, String), String> { [ ((1, "en".to_owned()), "one".to_owned()), ((1, "zh".to_owned()), "一".to_owned()), ((2, "en".to_owned()), "two".to_owned()), ((2, "zh".to_owned()), "二".to_owned()), ((4, "en".to_owned()), "four".to_owned()), ((5, "en".to_owned()), "five".to_owned()), ((5, "zh".to_owned()), "五".to_owned()), ((7, "zh".to_owned()), "七".to_owned()), ] .into_iter() .collect() } #[test] fn test_roundtrip_json() { let map = get_simple_map(); let json = serde_json::to_string(&map).unwrap(); assert_eq!( json, "{\"1\":\"one\",\"2\":\"two\",\"4\":\"four\",\"5\":\"five\"}" ); let deserialized: LiteMap = serde_json::from_str(&json).unwrap(); assert_eq!(map, deserialized); let map = get_tuple_map(); let json = serde_json::to_string(&map).unwrap(); assert_eq!( json, "[[[1,\"en\"],\"one\"],[[1,\"zh\"],\"一\"],[[2,\"en\"],\"two\"],\ [[2,\"zh\"],\"二\"],[[4,\"en\"],\"four\"],[[5,\"en\"],\"five\"],\ [[5,\"zh\"],\"五\"],[[7,\"zh\"],\"七\"]]" ); let deserialized: LiteMap<(u32, String), String> = serde_json::from_str(&json).unwrap(); assert_eq!(map, deserialized); } #[test] fn test_roundtrip_postcard() { let map = get_simple_map(); let postcard = postcard::to_stdvec(&map).unwrap(); let deserialized: LiteMap = postcard::from_bytes(&postcard).unwrap(); assert_eq!(map, deserialized); let map = get_tuple_map(); let postcard = postcard::to_stdvec(&map).unwrap(); let deserialized: LiteMap<(u32, String), String> = postcard::from_bytes(&postcard).unwrap(); assert_eq!(map, deserialized); } } litemap-0.7.4/src/serde_helpers.rs000064400000000000000000000136541046102023000152610ustar 00000000000000// 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 ). // @@@@@@@@@@@@@@@@ // THIS FILE IS SHARED BETWEEN LITEMAP AND ZEROVEC. PLEASE KEEP IT IN SYNC FOR ALL EDITS // @@@@@@@@@@@@@@@@ use serde::ser::{Impossible, Serialize, Serializer}; pub fn is_num_or_string(k: &T) -> bool { // Serializer that errors in the same cases as serde_json::ser::MapKeySerializer struct MapKeySerializerDryRun; impl Serializer for MapKeySerializerDryRun { type Ok = (); // Singleton error type that implements serde::ser::Error type Error = core::fmt::Error; type SerializeSeq = Impossible<(), Self::Error>; type SerializeTuple = Impossible<(), Self::Error>; type SerializeTupleStruct = Impossible<(), Self::Error>; type SerializeTupleVariant = Impossible<(), Self::Error>; type SerializeMap = Impossible<(), Self::Error>; type SerializeStruct = Impossible<(), Self::Error>; type SerializeStructVariant = Impossible<(), Self::Error>; fn serialize_str(self, _value: &str) -> Result { Ok(()) } fn serialize_unit_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, ) -> Result { Ok(()) } fn serialize_newtype_struct( self, _name: &'static str, value: &T, ) -> Result { // Recurse value.serialize(self) } fn serialize_bool(self, _value: bool) -> Result { Err(core::fmt::Error) } fn serialize_i8(self, _value: i8) -> Result { Ok(()) } fn serialize_i16(self, _value: i16) -> Result { Ok(()) } fn serialize_i32(self, _value: i32) -> Result { Ok(()) } fn serialize_i64(self, _value: i64) -> Result { Ok(()) } serde::serde_if_integer128! { fn serialize_i128(self, _value: i128) -> Result { Ok(()) } } fn serialize_u8(self, _value: u8) -> Result { Ok(()) } fn serialize_u16(self, _value: u16) -> Result { Ok(()) } fn serialize_u32(self, _value: u32) -> Result { Ok(()) } fn serialize_u64(self, _value: u64) -> Result { Ok(()) } serde::serde_if_integer128! { fn serialize_u128(self, _value: u128) -> Result { Ok(()) } } fn serialize_f32(self, _value: f32) -> Result { Err(core::fmt::Error) } fn serialize_f64(self, _value: f64) -> Result { Err(core::fmt::Error) } fn serialize_char(self, _value: char) -> Result { Ok(()) } fn serialize_bytes(self, _value: &[u8]) -> Result { Err(core::fmt::Error) } fn serialize_unit(self) -> Result { Err(core::fmt::Error) } fn serialize_unit_struct(self, _name: &'static str) -> Result { Err(core::fmt::Error) } fn serialize_newtype_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _value: &T, ) -> Result { Err(core::fmt::Error) } fn serialize_none(self) -> Result { Err(core::fmt::Error) } fn serialize_some( self, _value: &T, ) -> Result { Err(core::fmt::Error) } fn serialize_seq(self, _len: Option) -> Result { Err(core::fmt::Error) } fn serialize_tuple(self, _len: usize) -> Result { Err(core::fmt::Error) } fn serialize_tuple_struct( self, _name: &'static str, _len: usize, ) -> Result { Err(core::fmt::Error) } fn serialize_tuple_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { Err(core::fmt::Error) } fn serialize_map(self, _len: Option) -> Result { Err(core::fmt::Error) } fn serialize_struct( self, _name: &'static str, _len: usize, ) -> Result { Err(core::fmt::Error) } fn serialize_struct_variant( self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize, ) -> Result { Err(core::fmt::Error) } fn collect_str( self, _value: &T, ) -> Result { Ok(()) } } k.serialize(MapKeySerializerDryRun).is_ok() } litemap-0.7.4/src/store/mod.rs000064400000000000000000000135421046102023000143440ustar 00000000000000// 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 ). //! Traits for pluggable LiteMap backends. //! //! By default, LiteMap is backed by a `Vec`. However, in some environments, it may be desirable //! to use a different data store while still using LiteMap to manage proper ordering of items. //! //! The general guidelines for a performant data store are: //! //! 1. Must support efficient random access for binary search //! 2. Should support efficient append operations for deserialization //! //! To plug a custom data store into LiteMap, implement: //! //! - [`Store`] for most of the methods //! - [`StoreIterable`] for methods that return iterators //! - [`StoreFromIterator`] to enable `FromIterator` for LiteMap //! //! To test your implementation, enable the `"testing"` Cargo feature and use [`check_store()`]. //! //! [`check_store()`]: crate::testing::check_store mod slice_impl; #[cfg(feature = "alloc")] mod vec_impl; use core::cmp::Ordering; use core::iter::DoubleEndedIterator; use core::iter::FromIterator; use core::iter::Iterator; use core::ops::Range; /// Trait to enable const construction of empty store. pub trait StoreConstEmpty { /// An empty store const EMPTY: Self; } /// Trait to enable pluggable backends for LiteMap. /// /// Some methods have default implementations provided for convenience; however, it is generally /// better to implement all methods that your data store supports. pub trait Store: Sized { /// Returns the number of elements in the store. fn lm_len(&self) -> usize; /// Returns whether the store is empty (contains 0 elements). fn lm_is_empty(&self) -> bool { self.lm_len() == 0 } /// Gets a key/value pair at the specified index. fn lm_get(&self, index: usize) -> Option<(&K, &V)>; /// Gets the last element in the store, or `None` if the store is empty. fn lm_last(&self) -> Option<(&K, &V)> { let len = self.lm_len(); if len == 0 { None } else { self.lm_get(len - 1) } } /// Searches the store for a particular element with a comparator function. /// /// See the binary search implementation on `slice` for more information. fn lm_binary_search_by(&self, cmp: F) -> Result where F: FnMut(&K) -> Ordering; } pub trait StoreFromIterable: Store { /// Create a sorted store from `iter`. fn lm_sort_from_iter>(iter: I) -> Self; } pub trait StoreSlice: Store { type Slice: ?Sized; fn lm_get_range(&self, range: Range) -> Option<&Self::Slice>; } pub trait StoreMut: Store { /// Creates a new store with the specified capacity hint. /// /// Implementations may ignore the argument if they do not support pre-allocating capacity. fn lm_with_capacity(capacity: usize) -> Self; /// Reserves additional capacity in the store. /// /// Implementations may ignore the argument if they do not support pre-allocating capacity. fn lm_reserve(&mut self, additional: usize); /// Gets a key/value pair at the specified index, with a mutable value. fn lm_get_mut(&mut self, index: usize) -> Option<(&K, &mut V)>; /// Pushes one additional item onto the store. fn lm_push(&mut self, key: K, value: V); /// Inserts an item at a specific index in the store. /// /// # Panics /// /// Panics if `index` is greater than the length. fn lm_insert(&mut self, index: usize, key: K, value: V); /// Removes an item at a specific index in the store. /// /// # Panics /// /// Panics if `index` is greater than the length. fn lm_remove(&mut self, index: usize) -> (K, V); /// Removes all items from the store. fn lm_clear(&mut self); /// Retains items satisfying a predicate in this store. fn lm_retain(&mut self, mut predicate: F) where F: FnMut(&K, &V) -> bool, { let mut i = 0; while i < self.lm_len() { #[allow(clippy::unwrap_used)] // i is in range let (k, v) = self.lm_get(i).unwrap(); if predicate(k, v) { i += 1; } else { self.lm_remove(i); } } } } /// Iterator methods for the LiteMap store. pub trait StoreIterable<'a, K: 'a + ?Sized, V: 'a + ?Sized>: Store { type KeyValueIter: Iterator + DoubleEndedIterator + 'a; /// Returns an iterator over key/value pairs. fn lm_iter(&'a self) -> Self::KeyValueIter; } pub trait StoreIterableMut<'a, K: 'a, V: 'a>: StoreMut + StoreIterable<'a, K, V> { type KeyValueIterMut: Iterator + DoubleEndedIterator + 'a; /// Returns an iterator over key/value pairs, with a mutable value. fn lm_iter_mut(&'a mut self) -> Self::KeyValueIterMut; } pub trait StoreIntoIterator: StoreMut { type KeyValueIntoIter: Iterator; /// Returns an iterator that moves every item from this store. fn lm_into_iter(self) -> Self::KeyValueIntoIter; /// Adds items from another store to the end of this store. fn lm_extend_end(&mut self, other: Self) where Self: Sized, { for item in other.lm_into_iter() { self.lm_push(item.0, item.1); } } /// Adds items from another store to the beginning of this store. fn lm_extend_start(&mut self, other: Self) where Self: Sized, { for (i, item) in other.lm_into_iter().enumerate() { self.lm_insert(i, item.0, item.1); } } } /// A store that can be built from a tuple iterator. pub trait StoreFromIterator: FromIterator<(K, V)> {} litemap-0.7.4/src/store/slice_impl.rs000064400000000000000000000027221046102023000157030ustar 00000000000000// 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 super::*; type MapF = fn(&(K, V)) -> (&K, &V); #[inline] fn map_f(input: &(K, V)) -> (&K, &V) { (&input.0, &input.1) } impl<'a, K: 'a, V: 'a> StoreConstEmpty for &'a [(K, V)] { const EMPTY: &'a [(K, V)] = &[]; } impl<'a, K: 'a, V: 'a> Store for &'a [(K, V)] { #[inline] fn lm_len(&self) -> usize { self.len() } #[inline] fn lm_is_empty(&self) -> bool { self.is_empty() } #[inline] fn lm_get(&self, index: usize) -> Option<(&K, &V)> { self.get(index).map(map_f) } #[inline] fn lm_last(&self) -> Option<(&K, &V)> { self.last().map(map_f) } #[inline] fn lm_binary_search_by(&self, mut cmp: F) -> Result where F: FnMut(&K) -> Ordering, { self.binary_search_by(|(k, _)| cmp(k)) } } impl StoreSlice for &[(K, V)] { type Slice = [(K, V)]; fn lm_get_range(&self, range: Range) -> Option<&Self::Slice> { self.get(range) } } impl<'a, K: 'a, V: 'a> StoreIterable<'a, K, V> for &'a [(K, V)] { type KeyValueIter = core::iter::Map, MapF>; #[inline] fn lm_iter(&'a self) -> Self::KeyValueIter { self.iter().map(map_f) } } litemap-0.7.4/src/store/vec_impl.rs000064400000000000000000000112221046102023000153540ustar 00000000000000// 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 super::*; use alloc::vec::Vec; type MapF = fn(&(K, V)) -> (&K, &V); #[inline] fn map_f(input: &(K, V)) -> (&K, &V) { (&input.0, &input.1) } type MapFMut = fn(&mut (K, V)) -> (&K, &mut V); #[inline] fn map_f_mut(input: &mut (K, V)) -> (&K, &mut V) { (&input.0, &mut input.1) } impl StoreConstEmpty for Vec<(K, V)> { const EMPTY: Vec<(K, V)> = Vec::new(); } impl Store for Vec<(K, V)> { #[inline] fn lm_len(&self) -> usize { self.as_slice().len() } #[inline] fn lm_is_empty(&self) -> bool { self.as_slice().is_empty() } #[inline] fn lm_get(&self, index: usize) -> Option<(&K, &V)> { self.as_slice().get(index).map(map_f) } #[inline] fn lm_last(&self) -> Option<(&K, &V)> { self.as_slice().last().map(map_f) } #[inline] fn lm_binary_search_by(&self, mut cmp: F) -> Result where F: FnMut(&K) -> Ordering, { self.as_slice().binary_search_by(|(k, _)| cmp(k)) } } impl StoreSlice for Vec<(K, V)> { type Slice = [(K, V)]; fn lm_get_range(&self, range: Range) -> Option<&Self::Slice> { self.get(range) } } impl StoreMut for Vec<(K, V)> { #[inline] fn lm_with_capacity(capacity: usize) -> Self { Self::with_capacity(capacity) } #[inline] fn lm_reserve(&mut self, additional: usize) { self.reserve(additional) } #[inline] fn lm_get_mut(&mut self, index: usize) -> Option<(&K, &mut V)> { self.as_mut_slice().get_mut(index).map(map_f_mut) } #[inline] fn lm_push(&mut self, key: K, value: V) { self.push((key, value)) } #[inline] fn lm_insert(&mut self, index: usize, key: K, value: V) { self.insert(index, (key, value)) } #[inline] fn lm_remove(&mut self, index: usize) -> (K, V) { self.remove(index) } #[inline] fn lm_clear(&mut self) { self.clear() } #[inline] fn lm_retain(&mut self, mut predicate: F) where F: FnMut(&K, &V) -> bool, { self.retain(|(k, v)| predicate(k, v)) } } impl StoreFromIterable for Vec<(K, V)> { fn lm_sort_from_iter>(iter: I) -> Self { let iter = iter.into_iter(); let mut container = match iter.size_hint() { (_, Some(upper)) => Self::with_capacity(upper), (lower, None) => Self::with_capacity(lower), }; for (key, value) in iter { if let Some(last) = container.lm_last() { if last.0 >= &key { match container.lm_binary_search_by(|k| k.cmp(&key)) { #[allow(clippy::unwrap_used)] // Index came from binary_search Ok(found) => { let _ = core::mem::replace(container.lm_get_mut(found).unwrap().1, value); } Err(ins) => { container.insert(ins, (key, value)); } } } else { container.push((key, value)) } } else { container.push((key, value)) } } container } } impl<'a, K: 'a, V: 'a> StoreIterable<'a, K, V> for Vec<(K, V)> { type KeyValueIter = core::iter::Map, MapF>; #[inline] fn lm_iter(&'a self) -> Self::KeyValueIter { self.as_slice().iter().map(map_f) } } impl<'a, K: 'a, V: 'a> StoreIterableMut<'a, K, V> for Vec<(K, V)> { type KeyValueIterMut = core::iter::Map, MapFMut>; #[inline] fn lm_iter_mut(&'a mut self) -> Self::KeyValueIterMut { self.as_mut_slice().iter_mut().map(map_f_mut) } } impl StoreIntoIterator for Vec<(K, V)> { type KeyValueIntoIter = alloc::vec::IntoIter<(K, V)>; #[inline] fn lm_into_iter(self) -> Self::KeyValueIntoIter { IntoIterator::into_iter(self) } #[inline] fn lm_extend_end(&mut self, other: Self) { self.extend(other) } #[inline] fn lm_extend_start(&mut self, other: Self) { self.splice(0..0, other); } } impl StoreFromIterator for Vec<(K, V)> {} #[test] fn test_vec_impl() { crate::testing::check_store_full::>(); } litemap-0.7.4/src/testing.rs000064400000000000000000000170561046102023000141120ustar 00000000000000// 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 ). //! Test utilities, primarily targeted to custom LiteMap stores. use crate::store::*; use crate::LiteMap; use alloc::vec::Vec; use core::fmt::Debug; // Test code #[allow(clippy::expect_used)] fn check_equivalence<'a, K, V, S0, S1>(mut a: S0, mut b: S1) where K: Ord + Debug + PartialEq + 'a, V: Debug + PartialEq + 'a, S0: StoreMut + StoreIterable<'a, K, V>, S1: StoreMut + StoreIterable<'a, K, V>, { let len = a.lm_len(); assert_eq!(len, b.lm_len()); if len == 0 { assert!(a.lm_is_empty()); assert!(b.lm_is_empty()); } for i in 0..len { let a_kv = a.lm_get(i); let b_kv = b.lm_get(i); assert!(a_kv.is_some()); assert_eq!(a_kv, b_kv); let a_kv_mut = a.lm_get_mut(i); let b_kv_mut = b.lm_get_mut(i); assert!(a_kv_mut.is_some()); assert_eq!(a_kv_mut, b_kv_mut); } for j in 0..len { let needle = a.lm_get(j).expect("j is in range").0; let a_binary = a.lm_binary_search_by(|k| k.cmp(needle)); let b_binary = a.lm_binary_search_by(|k| k.cmp(needle)); assert_eq!(Ok(j), a_binary); assert_eq!(Ok(j), b_binary); } assert!(a.lm_get(len).is_none()); assert!(b.lm_get(len).is_none()); assert_eq!(a.lm_last(), b.lm_last()); } // Test code #[allow(clippy::expect_used)] fn check_into_iter_equivalence(a: S0, b: S1) where K: Ord + Debug + PartialEq, V: Debug + PartialEq, S0: StoreIntoIterator, S1: StoreIntoIterator, { let a_vec = a.lm_into_iter().collect::>(); let b_vec = b.lm_into_iter().collect::>(); assert_eq!(a_vec, b_vec); } const SORTED_DATA: &[(u32, u64)] = &[ (106, 4816), (147, 9864), (188, 8588), (252, 6031), (434, 2518), (574, 8500), (607, 3756), (619, 4965), (663, 2669), (724, 9211), ]; const RANDOM_DATA: &[(u32, u64)] = &[ (546, 7490), (273, 4999), (167, 8078), (176, 2101), (373, 1304), (339, 9613), (561, 3620), (301, 1214), (483, 4453), (704, 5359), ]; // Test code #[allow(clippy::expect_used)] #[allow(clippy::panic)] fn populate_litemap(map: &mut LiteMap) where S: StoreMut + Debug, { assert_eq!(0, map.len()); assert!(map.is_empty()); for (k, v) in SORTED_DATA.iter() { #[allow(clippy::single_match)] // for clarity match map.try_append(*k, *v) { Some(_) => panic!("appending sorted data: {k:?} to {map:?}"), None => (), // OK }; } assert_eq!(10, map.len()); for (k, v) in RANDOM_DATA.iter() { #[allow(clippy::single_match)] // for clarity match map.try_append(*k, *v) { Some(_) => (), // OK None => panic!("cannot append random data: {k:?} to{map:?}"), }; } assert_eq!(10, map.len()); for (k, v) in RANDOM_DATA.iter() { map.insert(*k, *v); } assert_eq!(20, map.len()); } /// Tests that a litemap that uses the given store as backend has behavior consistent with the /// reference impl. /// /// Call this function in a test with the store impl to test as a valid backend for LiteMap. // Test code #[allow(clippy::expect_used)] pub fn check_store<'a, S>() where S: StoreConstEmpty + StoreMut + StoreIterable<'a, u32, u64> + StoreFromIterator + Clone + Debug + PartialEq + 'a, { let mut litemap_test: LiteMap = LiteMap::new(); assert!(litemap_test.is_empty()); let mut litemap_std = LiteMap::::new(); populate_litemap(&mut litemap_test); populate_litemap(&mut litemap_std); check_equivalence(litemap_test.clone().values, litemap_std.clone().values); litemap_test.retain(|_, v| v % 2 == 0); litemap_std.retain(|_, v| v % 2 == 0); assert_eq!(11, litemap_test.len()); assert_eq!(11, litemap_std.len()); check_equivalence(litemap_test.clone().values, litemap_std.clone().values); litemap_test .remove(&175) .ok_or(()) .expect_err("does not exist"); litemap_test.remove(&147).ok_or(()).expect("exists"); litemap_std .remove(&175) .ok_or(()) .expect_err("does not exist"); litemap_std.remove(&147).ok_or(()).expect("exists"); assert_eq!(10, litemap_test.len()); assert_eq!(10, litemap_std.len()); check_equivalence(litemap_test.clone().values, litemap_std.clone().values); litemap_test.clear(); litemap_std.clear(); check_equivalence(litemap_test.values, litemap_std.values); } /// Similar to [`check_store`] function, but also checks the validitiy of [`StoreIterableMut`] /// trait. // Test code #[allow(clippy::expect_used)] pub fn check_store_full<'a, S>() where S: StoreConstEmpty + StoreIterableMut<'a, u32, u64> + StoreIntoIterator + StoreFromIterator + Clone + Debug + PartialEq + 'a, { let mut litemap_test: LiteMap = LiteMap::new(); assert!(litemap_test.is_empty()); let mut litemap_std = LiteMap::::new(); populate_litemap(&mut litemap_test); populate_litemap(&mut litemap_std); check_equivalence(litemap_test.clone().values, litemap_std.clone().values); check_into_iter_equivalence(litemap_test.clone().values, litemap_std.clone().values); let extras_test = litemap_test.clone(); let extras_test = litemap_test .extend_from_litemap(extras_test) .expect("duplicates"); assert_eq!(extras_test, litemap_test); let extras_std = litemap_std.clone(); check_equivalence(litemap_test.clone().values, litemap_std.clone().values); check_into_iter_equivalence(litemap_test.clone().values, litemap_std.clone().values); litemap_test.retain(|_, v| v % 2 == 0); litemap_std.retain(|_, v| v % 2 == 0); assert_eq!(11, litemap_test.len()); assert_eq!(11, litemap_std.len()); check_equivalence(litemap_test.clone().values, litemap_std.clone().values); check_into_iter_equivalence(litemap_test.clone().values, litemap_std.clone().values); let extras_test = litemap_test .extend_from_litemap(extras_test) .expect("duplicates"); let extras_std = litemap_std .extend_from_litemap(extras_std) .expect("duplicates"); assert_eq!(11, extras_test.len()); assert_eq!(11, extras_std.len()); assert_eq!(20, litemap_test.len()); assert_eq!(20, litemap_std.len()); check_equivalence(litemap_test.clone().values, litemap_std.clone().values); check_into_iter_equivalence(litemap_test.clone().values, litemap_std.clone().values); litemap_test .remove(&175) .ok_or(()) .expect_err("does not exist"); litemap_test.remove(&176).ok_or(()).expect("exists"); litemap_std .remove(&175) .ok_or(()) .expect_err("does not exist"); litemap_std.remove(&176).ok_or(()).expect("exists"); assert_eq!(19, litemap_test.len()); assert_eq!(19, litemap_std.len()); check_equivalence(litemap_test.clone().values, litemap_std.clone().values); check_into_iter_equivalence(litemap_test.clone().values, litemap_std.clone().values); litemap_test.clear(); litemap_std.clear(); check_equivalence(litemap_test.clone().values, litemap_std.clone().values); check_into_iter_equivalence(litemap_test.values, litemap_std.values); } litemap-0.7.4/tests/rkyv.rs000064400000000000000000000055731046102023000140040ustar 00000000000000// 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 litemap::LiteMap; use rkyv::archived_root; use rkyv::check_archived_root; use rkyv::ser::serializers::AllocSerializer; use rkyv::ser::Serializer; use rkyv::util::AlignedBytes; use rkyv::util::AlignedVec; use rkyv::Deserialize; use rkyv::Infallible; const DATA: [(&str, &str); 11] = [ ("ar", "Arabic"), ("bn", "Bangla"), ("ccp", "Chakma"), ("en", "English"), ("es", "Spanish"), ("fr", "French"), ("ja", "Japanese"), ("ru", "Russian"), ("sr", "Serbian"), ("th", "Thai"), ("tr", "Turkish"), ]; const RKYV: AlignedBytes<192> = AlignedBytes([ 74, 97, 112, 97, 110, 101, 115, 101, 97, 114, 0, 0, 0, 0, 0, 2, 65, 114, 97, 98, 105, 99, 0, 6, 98, 110, 0, 0, 0, 0, 0, 2, 66, 97, 110, 103, 108, 97, 0, 6, 99, 99, 112, 0, 0, 0, 0, 3, 67, 104, 97, 107, 109, 97, 0, 6, 101, 110, 0, 0, 0, 0, 0, 2, 69, 110, 103, 108, 105, 115, 104, 7, 101, 115, 0, 0, 0, 0, 0, 2, 83, 112, 97, 110, 105, 115, 104, 7, 102, 114, 0, 0, 0, 0, 0, 2, 70, 114, 101, 110, 99, 104, 0, 6, 106, 97, 0, 0, 0, 0, 0, 2, 8, 0, 0, 0, 144, 255, 255, 255, 114, 117, 0, 0, 0, 0, 0, 2, 82, 117, 115, 115, 105, 97, 110, 7, 115, 114, 0, 0, 0, 0, 0, 2, 83, 101, 114, 98, 105, 97, 110, 7, 116, 104, 0, 0, 0, 0, 0, 2, 84, 104, 97, 105, 0, 0, 0, 4, 116, 114, 0, 0, 0, 0, 0, 2, 84, 117, 114, 107, 105, 115, 104, 7, 80, 255, 255, 255, 11, 0, 0, 0, ]); type LiteMapOfStrings = LiteMap; type TupleVecOfStrings = Vec<(String, String)>; fn generate() -> AlignedVec { let map = DATA .iter() .map(|&(k, v)| (k.to_owned(), v.to_owned())) .collect::(); let mut serializer = AllocSerializer::<4096>::default(); serializer .serialize_value(&map.into_tuple_vec()) .expect("failed to archive test"); serializer.into_serializer().into_inner() } #[test] fn rkyv_serialize() { let serialized = generate(); assert_eq!(RKYV.0, serialized.as_slice()); } #[test] fn rkyv_archive() { let archived = unsafe { archived_root::(&RKYV.0) }; let s = archived[0].1.as_str(); assert_eq!(s, "Arabic"); } #[test] fn rkyv_checked_archive() { let archived = check_archived_root::(&RKYV.0).unwrap(); let s = archived[0].1.as_str(); assert_eq!(s, "Arabic"); } #[test] fn rkyv_deserialize() { let archived = unsafe { archived_root::(&RKYV.0) }; let deserialized = archived.deserialize(&mut Infallible).unwrap(); // Safe because we are deserializing a buffer from a trusted source let deserialized: LiteMapOfStrings = LiteMap::from_sorted_store_unchecked(deserialized); assert_eq!(deserialized.get("tr").map(String::as_str), Some("Turkish")); } litemap-0.7.4/tests/serde.rs000064400000000000000000000011641046102023000141030ustar 00000000000000// 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 litemap::LiteMap; #[test] fn test_ser() { let mut map = LiteMap::new_vec(); map.insert(1, "jat"); map.insert(4, "sei"); map.insert(3, "saam"); map.insert(2, "ji"); let json_string = serde_json::to_string(&map).unwrap(); assert_eq!(json_string, r#"{"1":"jat","2":"ji","3":"saam","4":"sei"}"#); let new_map = serde_json::from_str(&json_string).unwrap(); assert_eq!(map, new_map); } litemap-0.7.4/tests/store.rs000064400000000000000000000072431046102023000141410ustar 00000000000000// 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 litemap::store::*; use litemap::testing::check_store_full; use std::cmp::Ordering; /// A Vec wrapper that leverages the default function impls from `Store` #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] struct VecWithDefaults(Vec); type MapF = fn(&(K, V)) -> (&K, &V); #[inline] fn map_f(input: &(K, V)) -> (&K, &V) { (&input.0, &input.1) } type MapFMut = fn(&mut (K, V)) -> (&K, &mut V); #[inline] fn map_f_mut(input: &mut (K, V)) -> (&K, &mut V) { (&input.0, &mut input.1) } impl StoreConstEmpty for VecWithDefaults<(K, V)> { const EMPTY: VecWithDefaults<(K, V)> = VecWithDefaults(Vec::new()); } impl Store for VecWithDefaults<(K, V)> { #[inline] fn lm_len(&self) -> usize { self.0.as_slice().len() } // leave lm_is_empty as default #[inline] fn lm_get(&self, index: usize) -> Option<(&K, &V)> { self.0.as_slice().get(index).map(map_f) } // leave lm_last as default #[inline] fn lm_binary_search_by(&self, mut cmp: F) -> Result where F: FnMut(&K) -> Ordering, { self.0.as_slice().binary_search_by(|(k, _)| cmp(k)) } } impl StoreFromIterable for VecWithDefaults<(K, V)> { fn lm_sort_from_iter>(iter: I) -> Self { let v: Vec<_> = Vec::lm_sort_from_iter(iter); Self(v) } } impl StoreMut for VecWithDefaults<(K, V)> { #[inline] fn lm_with_capacity(capacity: usize) -> Self { Self(Vec::with_capacity(capacity)) } #[inline] fn lm_reserve(&mut self, additional: usize) { self.0.reserve(additional) } #[inline] fn lm_get_mut(&mut self, index: usize) -> Option<(&K, &mut V)> { self.0.as_mut_slice().get_mut(index).map(map_f_mut) } #[inline] fn lm_push(&mut self, key: K, value: V) { self.0.push((key, value)) } #[inline] fn lm_insert(&mut self, index: usize, key: K, value: V) { self.0.insert(index, (key, value)) } #[inline] fn lm_remove(&mut self, index: usize) -> (K, V) { self.0.remove(index) } #[inline] fn lm_clear(&mut self) { self.0.clear() } // leave lm_retain as default } impl<'a, K: 'a, V: 'a> StoreIterable<'a, K, V> for VecWithDefaults<(K, V)> { type KeyValueIter = core::iter::Map, MapF>; #[inline] fn lm_iter(&'a self) -> Self::KeyValueIter { self.0.as_slice().iter().map(map_f) } } impl<'a, K: 'a, V: 'a> StoreIterableMut<'a, K, V> for VecWithDefaults<(K, V)> { type KeyValueIterMut = core::iter::Map, MapFMut>; #[inline] fn lm_iter_mut(&'a mut self) -> Self::KeyValueIterMut { self.0.as_mut_slice().iter_mut().map(map_f_mut) } } impl StoreIntoIterator for VecWithDefaults<(K, V)> { type KeyValueIntoIter = std::vec::IntoIter<(K, V)>; #[inline] fn lm_into_iter(self) -> Self::KeyValueIntoIter { IntoIterator::into_iter(self.0) } // leave lm_extend_end as default // leave lm_extend_start as default } impl std::iter::FromIterator for VecWithDefaults { fn from_iter>(iter: I) -> Self { Self(Vec::from_iter(iter)) } } impl StoreFromIterator for VecWithDefaults<(K, V)> {} #[test] fn test_default_impl() { check_store_full::>(); }