chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

1
vendor/litemap/.cargo-checksum.json vendored Normal file
View File

@@ -0,0 +1 @@
{"files":{".cargo_vcs_info.json":"2bb5e9625612e40617117c70a70b5eed08654e39b80fa1a1fb32370554a11ef4","Cargo.lock":"1efdc485a6cdb2311f35819d08c814d250269eff282e38148604a24989c3426d","Cargo.toml":"5e99a93010ba9456fd86068486d67f28756956a39c495b4b6707e4c684694894","Cargo.toml.orig":"77f3634618a55272ffda9c7e680b935d43ade5d5fe903d2978c5e3069c4e9247","LICENSE":"f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2","README.md":"34cd913e9410be17d4f8ada19fb1d3660d8415e2e92b59ad2bd38e30f18b1de3","benches/litemap.rs":"72bc3e9b2fadd9fd2cf9fb45bb305ce0aa7fa47c12be11c53a4ebacbccf2cb0c","examples/language_names_hash_map.rs":"fdc55380773f37c3ef0b5c6f4c1cedcfc446f1df39a55e011c5b69784b2fd528","examples/language_names_lite_map.rs":"b00b8b2e6dc6384296617b3db427a408a898d239cf1f4f3f6ae4daf9031c1e94","examples/litemap_bincode.rs":"73ef1a6160f8af9c1d804a2963a2e947ab6e4be7d8deda29b7656ecd8125d3b4","examples/litemap_postcard.rs":"e016fdb56640d2292e2981b2d3e313b8df16b2272787829189a3f736d84d525b","src/databake.rs":"e6e256164b6a3b6567cb888cb433e104cda84523ae48b944f8207556d925e0c1","src/lib.rs":"7e1c202d1580a68f8e5723e862522519d6577ac17604c0793851dd43fc5d0716","src/map.rs":"e9c6c10c8897bbb11d03964fe79cc1060f673cae22864bce0da43a3cad077ba6","src/serde.rs":"ef767493beb0d72421730d77e8b36e685ae1f13de202c3020dacc05f1cf4ed8f","src/serde_helpers.rs":"518441e8d56778187b6652519e5a63e2f1a331c8a6b1274ffcbd931d8c0defa2","src/store/mod.rs":"cfccec951bd9792fe7a8e2186d649815fc437cc5e15f62b15ab9db6c79d89929","src/store/slice_impl.rs":"e5bd0d4bfd7ab5957ec6979f2a29c12f29ba199b4c17a9cf64bb3866e3b6a00e","src/store/vec_impl.rs":"558c0502b93ffff9c2f381e0626ec8a707bff350f547f007b8464d35b447e827","src/testing.rs":"40b36a138bff27ee25e3d2829a35ea9a147ed67630bdc832fe5f3e716d958b4a","tests/rkyv.rs":"4490722330b801bff654594aec29526a7e6fb67744e6b7c1e03ac238e4128e12","tests/serde.rs":"0051274f8490c5837d88447bf72fc7266e970fa95c6e4ca540eeba45b7947ce6","tests/store.rs":"ac47119be831db60e360d2faa9788becf68270c497c80507a809a344ad5f5179"},"package":"6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"}

6
vendor/litemap/.cargo_vcs_info.json vendored Normal file
View File

@@ -0,0 +1,6 @@
{
"git": {
"sha1": "29dfe2790b6cfdab94ca6a6b69f58ce54802dbf7"
},
"path_in_vcs": "utils/litemap"
}

1008
vendor/litemap/Cargo.lock generated vendored Normal file

File diff suppressed because it is too large Load Diff

148
vendor/litemap/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,148 @@
# 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.82"
name = "litemap"
version = "0.8.1"
authors = ["The ICU4X Project Developers"]
build = false
include = [
"data/**/*",
"src/**/*",
"examples/**/*",
"benches/**/*",
"tests/**/*",
"Cargo.toml",
"LICENSE",
"README.md",
"build.rs",
]
autolib = false
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.workspaces]
independent = true
[package.metadata.docs.rs]
all-features = true
[features]
alloc = []
databake = ["dep:databake"]
default = ["alloc"]
serde = [
"dep:serde_core",
"alloc",
]
testing = ["alloc"]
yoke = ["dep:yoke"]
[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_core]
version = "1.0.220"
features = ["alloc"]
optional = true
default-features = false
[dependencies.yoke]
version = "0.8.0"
features = ["derive"]
optional = true
default-features = false
[dev-dependencies.bincode]
version = "1.3.1"
[dev-dependencies.postcard]
version = "1.0.3"
features = ["use-std"]
default-features = false
[dev-dependencies.rand]
version = "0.9"
[dev-dependencies.rkyv]
version = "0.7"
features = ["validation"]
[dev-dependencies.serde_core]
version = "1.0.220"
default-features = false
[dev-dependencies.serde_json]
version = "1.0.45"
[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies.criterion]
version = "0.5.0"

46
vendor/litemap/LICENSE vendored Normal file
View File

@@ -0,0 +1,46 @@
UNICODE 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.

51
vendor/litemap/README.md vendored Normal file
View File

