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

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);
}