diff --git a/README.md b/README.md index 9cac869..cf4bc8c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [Also available on crates.io.](https://crates.io/crates/wrapped_slab) -Very simple Rust library useful when you want stronger type guarantees than Slab's `usize` keys. Generates `TSlab(Slab)` that accepts `TKey` instead of `usize`. `TVacantEntry(VacantEntry)` is also generated along the same lines. +Very simple Rust library useful when you want stronger type guarantees than Slab's `usize` keys. Generates `TSlab(Slab)` that accepts `TKey` instead of `usize`. `TVacantEntry(VacantEntry)` is also generated along the same lines. This should be a drop-in replacement for `Slab`, provided all the keys are changed from `usize` to `TKey`. ## Example @@ -23,7 +23,3 @@ fn main() { // See wrapped_slab/tests/ for more examples } ``` - -## Warning - -This is a very early version, however the aim is to just translate the Slab API 1-1. Currently the only things missing are Iter, IterMut, drain, and retain. diff --git a/RELEASES.md b/RELEASES.md index 01f5aa7..40bd970 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,8 @@ +Version 0.2.0 (2023-07-24) +========================== + +- Implement Iter, IterMut, and Drain. + Version 0.1.1 (2023-07-19) ========================== diff --git a/wrapped_slab/Cargo.toml b/wrapped_slab/Cargo.toml index 57f6e82..e805e76 100644 --- a/wrapped_slab/Cargo.toml +++ b/wrapped_slab/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wrapped_slab" -version = "0.1.1" +version = "0.2.0" edition = "2021" authors = ["Louis Wyborn "] rust-version = "1.62" @@ -14,7 +14,7 @@ readme = "README.md" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -wrapped_slab_derive = {version="0.1.0", path="../wrapped_slab_derive"} +wrapped_slab_derive = { version = "0.2.0", path = "../wrapped_slab_derive" } # Used as the backing store of all the elements. -slab = { version = "0.4" } \ No newline at end of file +slab = { version = "0.4" } diff --git a/wrapped_slab/src/lib.rs b/wrapped_slab/src/lib.rs index 44d0bbf..1064eec 100644 --- a/wrapped_slab/src/lib.rs +++ b/wrapped_slab/src/lib.rs @@ -1,4 +1,10 @@ pub use wrapped_slab_derive::WrappedSlab; +#[derive(Clone)] +pub enum Entry { + Vacant(usize), + Occupied(T), +} + #[doc(hidden)] pub use slab; diff --git a/wrapped_slab/tests/basic.rs b/wrapped_slab/tests/basic.rs index efbc12f..c71768c 100644 --- a/wrapped_slab/tests/basic.rs +++ b/wrapped_slab/tests/basic.rs @@ -1,6 +1,6 @@ use wrapped_slab::WrappedSlab; -#[derive(WrappedSlab)] +#[derive(WrappedSlab, PartialEq, Debug)] struct TestUnitStruct(String); #[test] @@ -18,15 +18,9 @@ fn test_unit_struct() { assert_eq!(val.0, "testing"); assert_eq!(slab.len(), 0); - - let next_entry: TestUnitStructVacantEntry = slab.vacant_entry(); - let next_key: TestUnitStructKey = next_entry.key(); - let next_entry_ref: &mut TestUnitStruct = - next_entry.insert(TestUnitStruct(format!("{next_key:?}"))); - assert_eq!(next_entry_ref.0, format!("{next_key:?}")) } -#[derive(WrappedSlab)] +#[derive(WrappedSlab, PartialEq, Debug)] struct TestStruct { field1: String, } @@ -48,18 +42,12 @@ fn test_struct() { assert_eq!(val.field1, "testing"); assert_eq!(slab.len(), 0); - - let next_entry: TestStructVacantEntry = slab.vacant_entry(); - let next_key: TestStructKey = next_entry.key(); - let next_entry_ref: &mut TestStruct = next_entry.insert(TestStruct { - field1: format!("{next_key:?}"), - }); - assert_eq!(next_entry_ref.field1, format!("{next_key:?}")) } #[derive(WrappedSlab, PartialEq, Debug)] enum TestEnum { VariantOne(String), + VariantTwo, } #[test] @@ -77,6 +65,12 @@ fn test_enum() { assert_eq!(val, TestEnum::VariantOne("testing".into())); assert_eq!(slab.len(), 0); +} + +#[test] +fn test_vacant_entry() { + let mut slab = TestEnumSlab::default(); + slab.insert(TestEnum::VariantOne("testing".into())); let next_entry: TestEnumVacantEntry = slab.vacant_entry(); let next_key: TestEnumKey = next_entry.key(); @@ -85,5 +79,63 @@ fn test_enum() { assert_eq!( next_entry_ref, &mut TestEnum::VariantOne(format!("{next_key:?}")) - ) + ); +} + +#[test] +fn test_iter() { + let mut slab = TestEnumSlab::default(); + slab.insert(TestEnum::VariantOne("testing".into())); + + let mut iter = slab.iter_mut(); + let (idx, s) = iter.next().unwrap(); + assert_eq!(idx, TestEnumKey(0)); + assert_eq!(s, &mut TestEnum::VariantOne("testing".to_string())); + *s = TestEnum::VariantTwo; + assert_eq!(iter.next(), None); + + let mut iter = slab.iter(); + let (idx, s) = iter.next().unwrap(); + assert_eq!(idx, TestEnumKey(0)); + assert_eq!(s, &TestEnum::VariantTwo); + assert_eq!(iter.next(), None); + + let mut iter = slab.into_iter(); + let (idx, s) = iter.next().unwrap(); + assert_eq!(idx, TestEnumKey(0)); + assert_eq!(s, TestEnum::VariantTwo); + assert_eq!(iter.next(), None); +} + +#[test] +fn test_drain() { + let mut slab = TestEnumSlab::with_capacity(32); + slab.reserve(64); + assert_eq!(slab.capacity(), 64); + + slab.insert(TestEnum::VariantTwo); + + let mut drain = slab.drain(); + assert_eq!(drain.len(), 1); + let s = drain.next().unwrap(); + assert_eq!(s, TestEnum::VariantTwo); + assert_eq!(drain.len(), 0); + drop(drain); + + assert_eq!(slab.len(), 0); +} + +#[test] +fn test_index() { + let mut slab = TestEnumSlab::with_capacity(32); + slab.reserve(64); + assert_eq!(slab.capacity(), 64); + + slab.insert(TestEnum::VariantTwo); + + let s = &slab[TestEnumKey(0)]; + assert_eq!(s, &TestEnum::VariantTwo); + + let s = &mut slab[TestEnumKey(0)]; + assert_eq!(s, &mut TestEnum::VariantTwo); } diff --git a/wrapped_slab_derive/Cargo.toml b/wrapped_slab_derive/Cargo.toml index be61d7f..ea2170e 100644 --- a/wrapped_slab_derive/Cargo.toml +++ b/wrapped_slab_derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wrapped_slab_derive" -version = "0.1.1" +version = "0.2.0" edition = "2021" authors = ["Louis Wyborn "] rust-version = "1.62" @@ -21,10 +21,10 @@ syn = { version = "1.0", features = ["full"] } quote = { version = "1.0" } # Necessary for syn and quote -proc-macro2 = { version = "1.0"} +proc-macro2 = { version = "1.0" } # Better error handling in proc macros, avoids using panic! proc-macro-error = { version = "1.0" } [lib] -proc-macro = true \ No newline at end of file +proc-macro = true diff --git a/wrapped_slab_derive/src/lib.rs b/wrapped_slab_derive/src/lib.rs index 41e7e34..06f47d6 100644 --- a/wrapped_slab_derive/src/lib.rs +++ b/wrapped_slab_derive/src/lib.rs @@ -15,11 +15,15 @@ pub fn wrapped_slab_derive(input: proc_macro::TokenStream) -> proc_macro::TokenS let slab_name = format_ident!("{element_name}Slab"); let vacant_entry_name = format_ident!("{element_name}VacantEntry"); let key_name = format_ident!("{element_name}Key"); + let iter_name = format_ident!("{element_name}Iter"); + let iter_mut_name = format_ident!("{element_name}IterMut"); + let into_iter_name = format_ident!("{element_name}IntoIter"); let expanded = quote! { #[derive(Default)] #element_vis struct #slab_name(wrapped_slab::slab::Slab<#element_name>); + #[derive(Debug)] #element_vis struct #vacant_entry_name<'a>(wrapped_slab::slab::VacantEntry<'a, #element_name>); #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] @@ -35,6 +39,134 @@ pub fn wrapped_slab_derive(input: proc_macro::TokenStream) -> proc_macro::TokenS } } + #[derive(Debug)] + #element_vis struct #iter_name<'a>(wrapped_slab::slab::Iter<'a, #element_name>); + + #[derive(Debug)] + #element_vis struct #iter_mut_name<'a>(wrapped_slab::slab::IterMut<'a, #element_name>); + + #[derive(Debug)] + #element_vis struct #into_iter_name(wrapped_slab::slab::IntoIter<#element_name>); + + impl<'a> Iterator for #iter_name<'a> { + type Item = (#key_name, &'a #element_name); + + fn next(&mut self) -> Option { + self.0.next().map(|(key, val)| (#key_name(key), val)) + } + + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + } + + impl DoubleEndedIterator for #iter_name<'_> { + fn next_back(&mut self) -> Option { + self.0.next_back().map(|(key, val)| (#key_name(key), val)) + } + } + + impl ExactSizeIterator for #iter_name<'_> { + fn len(&self) -> usize { + self.0.len() + } + } + + impl core::iter::FusedIterator for #iter_name<'_> {} + + impl<'a> Iterator for #iter_mut_name<'a> { + type Item = (#key_name, &'a mut #element_name); + + fn next(&mut self) -> Option { + self.0.next().map(|(key, val)| (#key_name(key), val)) + } + + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + } + + impl DoubleEndedIterator for #iter_mut_name<'_> { + fn next_back(&mut self) -> Option { + self.0.next_back().map(|(key, val)| (#key_name(key), val)) + } + } + + impl ExactSizeIterator for #iter_mut_name<'_> { + fn len(&self) -> usize { + self.0.len() + } + } + + impl core::iter::FusedIterator for #iter_mut_name<'_> {} + + impl Iterator for #into_iter_name { + type Item = (#key_name, #element_name); + + fn next(&mut self) -> Option { + self.0.next().map(|(key, val)| (#key_name(key), val)) + } + + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + } + + impl DoubleEndedIterator for #into_iter_name { + fn next_back(&mut self) -> Option { + self.0.next_back().map(|(key, val)| (#key_name(key), val)) + } + } + + impl ExactSizeIterator for #into_iter_name { + fn len(&self) -> usize { + self.0.len() + } + } + + impl core::iter::FusedIterator for #into_iter_name {} + + impl<'a> IntoIterator for &'a #slab_name { + type Item = (#key_name, &'a #element_name); + type IntoIter = #iter_name<'a>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } + } + + impl<'a> IntoIterator for &'a mut #slab_name { + type Item = (#key_name, &'a mut #element_name); + type IntoIter = #iter_mut_name<'a>; + + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } + } + + impl IntoIterator for #slab_name { + type Item = (#key_name, #element_name); + type IntoIter = #into_iter_name; + + fn into_iter(self) -> Self::IntoIter { + #into_iter_name(self.0.into_iter()) + } + } + + impl std::ops::Index<#key_name> for #slab_name { + type Output = #element_name; + + fn index(&self, key: #key_name) -> &#element_name { + self.0.index(key.0) + } + } + + impl std::ops::IndexMut<#key_name> for #slab_name { + fn index_mut(&mut self, key: #key_name) -> &mut #element_name { + self.0.index_mut(key.0) + } + } + impl #slab_name { pub const fn new() -> Self { Self(wrapped_slab::slab::Slab::new()) @@ -123,6 +255,18 @@ pub fn wrapped_slab_derive(input: proc_macro::TokenStream) -> proc_macro::TokenS pub fn contains(&self, key: #key_name) -> bool { self.0.contains(key.0) } + + pub fn iter(&self) -> #iter_name<'_> { + #iter_name(self.0.iter()) + } + + pub fn iter_mut(&mut self) -> #iter_mut_name<'_> { + #iter_mut_name(self.0.iter_mut()) + } + + pub fn drain(&mut self) -> wrapped_slab::slab::Drain<'_, #element_name> { + self.0.drain() + } } };