@@ -0,0 +1,51 @@
# litemap [![crates.io](https://img.shields.io/crates/v/litemap)](https://crates.io/crates/litemap)
<!-- cargo-rdme start -->
## `litemap`
`litemap` is a crate providing [`LiteMap`], a highly simplistic "flat" key-value map
based off of a single sorted vector.
The main 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.
### Performance characteristics
[`LiteMap`] is a data structure with similar characteristics as [`std::collections::BTreeMap`] but
with slightly different trade-offs as it's implemented on top of a flat storage (e.g. Vec).
* [`LiteMap`] iteration is generally faster than `BTreeMap` because of the flat storage.
* [`LiteMap`] can be pre-allocated whereas `BTreeMap` can't.
* [`LiteMap`] has a smaller memory footprint than `BTreeMap` for small collections (< 20 items).
* Lookup is `O(log(n))` like `BTreeMap`.
* Insertion is generally `O(n)`, but optimized to `O(1)` if the new item sorts greater than the current items. In `BTreeMap` it's `O(log(n))`.
* Deletion is `O(n)` whereas `BTreeMap` is `O(log(n))`.
* Bulk operations like `from_iter`, `extend` and deserialization have an optimized `O(n)` path
for inputs that are ordered and `O(n*log(n))` complexity otherwise.
### 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<K,+V,+S>
[`Vec`]: alloc::vec::Vec
<!-- cargo-rdme end -->
## More Information
For more information on development, authorship, contributing etc. please visit [`ICU4X home page`](https://github.com/unicode-org/icu4x).

218
vendor/litemap/benches/litemap.rs vendored Normal file
View File

@@ -0,0 +1,218 @@
// 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;
use rand::seq::SliceRandom;
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<u8> {
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);
bench_from_iter(c);
bench_from_iter_rand_large(c);
bench_from_iter_sorted(c);
bench_from_iter_large_sorted(c);
bench_extend_rand(c);
bench_extend_rand_dups(c);
bench_extend_from_litemap_rand(c);
}
fn build_litemap(large: bool) -> LiteMap<String, String> {
let mut map: LiteMap<String, String> = 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<String, String> = 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<String, String> = postcard::from_bytes(black_box(&buf)).unwrap();
assert_eq!(map.get("iu3333"), Some(&"Inuktitut".to_owned()));
});
});
}
fn bench_from_iter(c: &mut Criterion) {
c.bench_function("litemap/from_iter_rand/small", |b| {
let mut ff = build_litemap(false).into_iter().collect::<Vec<_>>();
ff[..].shuffle(&mut rand::rng());
b.iter(|| {
let map: LiteMap<&String, &String> = LiteMap::from_iter(ff.iter().map(|(k, v)| (k, v)));
black_box(map)
})
});
}
fn bench_from_iter_rand_large(c: &mut Criterion) {
c.bench_function("litemap/from_iter_rand/large", |b| {
let mut ff = build_litemap(true).into_iter().collect::<Vec<_>>();
ff[..].shuffle(&mut rand::rng());
b.iter(|| {
let map: LiteMap<&String, &String> = LiteMap::from_iter(ff.iter().map(|(k, v)| (k, v)));
black_box(map)
})
});
}
fn bench_from_iter_sorted(c: &mut Criterion) {
c.bench_function("litemap/from_iter_sorted/small", |b| {
let ff = build_litemap(false).into_iter().collect::<Vec<_>>();
b.iter(|| {
let map: LiteMap<&String, &String> = LiteMap::from_iter(ff.iter().map(|(k, v)| (k, v)));
black_box(map)
})
});
}
fn bench_from_iter_large_sorted(c: &mut Criterion) {
c.bench_function("litemap/from_iter_sorted/large", |b| {
let ff = build_litemap(true).into_iter().collect::<Vec<_>>();
b.iter(|| {
let map: LiteMap<&String, &String> = LiteMap::from_iter(ff.iter().map(|(k, v)| (k, v)));
black_box(map)
})
});
}
fn bench_extend_rand(c: &mut Criterion) {
c.bench_function("litemap/extend_rand/large", |b| {
let mut ff = build_litemap(true).into_iter().collect::<Vec<_>>();
ff[..].shuffle(&mut rand::rng());
b.iter(|| {
let mut map: LiteMap<&String, &String> = LiteMap::with_capacity(0);
let mut iter = ff.iter().map(|(k, v)| (k, v));
let step = ff.len().div_ceil(10);
for _ in 0..10 {
map.extend(iter.by_ref().take(step));
}
black_box(map)
})
});
}
fn bench_extend_rand_dups(c: &mut Criterion) {
c.bench_function("litemap/extend_rand_dups/large", |b| {
let mut ff = build_litemap(true).into_iter().collect::<Vec<_>>();
ff[..].shuffle(&mut rand::rng());
b.iter(|| {
let mut map: LiteMap<&String, &String> = LiteMap::with_capacity(0);
for _ in 0..2 {
let mut iter = ff.iter().map(|(k, v)| (k, v));
let step = ff.len().div_ceil(10);
for _ in 0..10 {
map.extend(iter.by_ref().take(step));
}
}
black_box(map)
})
});
}
fn bench_extend_from_litemap_rand(c: &mut Criterion) {
c.bench_function("litemap/extend_from_litemap_rand/large", |b| {
let mut ff = build_litemap(true).into_iter().collect::<Vec<_>>();
ff[..].shuffle(&mut rand::rng());
b.iter(|| {
let mut map: LiteMap<&String, &String> = LiteMap::with_capacity(0);
let mut iter = ff.iter().map(|(k, v)| (k, v));
let step = ff.len().div_ceil(10);
for _ in 0..10 {
let tmp: LiteMap<&String, &String> = LiteMap::from_iter(iter.by_ref().take(step));
map.extend_from_litemap(tmp);
}
black_box(map)
})
});
}
fn bench_lookup(c: &mut Criterion) {
let map: LiteMap<String, String> = 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<String, String> = 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);

