From 66ed92c0867fb2c451a60840d312dc549c0b435c Mon Sep 17 00:00:00 2001 From: Moritz Hoffmann Date: Wed, 26 Jun 2024 16:54:08 -0400 Subject: [PATCH] Rename Containerized to RegionPreference and add owned type (#47) Signed-off-by: Moritz Hoffmann --- README.md | 2 +- benches/bench.rs | 46 ++++++++++++++++++++++----------------------- src/impls/mirror.rs | 5 +++-- src/impls/option.rs | 9 +++++---- src/impls/result.rs | 9 +++++---- src/impls/slice.rs | 15 +++++++++------ src/impls/string.rs | 10 ++++++---- src/impls/tuple.rs | 5 +++-- src/lib.rs | 27 ++++++++++++++++++++------ tests/person.rs | 35 +++++++++++++++++----------------- 10 files changed, 94 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index 4e7018f..5b987aa 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ writing down all values. All region implementations should be considered examples on how to implement specific regions that are tailored to the needs of the type, and characteristics of the data -encountered in practice. This crate provides a [`Containerized`] trait to let types +encountered in practice. This crate provides a [`RegionPreference`] trait to let types express their suggested region, but users can select a different region, as long as it is compatible with the types to be stored. For example, a vector suggests to use a slice-based region, but a client might know that the inner type is copy, and hence diff --git a/benches/bench.rs b/benches/bench.rs index f87796e..9903bab 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -8,8 +8,8 @@ use flatcontainer::impls::deduplicate::{CollapseSequence, ConsecutiveOffsetPairs use flatcontainer::impls::offsets::OffsetOptimized; use flatcontainer::impls::tuple::{TupleABCRegion, TupleABRegion}; use flatcontainer::{ - ColumnsRegion, Containerized, FlatStack, MirrorRegion, OwnedRegion, Push, Region, ReserveItems, - SliceRegion, StringRegion, + ColumnsRegion, FlatStack, MirrorRegion, OwnedRegion, Push, Region, RegionPreference, + ReserveItems, SliceRegion, StringRegion, }; use test::Bencher; @@ -265,46 +265,46 @@ fn vec_u_vn_s_prealloc(bencher: &mut Bencher) { #[bench] fn empty_copy_flat(bencher: &mut Bencher) { - _bench_copy_flat_containerized(bencher, vec![(); 1024]); + _bench_copy_flat_preference(bencher, vec![(); 1024]); } #[bench] fn u64_copy_flat(bencher: &mut Bencher) { - _bench_copy_flat_containerized(bencher, vec![0u64; 1024]); + _bench_copy_flat_preference(bencher, vec![0u64; 1024]); } #[bench] fn u32x2_copy_flat(bencher: &mut Bencher) { - _bench_copy_flat_containerized(bencher, vec![(0u32, 0u32); 1024]); + _bench_copy_flat_preference(bencher, vec![(0u32, 0u32); 1024]); } #[bench] fn u8_u64_copy_flat(bencher: &mut Bencher) { - _bench_copy_flat_containerized(bencher, vec![(0u8, 0u64); 512]); + _bench_copy_flat_preference(bencher, vec![(0u8, 0u64); 512]); } #[bench] fn str10_copy_flat(bencher: &mut Bencher) { - _bench_copy_flat_containerized(bencher, vec!["grawwwwrr!"; 1024]); + _bench_copy_flat_preference(bencher, vec!["grawwwwrr!"; 1024]); } #[bench] fn str100_copy_flat(bencher: &mut Bencher) { - _bench_copy_flat_containerized(bencher, vec!["grawwwwrrgrawwwwrrgrawwwwrrgrawwwwrrgrawwwwrrgrawwwwrrgrawwwwrrgrawwwwrrgrawwwwrr!!!!!!!!!grawwwwrr!"; 1024]); + _bench_copy_flat_preference(bencher, vec!["grawwwwrrgrawwwwrrgrawwwwrrgrawwwwrrgrawwwwrrgrawwwwrrgrawwwwrrgrawwwwrrgrawwwwrr!!!!!!!!!grawwwwrr!"; 1024]); } #[bench] fn string10_copy_flat(bencher: &mut Bencher) { - _bench_copy_flat_containerized(bencher, vec![format!("grawwwwrr!"); 1024]); + _bench_copy_flat_preference(bencher, vec![format!("grawwwwrr!"); 1024]); } #[bench] fn string20_copy_flat(bencher: &mut Bencher) { - _bench_copy_flat_containerized(bencher, vec![format!("grawwwwrr!!!!!!!!!!!"); 512]); + _bench_copy_flat_preference(bencher, vec![format!("grawwwwrr!!!!!!!!!!!"); 512]); } #[bench] fn vec_u_s_copy_flat(bencher: &mut Bencher) { - _bench_copy_flat_containerized( + _bench_copy_flat_preference( bencher, vec![vec![(0u64, "grawwwwrr!".to_string()); 32]; 32], ); } #[bench] fn vec_u_vn_s_copy_flat(bencher: &mut Bencher) { - _bench_copy_flat_containerized( + _bench_copy_flat_preference( bencher, vec![vec![(0u64, vec![(); 1 << 40], "grawwwwrr!".to_string()); 32]; 32], ); @@ -381,9 +381,9 @@ fn vec_u_vn_s_copy_flat_region_column(bencher: &mut Bencher) { ); } -fn _bench_copy(bencher: &mut Bencher, record: T) +fn _bench_copy(bencher: &mut Bencher, record: T) where - for<'a> ::Region: Push<&'a T>, + for<'a> ::Region: Push<&'a T>, { // prepare encoded data for bencher.bytes let mut arena = FlatStack::default_impl::(); @@ -425,7 +425,7 @@ where println!("{siz} {cap}"); } -fn _bench_clone(bencher: &mut Bencher, record: T) { +fn _bench_clone(bencher: &mut Bencher, record: T) { // prepare encoded data for bencher.bytes let mut arena = Vec::new(); @@ -437,9 +437,9 @@ fn _bench_clone(bencher: &mut Bencher, record: T) }); } -fn _bench_realloc(bencher: &mut Bencher, record: T) +fn _bench_realloc(bencher: &mut Bencher, record: T) where - for<'a> ::Region: Push<&'a T>, + for<'a> ::Region: Push<&'a T>, { let mut arena = FlatStack::default_impl::(); bencher.iter(|| { @@ -457,9 +457,9 @@ where bencher.bytes = siz as u64; } -fn _bench_prealloc(bencher: &mut Bencher, record: T) +fn _bench_prealloc(bencher: &mut Bencher, record: T) where - for<'a> ::Region: ReserveItems<&'a T> + Push<&'a T>, + for<'a> ::Region: ReserveItems<&'a T> + Push<&'a T>, { let mut arena = FlatStack::default_impl::(); bencher.iter(|| { @@ -478,11 +478,11 @@ where bencher.bytes = siz as u64; } -fn _bench_copy_flat_containerized(bencher: &mut Bencher, record: T) +fn _bench_copy_flat_preference(bencher: &mut Bencher, record: T) where - T: Containerized, - for<'a> ::Region: - Push<&'a T> + Push<<::Region as Region>::ReadItem<'a>> + Clone, + T: RegionPreference, + for<'a> ::Region: + Push<&'a T> + Push<<::Region as Region>::ReadItem<'a>> + Clone, { _bench_copy_flat::(bencher, record) } diff --git a/src/impls/mirror.rs b/src/impls/mirror.rs index 2574d49..664f1e0 100644 --- a/src/impls/mirror.rs +++ b/src/impls/mirror.rs @@ -6,7 +6,7 @@ use std::marker::PhantomData; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use crate::{Containerized, Index, IntoOwned, Push, Region, ReserveItems}; +use crate::{Index, IntoOwned, Push, Region, RegionPreference, ReserveItems}; /// A region for types where the read item type is equal to the index type. /// @@ -147,7 +147,8 @@ where macro_rules! implement_for { ($index_type:ty) => { - impl Containerized for $index_type { + impl RegionPreference for $index_type { + type Owned = Self; type Region = MirrorRegion; } diff --git a/src/impls/option.rs b/src/impls/option.rs index b56b6c2..ec518b6 100644 --- a/src/impls/option.rs +++ b/src/impls/option.rs @@ -3,9 +3,10 @@ #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use crate::{Containerized, IntoOwned, Push, Region, ReserveItems}; +use crate::{IntoOwned, Push, Region, RegionPreference, ReserveItems}; -impl Containerized for Option { +impl RegionPreference for Option { + type Owned = Option; type Region = OptionRegion; } @@ -15,8 +16,8 @@ impl Containerized for Option { /// /// The region can hold options: /// ``` -/// # use flatcontainer::{Containerized, Push, OptionRegion, Region}; -/// let mut r = ::Region>>::default(); +/// # use flatcontainer::{RegionPreference, Push, OptionRegion, Region}; +/// let mut r = ::Region>>::default(); /// /// let some_index = r.push(Some(123)); /// // Type annotations required for `None`: diff --git a/src/impls/result.rs b/src/impls/result.rs index 5a26670..99ea871 100644 --- a/src/impls/result.rs +++ b/src/impls/result.rs @@ -3,9 +3,10 @@ #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use crate::{Containerized, IntoOwned, Push, Region, ReserveItems}; +use crate::{IntoOwned, Push, Region, RegionPreference, ReserveItems}; -impl Containerized for Result { +impl RegionPreference for Result { + type Owned = Result; type Region = ResultRegion; } @@ -15,9 +16,9 @@ impl Containerized for Result { /// /// Add results to a result region: /// ``` -/// use flatcontainer::{Containerized, Push, Region, ResultRegion}; +/// use flatcontainer::{RegionPreference, Push, Region, ResultRegion}; /// let mut r = -/// ::Region, ::Region>>::default(); +/// ::Region, ::Region>>::default(); /// /// let ok_index = r.push(Result::<(), String>::Ok(())); /// let err_index = r.push(Result::<(), String>::Err("Error".to_string())); diff --git a/src/impls/slice.rs b/src/impls/slice.rs index cdfbb20..51c9705 100644 --- a/src/impls/slice.rs +++ b/src/impls/slice.rs @@ -8,17 +8,20 @@ use std::ops::{Deref, Range}; use serde::{Deserialize, Serialize}; use crate::impls::offsets::OffsetContainer; -use crate::{Containerized, IntoOwned, Push, Region, ReserveItems}; +use crate::{IntoOwned, Push, Region, RegionPreference, ReserveItems}; -impl Containerized for Vec { +impl RegionPreference for Vec { + type Owned = Vec; type Region = SliceRegion; } -impl Containerized for [T] { +impl RegionPreference for [T] { + type Owned = Vec; type Region = SliceRegion; } -impl Containerized for [T; N] { +impl RegionPreference for [T; N] { + type Owned = Vec; type Region = SliceRegion; } @@ -33,8 +36,8 @@ impl Containerized for [T; N] { /// /// We fill some data into a slice region and use the [`ReadSlice`] to extract it later. /// ``` -/// use flatcontainer::{Containerized, Push, Region, SliceRegion}; -/// let mut r = ::Region>>::default(); +/// use flatcontainer::{RegionPreference, Push, Region, SliceRegion}; +/// let mut r = ::Region>>::default(); /// /// let panagram_en = "The quick fox jumps over the lazy dog" /// .split(" ") diff --git a/src/impls/string.rs b/src/impls/string.rs index c1d10b0..9a5d70e 100644 --- a/src/impls/string.rs +++ b/src/impls/string.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use crate::impls::slice_copy::OwnedRegion; -use crate::{Containerized, Push, Region, ReserveItems}; +use crate::{Push, Region, RegionPreference, ReserveItems}; /// A region to store strings and read `&str`. /// @@ -18,7 +18,7 @@ use crate::{Containerized, Push, Region, ReserveItems}; /// /// We fill some data into a string region and use extract it later. /// ``` -/// use flatcontainer::{Containerized, Push, OwnedRegion, Region, StringRegion}; +/// use flatcontainer::{RegionPreference, Push, OwnedRegion, Region, StringRegion}; /// let mut r = ::default(); /// /// let panagram_en = "The quick fox jumps over the lazy dog"; @@ -100,11 +100,13 @@ where } } -impl Containerized for String { +impl RegionPreference for String { + type Owned = Self; type Region = StringRegion; } -impl Containerized for &str { +impl RegionPreference for &str { + type Owned = String; type Region = StringRegion; } diff --git a/src/impls/tuple.rs b/src/impls/tuple.rs index 17502df..2348fb1 100644 --- a/src/impls/tuple.rs +++ b/src/impls/tuple.rs @@ -4,13 +4,14 @@ use paste::paste; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use crate::{Containerized, IntoOwned, Push, Region, ReserveItems}; +use crate::{IntoOwned, Push, Region, RegionPreference, ReserveItems}; /// The macro creates the region implementation for tuples macro_rules! tuple_flatcontainer { ($($name:ident)+) => ( paste! { - impl<$($name: Containerized),*> Containerized for ($($name,)*) { + impl<$($name: RegionPreference),*> RegionPreference for ($($name,)*) { + type Owned = ($($name::Owned,)*); type Region = []<$($name::Region,)*>; } diff --git a/src/lib.rs b/src/lib.rs index 0347288..cb15176 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -82,10 +82,25 @@ pub trait Region: Default { Self: 'a; } -/// A trait to let types express a default container type. -pub trait Containerized { +/// A trait to let types express a default container type and an owned type, which can +/// be used to define regions in simpler terms. +/// +/// # Example +/// +/// ``` +/// # use flatcontainer::{FlatStack, RegionPreference}; +/// let _ = FlatStack::<<((Vec, &[usize]), Option, Result) as RegionPreference>::Region>::default(); +/// ``` +pub trait RegionPreference { + /// The owned type of the region. + type Owned; /// The recommended container type. - type Region: Region; + type Region: Region; +} + +impl RegionPreference for &T { + type Owned = T::Owned; + type Region = T::Region; } /// Push an item `T` into a region. @@ -179,7 +194,7 @@ impl FlatStack { /// Default implementation based on the preference of type `T`. #[inline] #[must_use] - pub fn default_impl>() -> Self { + pub fn default_impl>() -> Self { Self::default() } @@ -531,8 +546,8 @@ mod tests { test_copy::<_, OwnedRegion<_>>([0u8].as_slice()); test_copy::<_, OwnedRegion<_>>(&[0u8].as_slice()); - test_copy::<_, <(u8, u8) as Containerized>::Region>((1, 2)); - test_copy::<_, <(u8, u8) as Containerized>::Region>(&(1, 2)); + test_copy::<_, <(u8, u8) as RegionPreference>::Region>((1, 2)); + test_copy::<_, <(u8, u8) as RegionPreference>::Region>(&(1, 2)); test_copy::<_, ConsecutiveOffsetPairs>>([1, 2, 3].as_slice()); diff --git a/tests/person.rs b/tests/person.rs index 514217e..5f3a43c 100644 --- a/tests/person.rs +++ b/tests/person.rs @@ -1,6 +1,6 @@ //! Test a slightly more struct with nested regions, representing people. -use flatcontainer::{Containerized, FlatStack, IntoOwned, Push, Region, ReserveItems}; +use flatcontainer::{FlatStack, IntoOwned, Push, Region, RegionPreference, ReserveItems}; struct Person { name: String, @@ -8,22 +8,23 @@ struct Person { hobbies: Vec, } -impl Containerized for Person { +impl RegionPreference for Person { + type Owned = Self; type Region = PersonRegion; } #[derive(Default)] struct PersonRegion { - name_container: ::Region, - age_container: ::Region, - hobbies: as Containerized>::Region, + name_container: ::Region, + age_container: ::Region, + hobbies: as RegionPreference>::Region, } #[derive(Debug, Clone, Copy)] struct PersonRef<'a> { - name: <::Region as Region>::ReadItem<'a>, - age: <::Region as Region>::ReadItem<'a>, - hobbies: < as Containerized>::Region as Region>::ReadItem<'a>, + name: <::Region as Region>::ReadItem<'a>, + age: <::Region as Region>::ReadItem<'a>, + hobbies: < as RegionPreference>::Region as Region>::ReadItem<'a>, } impl<'a> IntoOwned<'a> for PersonRef<'a> { @@ -56,9 +57,9 @@ impl Region for PersonRegion { type Owned = Person; type ReadItem<'a> = PersonRef<'a> where Self: 'a; type Index = ( - <::Region as Region>::Index, - <::Region as Region>::Index, - < as Containerized>::Region as Region>::Index, + <::Region as Region>::Index, + <::Region as Region>::Index, + < as RegionPreference>::Region as Region>::Index, ); fn merge_regions<'a>(regions: impl Iterator + Clone) -> Self @@ -66,13 +67,13 @@ impl Region for PersonRegion { Self: 'a, { Self { - name_container: ::Region::merge_regions( + name_container: ::Region::merge_regions( regions.clone().map(|r| &r.name_container), ), - age_container: ::Region::merge_regions( + age_container: ::Region::merge_regions( regions.clone().map(|r| &r.age_container), ), - hobbies: as Containerized>::Region::merge_regions( + hobbies: as RegionPreference>::Region::merge_regions( regions.map(|r| &r.hobbies), ), } @@ -116,9 +117,9 @@ impl Region for PersonRegion { Self: 'a, { PersonRef { - name: ::Region::reborrow(item.name), - age: ::Region::reborrow(item.age), - hobbies: as Containerized>::Region::reborrow(item.hobbies), + name: ::Region::reborrow(item.name), + age: ::Region::reborrow(item.age), + hobbies: as RegionPreference>::Region::reborrow(item.hobbies), } } }