From 70dd744d2e95c460bdecfb9d183deea5345abf2e Mon Sep 17 00:00:00 2001 From: "Shane F. Carr" Date: Mon, 13 Nov 2023 11:12:49 -0800 Subject: [PATCH 1/7] Add databake impl for LiteMap --- Cargo.lock | 1 + utils/litemap/Cargo.toml | 1 + utils/litemap/src/databake.rs | 45 +++++++++++++++++++++++++++++++++++ utils/litemap/src/lib.rs | 2 ++ 4 files changed, 49 insertions(+) create mode 100644 utils/litemap/src/databake.rs diff --git a/Cargo.lock b/Cargo.lock index 23702d7a996..310654fabae 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..caa2809675e 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 } diff --git a/utils/litemap/src/databake.rs b/utils/litemap/src/databake.rs new file mode 100644 index 00000000000..cf1dcc77943 --- /dev/null +++ b/utils/litemap/src/databake.rs @@ -0,0 +1,45 @@ +// 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::*; + +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..3db36033d3b 100644 --- a/utils/litemap/src/lib.rs +++ b/utils/litemap/src/lib.rs @@ -44,6 +44,8 @@ extern crate std; extern crate alloc; +#[cfg(feature = "databake")] +mod databake; mod map; #[cfg(feature = "serde")] mod serde; From c425f2a68d86fc719f8fce38760cfbb7651c1450 Mon Sep 17 00:00:00 2001 From: "Shane F. Carr" Date: Mon, 13 Nov 2023 11:32:56 -0800 Subject: [PATCH 2/7] Add docs --- utils/litemap/src/databake.rs | 25 ++++++++++++++++++++++++- utils/litemap/src/lib.rs | 8 ++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/utils/litemap/src/databake.rs b/utils/litemap/src/databake.rs index cf1dcc77943..f9ca44367b6 100644 --- a/utils/litemap/src/databake.rs +++ b/utils/litemap/src/databake.rs @@ -5,6 +5,29 @@ use crate::LiteMap; use databake::*; +/// Bakes a LiteMap into Rust code for fast runtime construction from data. Use this impl during +/// code generation or in a `build.rs` script. +/// +/// For the most efficient bake, bake the [`LiteMap`] with a slice store. +/// +/// # Examples +/// +/// ``` +/// use databake::*; +/// use litemap::LiteMap; +/// +/// let mut litemap = LiteMap::new_vec(); +/// litemap.insert(1usize, "one"); +/// litemap.insert(2usize, "one"); +/// litemap.insert(10usize, "ten"); +/// +/// let litemap_slice = litemap.as_sliced(); +/// +/// assert_eq!( +/// litemap_slice.bake(&Default::default()).to_string(), +/// r#"litemap :: LiteMap :: from_sorted_store_unchecked (& [(1usize , "one") , (2usize , "one") , (10usize , "ten")])"#, +/// ); +/// ``` impl Bake for LiteMap where S: Bake, @@ -20,7 +43,7 @@ where fn test_baked_map() { // Const construction: test_bake!( - LiteMap, + LiteMap, const: crate::LiteMap::from_sorted_store_unchecked( &[ (1usize, "one"), diff --git a/utils/litemap/src/lib.rs b/utils/litemap/src/lib.rs index 3db36033d3b..35be134c4d6 100644 --- a/utils/litemap/src/lib.rs +++ b/utils/litemap/src/lib.rs @@ -21,6 +21,14 @@ //! 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 +//! [`databake`]: ::databake //! [`Vec`]: alloc::vec::Vec // https://github.com/unicode-org/icu4x/blob/main/docs/process/boilerplate.md#library-annotations From 51f1918bc03842f8942422747801d77653671750 Mon Sep 17 00:00:00 2001 From: "Shane F. Carr" Date: Mon, 13 Nov 2023 11:40:44 -0800 Subject: [PATCH 3/7] Improve docs to demonstrate more allocated-to-borrowed transformations --- utils/litemap/src/databake.rs | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/utils/litemap/src/databake.rs b/utils/litemap/src/databake.rs index f9ca44367b6..e82015ce2d2 100644 --- a/utils/litemap/src/databake.rs +++ b/utils/litemap/src/databake.rs @@ -8,7 +8,13 @@ use databake::*; /// Bakes a LiteMap into Rust code for fast runtime construction from data. Use this impl during /// code generation or in a `build.rs` script. /// -/// For the most efficient bake, bake the [`LiteMap`] with a slice store. +/// 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 /// @@ -16,16 +22,20 @@ use databake::*; /// use databake::*; /// use litemap::LiteMap; /// -/// let mut litemap = LiteMap::new_vec(); -/// litemap.insert(1usize, "one"); -/// litemap.insert(2usize, "one"); -/// litemap.insert(10usize, "ten"); +/// // Construct the LiteMap fully owned and allocated: +/// let mut litemap_alloc = LiteMap::new_vec(); +/// litemap_alloc.insert(1usize, "one".to_string()); +/// litemap_alloc.insert(2usize, "two".to_string()); +/// litemap_alloc.insert(10usize, "ten".to_string()); /// -/// let litemap_slice = litemap.as_sliced(); +/// // Convert to a borrowed type for baking: +/// let litemap_str: LiteMap = litemap_alloc.to_borrowed_values(); +/// let litemap_slice = litemap_str.as_sliced(); /// +/// // The bake will now work for const construction: /// assert_eq!( /// litemap_slice.bake(&Default::default()).to_string(), -/// r#"litemap :: LiteMap :: from_sorted_store_unchecked (& [(1usize , "one") , (2usize , "one") , (10usize , "ten")])"#, +/// r#"litemap :: LiteMap :: from_sorted_store_unchecked (& [(1usize , "one") , (2usize , "two") , (10usize , "ten")])"#, /// ); /// ``` impl Bake for LiteMap From 081176d31a1ed5ad08e61307ce54222515753a3a Mon Sep 17 00:00:00 2001 From: "Shane F. Carr" Date: Mon, 13 Nov 2023 11:45:12 -0800 Subject: [PATCH 4/7] cargo make generate-readmes --- utils/litemap/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/utils/litemap/README.md b/utils/litemap/README.md index cf5a19095cf..2e445aee531 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 From 70f01286620c7315aa11d4bb6477a4d0511292a3 Mon Sep 17 00:00:00 2001 From: "Shane F. Carr" Date: Mon, 13 Nov 2023 13:55:35 -0800 Subject: [PATCH 5/7] Try to fix databake docs link --- utils/litemap/README.md | 2 +- utils/litemap/src/lib.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/litemap/README.md b/utils/litemap/README.md index 2e445aee531..9aa80172b4f 100644 --- a/utils/litemap/README.md +++ b/utils/litemap/README.md @@ -25,7 +25,7 @@ module for more details. [`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. +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/lib.rs b/utils/litemap/src/lib.rs index 35be134c4d6..b6f4019a708 100644 --- a/utils/litemap/src/lib.rs +++ b/utils/litemap/src/lib.rs @@ -28,7 +28,6 @@ //! suitable for use with [`databake`]. See [`impl Bake for LiteMap`] for more details. //! //! [`impl Bake for LiteMap`]: ./struct.LiteMap.html#impl-Bake-for-LiteMap -//! [`databake`]: ::databake //! [`Vec`]: alloc::vec::Vec // https://github.com/unicode-org/icu4x/blob/main/docs/process/boilerplate.md#library-annotations @@ -53,7 +52,8 @@ extern crate std; extern crate alloc; #[cfg(feature = "databake")] -mod databake; +#[path = "databake.rs"] // to not conflict with `databake` as used in the docs +mod databake_impls; mod map; #[cfg(feature = "serde")] mod serde; From f8035f03f011386b36ef53c95abca78bc518864e Mon Sep 17 00:00:00 2001 From: "Shane F. Carr" Date: Mon, 13 Nov 2023 16:26:35 -0800 Subject: [PATCH 6/7] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 386014ec258..8275b28d65c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,8 @@ - Utilities - `databake` - Improvements `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` From 9cc21b6fe8db8f45d12cd5090f551e73160fd58e Mon Sep 17 00:00:00 2001 From: "Shane F. Carr" Date: Tue, 14 Nov 2023 09:21:59 -0800 Subject: [PATCH 7/7] Review feedback --- utils/litemap/Cargo.toml | 3 +++ utils/litemap/src/databake.rs | 15 ++++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/utils/litemap/Cargo.toml b/utils/litemap/Cargo.toml index caa2809675e..0e8c93c98ca 100644 --- a/utils/litemap/Cargo.toml +++ b/utils/litemap/Cargo.toml @@ -44,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/src/databake.rs b/utils/litemap/src/databake.rs index e82015ce2d2..dc33fcb3afe 100644 --- a/utils/litemap/src/databake.rs +++ b/utils/litemap/src/databake.rs @@ -6,7 +6,7 @@ use crate::LiteMap; use databake::*; /// Bakes a LiteMap into Rust code for fast runtime construction from data. Use this impl during -/// code generation or in a `build.rs` script. +/// 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`]: @@ -23,19 +23,20 @@ use databake::*; /// use litemap::LiteMap; /// /// // Construct the LiteMap fully owned and allocated: -/// let mut litemap_alloc = LiteMap::new_vec(); +/// 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_str.as_sliced(); +/// 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: -/// assert_eq!( -/// litemap_slice.bake(&Default::default()).to_string(), -/// r#"litemap :: LiteMap :: from_sorted_store_unchecked (& [(1usize , "one") , (2usize , "two") , (10usize , "ten")])"#, +/// let mut ctx = Default::default(); +/// println!( +/// "const FOO: LiteMap = {};", +/// litemap_slice.bake(&mut ctx) /// ); /// ``` impl Bake for LiteMap