View File

@@ -0,0 +1,36 @@
// 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::<Language, &str>::from_iter(DATA);
assert!(map.len() == 11);
assert!(map.get(&language!("th")) == Some(&"Thai"));
assert!(!map.contains_key(&language!("de")));
}

View File

@@ -0,0 +1,36 @@
// 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::<Language, &str>::from_iter(DATA);
assert!(map.len() == 11);
assert!(map.get(&language!("th")) == Some(&"Thai"));
assert!(map.get(&language!("de")).is_none());
}

View File

@@ -0,0 +1,60 @@
// 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"));
}

View File

@@ -0,0 +1,54 @@
// 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"));
}

81
vendor/litemap/src/databake.rs vendored Normal file
View File

@@ -0,0 +1,81 @@
// 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<usize, String, Vec<_>> = 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<usize, &str, Vec<_>> =
/// litemap_alloc.to_borrowed_values();
/// let litemap_slice: LiteMap<usize, &str, &[_]> = litemap_str.as_sliced();
///
/// // The bake will now work for const construction:
/// let mut ctx = Default::default();
/// println!(
/// "const FOO: LiteMap<usize, &str, &[(usize, &str)]> = {};",
/// litemap_slice.bake(&ctx)
/// );
/// ```
impl<K, V, S> Bake for LiteMap<K, V, S>
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<usize, &str, &[(usize, &str)]>,
const,
crate::LiteMap::from_sorted_store_unchecked(
&[
(1usize, "one"),
(2usize, "two"),
(10usize, "ten"),
]
),
litemap
);
// Non-const construction:
test_bake!(
LiteMap<usize, String, Vec<(usize, String)>>,
crate::LiteMap::from_sorted_store_unchecked(
alloc::vec![
(1usize, "one".to_owned()),
(2usize, "two".to_owned()),
(10usize, "ten".to_owned()),
]
),
litemap
);
}

83
vendor/litemap/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,83 @@
// 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 main 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.
//!
//! ## Performance characteristics
//!
//! [`LiteMap`] is a data structure with similar characteristics as [`std::collections::BTreeMap`] but
//! with slightly different trade-offs as it's implemented on top of a flat storage (e.g. Vec).
//!
//! * [`LiteMap`] iteration is generally faster than `BTreeMap` because of the flat storage.
//! * [`LiteMap`] can be pre-allocated whereas `BTreeMap` can't.
//! * [`LiteMap`] has a smaller memory footprint than `BTreeMap` for small collections (< 20 items).
//! * Lookup is `O(log(n))` like `BTreeMap`.
//! * Insertion is generally `O(n)`, but optimized to `O(1)` if the new item sorts greater than the current items. In `BTreeMap` it's `O(log(n))`.
//! * Deletion is `O(n)` whereas `BTreeMap` is `O(log(n))`.
//! * Bulk operations like `from_iter`, `extend` and deserialization have an optimized `O(n)` path
//! for inputs that are ordered and `O(n*log(n))` complexity otherwise.
//!
//! ## 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<K,+V,+S>
//! [`Vec`]: alloc::vec::Vec
// https://github.com/unicode-org/icu4x/blob/main/documents/process/boilerplate.md#library-annotations
#![cfg_attr(not(any(test, doc)), no_std)]
#![cfg_attr(
not(test),
deny(
clippy::indexing_slicing,
clippy::unwrap_used,
clippy::expect_used,
clippy::panic,
clippy::exhaustive_structs,
clippy::exhaustive_enums,
clippy::trivially_copy_pass_by_ref,
missing_debug_implementations,
)
)]
// for intra doc links
#[cfg(doc)]
extern crate std;
#[cfg(feature = "alloc")]
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::{Entry, LiteMap, OccupiedEntry, VacantEntry};

1663
vendor/litemap/src/map.rs vendored Normal file

File diff suppressed because it is too large Load Diff

245
vendor/litemap/src/serde.rs vendored Normal file
View File

