diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f55508665d..4b52711283d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,8 @@ - `databake` - Add implementations for `BTreeSet`, `BTreeMap` (https://github.com/unicode-org/icu4x/pull/4268, https://github.com/unicode-org/icu4x/pull/4274) - Improvements to `databake::test_bake!()` (https://github.com/unicode-org/icu4x/pull/4182) + - `litemap` + - Implement `databake::Bake` on `LiteMap` (https://github.com/unicode-org/icu4x/pull/4275) - `tinystr` - Better Debug impl for UnvalidatedTinyAsciiStr (https://github.com/unicode-org/icu4x/pull/4189) - `zerovec` diff --git a/Cargo.lock b/Cargo.lock index 5e529bf269c..1bf4d177d60 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2244,6 +2244,7 @@ dependencies = [ "bincode", "bytecheck", "criterion", + "databake", "icu_benchmark_macros", "icu_locid", "postcard", diff --git a/utils/litemap/Cargo.toml b/utils/litemap/Cargo.toml index e21288539fb..0e8c93c98ca 100644 --- a/utils/litemap/Cargo.toml +++ b/utils/litemap/Cargo.toml @@ -23,6 +23,7 @@ independent = true all-features = true [dependencies] +databake = { workspace = true, default-features = false, optional = true } serde = {version = "1", optional = true, default-features = false, features = ["alloc"]} yoke = { workspace = true, features = ["derive"], optional = true } @@ -43,6 +44,9 @@ criterion = "0.4" bench = ["serde"] default = ["alloc"] alloc = [] +databake = ["dep:databake"] +serde = ["dep:serde"] +yoke = ["dep:yoke"] # Enables the `testing` module with tools for testing custom stores. testing = ["alloc"] diff --git a/utils/litemap/README.md b/utils/litemap/README.md index cf5a19095cf..9aa80172b4f 100644 --- a/utils/litemap/README.md +++ b/utils/litemap/README.md @@ -21,6 +21,13 @@ By default, [`LiteMap`] is backed by a [`Vec`]; however, it can be backed by any random-access data store, giving that data store a map-like interface. See the [`store`] module for more details. +### Const construction + +[`LiteMap`] supports const construction from any store that is const-constructible, such as a +static slice, via [`LiteMap::from_sorted_store_unchecked()`]. This also makes [`LiteMap`] +suitable for use with [`databake`]. See [`impl Bake for LiteMap`] for more details. + +[`impl Bake for LiteMap`]: ./struct.LiteMap.html#impl-Bake-for-LiteMap [`Vec`]: alloc::vec::Vec diff --git a/utils/litemap/src/databake.rs b/utils/litemap/src/databake.rs new file mode 100644 index 00000000000..dc33fcb3afe --- /dev/null +++ b/utils/litemap/src/databake.rs @@ -0,0 +1,79 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +use crate::LiteMap; +use databake::*; + +/// Bakes a LiteMap into Rust code for fast runtime construction from data. Use this impl during +/// code generation, such as in a `build.rs` script. +/// +/// For the most efficient bake, bake the [`LiteMap`] with a slice store. Use functions such as +/// the following for converting an allocated [`LiteMap`] to a borrowing [`LiteMap`]: +/// +/// - [`LiteMap::to_borrowed_keys()`] +/// - [`LiteMap::to_borrowed_values()`] +/// - [`LiteMap::to_borrowed_keys_values()`] +/// - [`LiteMap::as_sliced()`] +/// +/// # Examples +/// +/// ``` +/// use databake::*; +/// use litemap::LiteMap; +/// +/// // Construct the LiteMap fully owned and allocated: +/// let mut litemap_alloc: LiteMap> = LiteMap::new_vec(); +/// litemap_alloc.insert(1usize, "one".to_string()); +/// litemap_alloc.insert(2usize, "two".to_string()); +/// litemap_alloc.insert(10usize, "ten".to_string()); +/// +/// // Convert to a borrowed type for baking: +/// let litemap_str: LiteMap> = litemap_alloc.to_borrowed_values(); +/// let litemap_slice: LiteMap = litemap_str.as_sliced(); +/// +/// // The bake will now work for const construction: +/// let mut ctx = Default::default(); +/// println!( +/// "const FOO: LiteMap = {};", +/// litemap_slice.bake(&mut ctx) +/// ); +/// ``` +impl Bake for LiteMap +where + S: Bake, +{ + fn bake(&self, env: &CrateEnv) -> TokenStream { + env.insert("litemap"); + let store = self.values.bake(env); + quote! { litemap::LiteMap::from_sorted_store_unchecked(#store) } + } +} + +#[test] +fn test_baked_map() { + // Const construction: + test_bake!( + LiteMap, + const: crate::LiteMap::from_sorted_store_unchecked( + &[ + (1usize, "one"), + (2usize, "two"), + (10usize, "ten") + ] + ), + litemap + ); + // Non-const construction: + test_bake!( + LiteMap>, + crate::LiteMap::from_sorted_store_unchecked( + alloc::vec![ + (1usize, "one".to_owned()), + (2usize, "two".to_owned()), + (10usize, "ten".to_owned()), + ] + ), + litemap + ); +} diff --git a/utils/litemap/src/lib.rs b/utils/litemap/src/lib.rs index 85f2c435d66..b6f4019a708 100644 --- a/utils/litemap/src/lib.rs +++ b/utils/litemap/src/lib.rs @@ -21,6 +21,13 @@ //! random-access data store, giving that data store a map-like interface. See the [`store`] //! module for more details. //! +//! ## Const construction +//! +//! [`LiteMap`] supports const construction from any store that is const-constructible, such as a +//! static slice, via [`LiteMap::from_sorted_store_unchecked()`]. This also makes [`LiteMap`] +//! suitable for use with [`databake`]. See [`impl Bake for LiteMap`] for more details. +//! +//! [`impl Bake for LiteMap`]: ./struct.LiteMap.html#impl-Bake-for-LiteMap //! [`Vec`]: alloc::vec::Vec // https://github.com/unicode-org/icu4x/blob/main/docs/process/boilerplate.md#library-annotations @@ -44,6 +51,9 @@ extern crate std; extern crate alloc; +#[cfg(feature = "databake")] +#[path = "databake.rs"] // to not conflict with `databake` as used in the docs +mod databake_impls; mod map; #[cfg(feature = "serde")] mod serde;