@@ -0,0 +1,245 @@
// 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 alloc::vec::Vec;
use core::fmt;
use core::marker::PhantomData;
use serde_core::{
de::{MapAccess, SeqAccess, Visitor},
ser::{SerializeMap, SerializeSeq},
Deserialize, Deserializer, Serialize, Serializer,
};
impl<K, V, R> Serialize for LiteMap<K, V, R>
where
K: Serialize,
V: Serialize,
R: Store<K, V>,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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 sequence of tuples instead
if serializer.is_human_readable() {
let k_is_num_or_string = self
.values
.lm_get(0)
.is_some_and(|(k, _)| super::serde_helpers::is_num_or_string(k));
if !k_is_num_or_string {
let mut seq = serializer.serialize_seq(Some(self.len()))?;
// Note that we can't require StoreIterable for R, see below.
for index in 0..self.len() {
#[expect(clippy::unwrap_used)] // looping over 0..len
seq.serialize_element(&self.get_indexed(index).unwrap())?;
}
return seq.end();
}
// continue to regular serialization
}
// Note that we can't require StoreIterable for R, because the Higher-Rank Trait Bounds (HRTBs)
// `R: for<'a> StoreIterable<'a, K, V>` would end up being too strict for some use cases
// as it would require Self, K and V to be 'static. See https://github.com/rust-lang/types-team/blob/master/minutes/2022-07-08-implied-bounds-and-wf-checking.md#problem-fora-shouldnt-really-mean-for-all-a
// Instead, we require only R: Store and manually iterate over the items.
// For some R types this is equivalent to StoreIterable after compiler optimizations but retains
// flexibility for other types.
let mut map = serializer.serialize_map(Some(self.len()))?;
for index in 0..self.len() {
#[expect(clippy::unwrap_used)] // looping over 0..len
let (k, v) = self.get_indexed(index).unwrap();
map.serialize_entry(k, v)?;
}
map.end()
}
}
/// Modified example from https://serde.rs/deserialize-map.html
#[expect(clippy::type_complexity)]
struct LiteMapVisitor<K, V, R> {
marker: PhantomData<fn() -> LiteMap<K, V, R>>,
}
impl<K, V, R> LiteMapVisitor<K, V, R> {
fn new() -> Self {
Self {
marker: PhantomData,
}
}
}
impl<'de, K, V, R> Visitor<'de> for LiteMapVisitor<K, V, R>
where
K: Deserialize<'de> + Ord,
V: Deserialize<'de>,
R: StoreBulkMut<K, V>,
{
type Value = LiteMap<K, V, R>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a map produced by LiteMap")
}
fn visit_seq<S>(self, mut access: S) -> Result<Self::Value, S::Error>
where
S: SeqAccess<'de>,
{
// See visit_map for an explanation of the fast-path and out-of-order handling
let mut map = LiteMap::with_capacity(access.size_hint().unwrap_or(0));
let mut out_of_order = Vec::new();
while let Some((key, value)) = access.next_element()? {
if let Some((key, value)) = map.try_append(key, value) {
out_of_order.push((key, value));
}
}
if !out_of_order.is_empty() {
map.extend(out_of_order);
}
Ok(map)
}
fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let mut map = LiteMap::with_capacity(access.size_hint().unwrap_or(0));
let mut out_of_order = Vec::new();
// 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. Otherwise, collect
// out of order items and extend the map with them later. This way, we give
// the implementation an opportunity to avoid quadratic costs from calling
// insert() with out of order items.
// Handling ordered inputs first 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) {
out_of_order.push((key, value));
}
}
if !out_of_order.is_empty() {
map.extend(out_of_order);
}
Ok(map)
}
}
impl<'de, K, V, R> Deserialize<'de> for LiteMap<K, V, R>
where
K: Ord + Deserialize<'de>,
V: Deserialize<'de>,
R: StoreBulkMut<K, V>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
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<u32, String> {
[
(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<u32, String> = 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<u32, String> = 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);
}
/// Test that a LiteMap<_, _, Vec> is deserialized with an exact capacity
/// if the deserializer provides a size hint information, like postcard here.
#[test]
fn test_deserialize_capacity() {
for len in 0..50 {
let mut map = (0..len).map(|i| (i, i.to_string())).collect::<Vec<_>>();
let postcard = postcard::to_stdvec(&map).unwrap();
let deserialized: LiteMap<u32, String> = postcard::from_bytes(&postcard).unwrap();
assert_eq!(deserialized.values.capacity(), len);
assert_eq!(deserialized.values.len(), len);
// again, but with a shuffled map
rand::seq::SliceRandom::shuffle(&mut map[..], &mut rand::rng());
let postcard = postcard::to_stdvec(&map).unwrap();
let deserialized: LiteMap<u32, String> = postcard::from_bytes(&postcard).unwrap();
assert_eq!(deserialized.values.capacity(), len);
assert_eq!(deserialized.values.len(), len);
}
}
}

164
vendor/litemap/src/serde_helpers.rs vendored Normal file
View File

@@ -0,0 +1,164 @@
// 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_core::ser::{Impossible, Serialize, Serializer};
pub fn is_num_or_string<T: Serialize + ?Sized>(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_core::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<Self::Ok, Self::Error> {
Ok(())
}
fn serialize_unit_variant(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
) -> Result<Self::Ok, Self::Error> {
Ok(())
}
fn serialize_newtype_struct<T: Serialize + ?Sized>(
self,
_name: &'static str,
value: &T,
) -> Result<Self::Ok, Self::Error> {
// Recurse
value.serialize(self)
}
fn serialize_bool(self, _value: bool) -> Result<Self::Ok, Self::Error> {
Err(core::fmt::Error)
}
fn serialize_i8(self, _value: i8) -> Result<Self::Ok, Self::Error> {
Ok(())
}
fn serialize_i16(self, _value: i16) -> Result<Self::Ok, Self::Error> {
Ok(())
}
fn serialize_i32(self, _value: i32) -> Result<Self::Ok, Self::Error> {
Ok(())
}
fn serialize_i64(self, _value: i64) -> Result<Self::Ok, Self::Error> {
Ok(())
}
fn serialize_i128(self, _value: i128) -> Result<Self::Ok, Self::Error> {
Ok(())
}
fn serialize_u8(self, _value: u8) -> Result<Self::Ok, Self::Error> {
Ok(())
}
fn serialize_u16(self, _value: u16) -> Result<Self::Ok, Self::Error> {
Ok(())
}
fn serialize_u32(self, _value: u32) -> Result<Self::Ok, Self::Error> {
Ok(())
}
fn serialize_u64(self, _value: u64) -> Result<Self::Ok, Self::Error> {
Ok(())
}
fn serialize_u128(self, _value: u128) -> Result<Self::Ok, Self::Error> {
Ok(())
}
fn serialize_f32(self, _value: f32) -> Result<Self::Ok, Self::Error> {
Err(core::fmt::Error)
}
fn serialize_f64(self, _value: f64) -> Result<Self::Ok, Self::Error> {
Err(core::fmt::Error)
}
fn serialize_char(self, _value: char) -> Result<Self::Ok, Self::Error> {
Ok(())
}
fn serialize_bytes(self, _value: &[u8]) -> Result<Self::Ok, Self::Error> {
Err(core::fmt::Error)
}
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
Err(core::fmt::Error)
}
fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
Err(core::fmt::Error)
}
fn serialize_newtype_variant<T: Serialize + ?Sized>(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_value: &T,
) -> Result<Self::Ok, Self::Error> {
Err(core::fmt::Error)
}
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
Err(core::fmt::Error)
}
fn serialize_some<T: Serialize + ?Sized>(
self,
_value: &T,
) -> Result<Self::Ok, Self::Error> {
Err(core::fmt::Error)
}
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
Err(core::fmt::Error)
}
fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
Err(core::fmt::Error)
}
fn serialize_tuple_struct(
self,
_name: &'static str,
_len: usize,
) -> Result<Self::SerializeTupleStruct, Self::Error> {
Err(core::fmt::Error)
}
fn serialize_tuple_variant(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_len: usize,
) -> Result<Self::SerializeTupleVariant, Self::Error> {
Err(core::fmt::Error)
}
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
Err(core::fmt::Error)
}
fn serialize_struct(
self,
_name: &'static str,
_len: usize,
) -> Result<Self::SerializeStruct, Self::Error> {
Err(core::fmt::Error)
}
fn serialize_struct_variant(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_len: usize,
) -> Result<Self::SerializeStructVariant, Self::Error> {
Err(core::fmt::Error)
}
fn collect_str<T: core::fmt::Display + ?Sized>(
self,
_value: &T,
) -> Result<Self::Ok, Self::Error> {
Ok(())
}
}
k.serialize(MapKeySerializerDryRun).is_ok()
}

176
vendor/litemap/src/store/mod.rs vendored Normal file
View File

@@ -0,0 +1,176 @@
// 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<K: ?Sized, V: ?Sized> {
/// 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<K: ?Sized, V: ?Sized>: 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<F>(&self, cmp: F) -> Result<usize, usize>
where
F: FnMut(&K) -> Ordering;
}
pub trait StoreFromIterable<K, V>: Store<K, V> {
/// Create a sorted store from `iter`.
fn lm_sort_from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self;
}
pub trait StoreSlice<K: ?Sized, V: ?Sized>: Store<K, V> {
type Slice: ?Sized;
fn lm_get_range(&self, range: Range<usize>) -> Option<&Self::Slice>;
}
pub trait StoreMut<K, V>: Store<K, V> {
/// 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);
}
pub trait StoreBulkMut<K, V>: StoreMut<K, V> {
/// Retains items satisfying a predicate in this store.
fn lm_retain<F>(&mut self, predicate: F)
where
F: FnMut(&K, &V) -> bool;
/// Extends this store with items from an iterator.
fn lm_extend<I>(&mut self, other: I)
where
I: IntoIterator<Item = (K, V)>;
}
/// Iterator methods for the LiteMap store.
pub trait StoreIterable<'a, K: 'a + ?Sized, V: 'a + ?Sized>: Store<K, V> {
type KeyValueIter: Iterator<Item = (&'a K, &'a V)> + 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<K, V> + StoreIterable<'a, K, V> {
type KeyValueIterMut: Iterator<Item = (&'a K, &'a mut V)> + 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<K, V>: StoreMut<K, V> {
type KeyValueIntoIter: Iterator<Item = (K, V)>;
/// 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<K, V>: FromIterator<(K, V)> {}

63
vendor/litemap/src/store/slice_impl.rs vendored Normal file
View File

@@ -0,0 +1,63 @@
// 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<K, V> = fn(&(K, V)) -> (&K, &V);
#[inline]
fn map_f<K, V>(input: &(K, V)) -> (&K, &V) {
(&input.0, &input.1)
}
impl<'a, K: 'a, V: 'a> StoreConstEmpty<K, V> for &'a [(K, V)] {
const EMPTY: &'a [(K, V)] = &[];
}
impl<'a, K: 'a, V: 'a> Store<K, V> 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<F>(&self, mut cmp: F) -> Result<usize, usize>
where
F: FnMut(&K) -> Ordering,
{
self.binary_search_by(|(k, _)| cmp(k))
}
}
impl<K, V> StoreSlice<K, V> for &[(K, V)] {
type Slice = [(K, V)];
fn lm_get_range(&self, range: Range<usize>) -> 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<core::slice::Iter<'a, (K, V)>, MapF<K, V>>;
#[inline]
fn lm_iter(&'a self) -> Self::KeyValueIter {
self.iter().map(map_f)
}
}

306
vendor/litemap/src/store/vec_impl.rs vendored Normal file
View File

@@ -0,0 +1,306 @@
// 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<K, V> = fn(&(K, V)) -> (&K, &V);
#[inline]
fn map_f<K, V>(input: &(K, V)) -> (&K, &V) {
(&input.0, &input.1)
}
type MapFMut<K, V> = fn(&mut (K, V)) -> (&K, &mut V);
#[inline]
fn map_f_mut<K, V>(input: &mut (K, V)) -> (&K, &mut V) {
(&input.0, &mut input.1)
}
impl<K, V> StoreConstEmpty<K, V> for Vec<(K, V)> {
const EMPTY: Vec<(K, V)> = Vec::new();
}
impl<K, V> Store<K, V> 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<F>(&self, mut cmp: F) -> Result<usize, usize>
where
F: FnMut(&K) -> Ordering,
{
self.as_slice().binary_search_by(|(k, _)| cmp(k))
}
}
impl<K, V> StoreSlice<K, V> for Vec<(K, V)> {
type Slice = [(K, V)];
fn lm_get_range(&self, range: Range<usize>) -> Option<&Self::Slice> {
self.get(range)
}
}
impl<K, V> StoreMut<K, V> 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()
}
}
impl<K: Ord, V> StoreBulkMut<K, V> for Vec<(K, V)> {
#[inline]
fn lm_retain<F>(&mut self, mut predicate: F)
where
F: FnMut(&K, &V) -> bool,
{
self.retain(|(k, v)| predicate(k, v))
}
/// Extends this store with items from an iterator.
///
/// It uses a two-pass (sort + dedup) approach to avoid any potential quadratic costs.
///
/// The asymptotic worst case complexity is O((n + m) log(n + m)), where `n`
/// is the number of elements already in `self` and `m` is the number of elements
/// in the iterator. The best case complexity is O(m), when the input iterator is
/// already sorted, keys aren't duplicated and all keys sort after the existing ones.
#[inline]
fn lm_extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = (K, V)>,
K: Ord,
{
// First N elements in self that are already sorted and not duplicated.
let mut sorted_len = self.len();
// Use Vec::extend as it has a specialized code for slice and trusted-len iterators.
self.extend(iter);
// `sorted_len` is the length of the sorted run before extension
// window slice `w` is guaranteed to have a length of 2.
#[expect(clippy::indexing_slicing)]
{
// Count new elements that are sorted and non-duplicated.
// Starting from the end of the existing sorted run, if any.
// Thus, start the slice at sorted_len.saturating_sub(1).
sorted_len += self[sorted_len.saturating_sub(1)..]
.windows(2)
.take_while(|w| w[0].0 < w[1].0)
.count();
}
// `windows(2)` only yields `slice len - 1` times, or none if the slice is empty.
// In other words, the first extended element of the slice won't be counted as sorted
// if self was initially empty (sorted_len == 0). We adjust this by adding 1 if the
// original slice was empty but became not empty after extend.
sorted_len += (sorted_len == 0 && !self.is_empty()) as usize;
// If everything was in order, we're done
if sorted_len >= self.len() {
return;
}
// Use stable sort to keep relative order of duplicates.
self.sort_by(|a, b| a.0.cmp(&b.0));
// Deduplicate by keeping the last element of the run in the first slice.
let (dedup, _merged_dup) = partition_dedup_by(self);
sorted_len = dedup.len();
self.truncate(sorted_len);
}
}
/// Moves all but the _last_ of consecutive elements to the end of the slice satisfying
/// equality on K.
///
/// Returns two slices. The first contains no consecutive repeated elements.
/// The second contains all the duplicates in no specified order.
///
/// This is based on std::slice::partition_dedup_by (currently unstable) but retains the
/// _last_ element of the duplicate run in the first slice (instead of first).
#[inline]
#[expect(clippy::type_complexity)]
fn partition_dedup_by<K: Eq, V>(v: &mut [(K, V)]) -> (&mut [(K, V)], &mut [(K, V)]) {
// Although we have a mutable reference to `self`, we cannot make
// *arbitrary* changes. The comparison could panic, so we
// must ensure that the slice is in a valid state at all times.
//
// The way that we handle this is by using swaps; we iterate
// over all the elements, swapping as we go so that at the end
// the elements we wish to keep are in the front, and those we
// wish to reject are at the back. We can then split the slice.
// This operation is still `O(n)`.
//
// Example:
// Assume (K, V) is (char, u8):
//
// We start in this state, where `r` represents "next
// read" and `w` represents "next_write".
//
// r
// | a,0 | b,0 | b,1 | c,0 | d,0 | d,1 |
// w
//
// Comparing self[r] against self[w-1], this is not a duplicate, so
// we swap self[r] and self[w] (no effect as r==w) and then increment both
// r and w, leaving us with:
//
// r
// | a,0 | b,0 | b,1 | c,0 | d,0 | d,0 |
// w
//
// Comparing self[r] against self[w-1], this value is a duplicate,
// we swap self[r] and self[w-1] and then increment `r`:
//
// r
// | a,0 | b,1 | b,0 | c,0 | d,0 | d,1 |
// w
//
// Comparing self[r] against self[w-1], this is not a duplicate,
// so swap self[r] and self[w] and advance r and w:
//
// r
// | a,0 | b,1 | c,0 | b,0 | d,0 | d,1 |
// w
//
// Comparing self[r] against self[w-1], this is not a duplicate,
// so swap self[r] and self[w] and advance r and w:
//
// r
// | a,0 | b,1 | c,0 | d,0 | b,0 | d,1 |
// w
//
// Comparing self[r] against self[w-1], this value is a duplicate,
// we swap self[r] and self[w-1] and then increment `r`:
// r
// | a,0 | b,1 | c,0 | d,1 | b,0 | d,0 |
// w
//
// End of slice, as r > len. Split at w.
if v.len() <= 1 {
return (v, &mut []);
}
let mut read_idx: usize = 1;
let mut write_idx: usize = 1;
while let Some((before_read, [read, ..])) = v.split_at_mut_checked(read_idx) {
// First, `read_idx >= write_idx` is always true as `read_idx` is always incremented
// whereas `write_idx` is only incremented when a distinct element is found.
// Second, before_read is always at least 1 length due to read_idx being initialized to 1.
// Thus it is safe to index before_read with `write_idx - 1`.
#[expect(clippy::indexing_slicing)]
let prev_write = &mut before_read[write_idx - 1];
if read.0 == prev_write.0 {
core::mem::swap(read, prev_write);
} else {
// Equivalent to checking if write_idx == read_idx
if let Some(write) = before_read.get_mut(write_idx) {
core::mem::swap(read, write);
}
write_idx += 1;
}
read_idx += 1;
}
v.split_at_mut(write_idx)
}
impl<K: Ord, V> StoreFromIterable<K, V> for Vec<(K, V)> {
fn lm_sort_from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
let mut v = Self::new();
v.lm_extend(iter);
v
}
}
impl<'a, K: 'a, V: 'a> StoreIterable<'a, K, V> for Vec<(K, V)> {
type KeyValueIter = core::iter::Map<core::slice::Iter<'a, (K, V)>, MapF<K, V>>;
#[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<core::slice::IterMut<'a, (K, V)>, MapFMut<K, V>>;
#[inline]
fn lm_iter_mut(&'a mut self) -> Self::KeyValueIterMut {
self.as_mut_slice().iter_mut().map(map_f_mut)
}
}
impl<K, V> StoreIntoIterator<K, V> 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<K, V> StoreFromIterator<K, V> for Vec<(K, V)> {}
#[test]
fn test_vec_impl() {
crate::testing::check_store_full::<Vec<(u32, u64)>>();
}

296
vendor/litemap/src/testing.rs vendored Normal file
View File

@@ -0,0 +1,296 @@
// 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
#[expect(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<K, V> + StoreIterable<'a, K, V>,
S1: StoreMut<K, V> + 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
fn check_into_iter_equivalence<K, V, S0, S1>(a: S0, b: S1)
where
K: Ord + Debug + PartialEq,
V: Debug + PartialEq,
S0: StoreIntoIterator<K, V>,
S1: StoreIntoIterator<K, V>,
{
let a_vec = a.lm_into_iter().collect::<Vec<_>>();
let b_vec = b.lm_into_iter().collect::<Vec<_>>();
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
#[expect(clippy::panic)]
fn populate_litemap<S>(map: &mut LiteMap<u32, u64, S>)
where
S: StoreMut<u32, u64> + Debug,
{
assert_eq!(0, map.len());
assert!(map.is_empty());
for (k, v) in SORTED_DATA.iter() {
if map.try_append(*k, *v).is_some() {
panic!("appending sorted data: {k:?} to {map:?}");
};
}
assert_eq!(10, map.len());
for (k, v) in RANDOM_DATA.iter() {
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
#[expect(clippy::expect_used)]
pub fn check_store<'a, S>()
where
S: StoreConstEmpty<u32, u64>
+ StoreMut<u32, u64>
+ StoreIterable<'a, u32, u64>
+ StoreFromIterator<u32, u64>
+ Clone
+ Debug
+ PartialEq
+ 'a,
{
let mut litemap_test: LiteMap<u32, u64, S> = LiteMap::new();
assert!(litemap_test.is_empty());
let mut litemap_std = LiteMap::<u32, u64>::new();
populate_litemap(&mut litemap_test);
populate_litemap(&mut litemap_std);
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!(19, litemap_test.len());
assert_eq!(19, 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`]
/// and [`StoreBulkMut`] traits.
// Test code
#[expect(clippy::expect_used)]
pub fn check_store_full<'a, S>()
where
S: StoreConstEmpty<u32, u64>
+ StoreIterableMut<'a, u32, u64>
+ StoreIntoIterator<u32, u64>
+ StoreFromIterator<u32, u64>
+ StoreBulkMut<u32, u64>
+ Clone
+ Debug
+ PartialEq
+ 'a,
{
let mut litemap_test: LiteMap<u32, u64, S> = LiteMap::new();
assert!(litemap_test.is_empty());
let mut litemap_std = LiteMap::<u32, u64>::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);
assert_eq!(20, litemap_test.len());
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);
assert_eq!(20, litemap_test.len());
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());
let mut extras = LiteMap::<u32, u64>::new();
populate_litemap(&mut extras);
litemap_test.extend(extras.clone());
litemap_std.extend(extras);
assert_eq!(20, litemap_test.len());
assert_eq!(20, litemap_std.len());
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);
test_extend::<S>();
}
fn test_extend<'a, S>()
where
S: StoreConstEmpty<u32, u64>
+ StoreIterableMut<'a, u32, u64>
+ StoreIntoIterator<u32, u64>
+ StoreFromIterator<u32, u64>
+ StoreBulkMut<u32, u64>
+ Clone
+ Debug
+ PartialEq
+ 'a,
{
// Extend an empty BTreeMap with initial entries.
let mut map: LiteMap<u32, u64, S> = LiteMap::new();
let initial_entries = [(1, 1), (2, 2), (3, 3)];
map.extend(initial_entries);
assert_eq!(map.len(), 3);
assert_eq!(map.get(&1), Some(&1));
assert_eq!(map.get(&2), Some(&2));
assert_eq!(map.get(&3), Some(&3));
// Extend with entries that contain keys already present.
// For repeated keys, the last value should remain.
let overlapping_entries = [(2, 22), (4, 44), (1, 11)];
map.extend(overlapping_entries);
assert_eq!(map.len(), 4);
assert_eq!(map.get(&1), Some(&11));
assert_eq!(map.get(&2), Some(&22));
assert_eq!(map.get(&3), Some(&3));
assert_eq!(map.get(&4), Some(&44));
// Extend with an iterator that includes duplicate key entries.
// The very last occurrence for a key should be the final value.
let duplicate_entries = [(3, 333), (3, 3333), (5, 5)];
map.extend(duplicate_entries);
assert_eq!(map.len(), 5);
assert_eq!(map.get(&3), Some(&3333));
assert_eq!(map.get(&5), Some(&5));
// Extend with an empty iterator: the map should remain unchanged.
let empty_entries: Vec<(u32, u64)> = Vec::new();
let map_clone = map.clone();
map.extend(empty_entries);
check_equivalence(map.values.clone(), map_clone.values.clone());
// Extend with the same values: the map should remain unchanged.
map.extend(map_clone.clone());
check_equivalence(map.values.clone(), map_clone.values);
}

98
vendor/litemap/tests/rkyv.rs vendored Normal file
View File

@@ -0,0 +1,98 @@
// 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(if cfg!(target_endian = "little") {
[
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,
]
} else {
[
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, 0, 0, 0, 8,
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,
255, 255, 255, 80, 0, 0, 0, 11,
]
});
type LiteMapOfStrings = LiteMap<String, String>;
type TupleVecOfStrings = Vec<(String, String)>;
fn generate() -> AlignedVec {
let map = DATA
.iter()
.map(|&(k, v)| (k.to_owned(), v.to_owned()))
.collect::<LiteMapOfStrings>();
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::<TupleVecOfStrings>(&RKYV.0) };
let s = archived[0].1.as_str();
assert_eq!(s, "Arabic");
}
#[test]
fn rkyv_checked_archive() {
let archived = check_archived_root::<TupleVecOfStrings>(&RKYV.0).unwrap();
let s = archived[0].1.as_str();
assert_eq!(s, "Arabic");
}
#[test]
fn rkyv_deserialize() {
let archived = unsafe { archived_root::<TupleVecOfStrings>(&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"));
}

22
vendor/litemap/tests/serde.rs vendored Normal file
View File

@@ -0,0 +1,22 @@
// 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);
}

158
vendor/litemap/tests/store.rs vendored Normal file
View File

@@ -0,0 +1,158 @@
// 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<T>(Vec<T>);
type MapF<K, V> = fn(&(K, V)) -> (&K, &V);
#[inline]
fn map_f<K, V>(input: &(K, V)) -> (&K, &V) {
(&input.0, &input.1)
}
type MapFMut<K, V> = fn(&mut (K, V)) -> (&K, &mut V);
#[inline]
fn map_f_mut<K, V>(input: &mut (K, V)) -> (&K, &mut V) {
(&input.0, &mut input.1)
}
impl<K, V> StoreConstEmpty<K, V> for VecWithDefaults<(K, V)> {
const EMPTY: VecWithDefaults<(K, V)> = VecWithDefaults(Vec::new());
}
impl<K, V> Store<K, V> 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<F>(&self, mut cmp: F) -> Result<usize, usize>
where
F: FnMut(&K) -> Ordering,
{
self.0.as_slice().binary_search_by(|(k, _)| cmp(k))
}
}
impl<K: Ord, V> StoreFromIterable<K, V> for VecWithDefaults<(K, V)> {
fn lm_sort_from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
let v: Vec<_> = Vec::lm_sort_from_iter(iter);
Self(v)
}
}
impl<K, V> StoreMut<K, V> 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<core::slice::Iter<'a, (K, V)>, MapF<K, V>>;
#[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<core::slice::IterMut<'a, (K, V)>, MapFMut<K, V>>;
#[inline]
fn lm_iter_mut(&'a mut self) -> Self::KeyValueIterMut {
self.0.as_mut_slice().iter_mut().map(map_f_mut)
}
}
impl<K, V> StoreIntoIterator<K, V> 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<A> std::iter::FromIterator<A> for VecWithDefaults<A> {
fn from_iter<I: IntoIterator<Item = A>>(iter: I) -> Self {
Self(Vec::from_iter(iter))
}
}
impl<K, V> StoreFromIterator<K, V> for VecWithDefaults<(K, V)> {}
impl<K: Ord, V> StoreBulkMut<K, V> for VecWithDefaults<(K, V)> {
fn lm_retain<F>(&mut self, predicate: F)
where
F: FnMut(&K, &V) -> bool,
{
self.0.lm_retain(predicate)
}
fn lm_extend<I>(&mut self, other: I)
where
I: IntoIterator<Item = (K, V)>,
{
self.0.lm_extend(other)
}
}
#[test]
fn test_default_impl() {
check_store_full::<VecWithDefaults<(u32, u64)>>();
}