From 312519344b841585390499113ec4d4b8a3551f26 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Tue, 15 Oct 2024 22:16:37 +0200 Subject: [PATCH 1/2] feat: reverse iteration --- packages/storey/src/containers/column.rs | 30 +++++++ packages/storey/src/containers/mod.rs | 102 ++++++++++++++++------- 2 files changed, 102 insertions(+), 30 deletions(-) diff --git a/packages/storey/src/containers/column.rs b/packages/storey/src/containers/column.rs index b792731..615a7c0 100644 --- a/packages/storey/src/containers/column.rs +++ b/packages/storey/src/containers/column.rs @@ -457,6 +457,8 @@ pub enum LenError { #[cfg(test)] mod tests { + use crate::containers::RevIterableAccessor as _; + use super::*; use mocks::backend::TestStorage; @@ -544,6 +546,34 @@ mod tests { ); } + #[test] + fn rev_iteration() { + let mut storage = TestStorage::new(); + + let column = Column::::new(0); + let mut access = column.access(&mut storage); + + access.push(&1337).unwrap(); + access.push(&42).unwrap(); + access.push(&9001).unwrap(); + access.remove(1).unwrap(); + + assert_eq!( + access.rev_pairs().collect::, _>>().unwrap(), + vec![(2, 9001), (0, 1337)] + ); + + assert_eq!( + access.rev_keys().collect::, _>>().unwrap(), + vec![2, 0] + ); + + assert_eq!( + access.rev_values().collect::, _>>().unwrap(), + vec![9001, 1337] + ); + } + #[test] fn bounded_iteration() { let mut storage = TestStorage::new(); diff --git a/packages/storey/src/containers/mod.rs b/packages/storey/src/containers/mod.rs index dbc469c..0144bbe 100644 --- a/packages/storey/src/containers/mod.rs +++ b/packages/storey/src/containers/mod.rs @@ -11,6 +11,7 @@ use std::marker::PhantomData; pub use column::{Column, ColumnAccess}; pub use item::{Item, ItemAccess}; pub use map::{Map, MapAccess}; +use storey_storage::RevIterableStorage; use crate::storage::IterableStorage; @@ -84,7 +85,9 @@ pub trait IterableAccessor: Sized { fn storage(&self) -> &Self::Storage; /// Iterate over key-value pairs in this collection. - fn pairs(&self) -> StorableIter<'_, Self::Storable, Self::Storage> { + fn pairs( + &self, + ) -> StorableIter::PairsIterator<'_>> { StorableIter { inner: self.storage().pairs(None, None), phantom: PhantomData, @@ -92,7 +95,9 @@ pub trait IterableAccessor: Sized { } /// Iterate over keys in this collection. - fn keys(&self) -> StorableKeys<'_, Self::Storable, Self::Storage> { + fn keys( + &self, + ) -> StorableKeys::KeysIterator<'_>> { StorableKeys { inner: self.storage().keys(None, None), phantom: PhantomData, @@ -100,7 +105,10 @@ pub trait IterableAccessor: Sized { } /// Iterate over values in this collection. - fn values(&self) -> StorableValues<'_, Self::Storable, Self::Storage> { + fn values( + &self, + ) -> StorableValues::ValuesIterator<'_>> + { StorableValues { inner: self.storage().values(None, None), phantom: PhantomData, @@ -108,6 +116,52 @@ pub trait IterableAccessor: Sized { } } +pub trait RevIterableAccessor +where + Self: IterableAccessor, + Self::Storage: RevIterableStorage, +{ + /// Iterate over key-value pairs in this collection in reverse order. + fn rev_pairs( + &self, + ) -> StorableIter::RevPairsIterator<'_>> + { + StorableIter { + inner: self.storage().rev_pairs(None, None), + phantom: PhantomData, + } + } + + /// Iterate over keys in this collection in reverse order. + fn rev_keys( + &self, + ) -> StorableKeys::RevKeysIterator<'_>> + { + StorableKeys { + inner: self.storage().rev_keys(None, None), + phantom: PhantomData, + } + } + + /// Iterate over values in this collection in reverse order. + fn rev_values( + &self, + ) -> StorableValues::RevValuesIterator<'_>> + { + StorableValues { + inner: self.storage().rev_values(None, None), + phantom: PhantomData, + } + } +} + +impl RevIterableAccessor for I +where + I: IterableAccessor, + I::Storage: RevIterableStorage, +{ +} + /// This trait extends [`IterableAccessor`] with methods for bounded iteration. Not every /// iterable collection supports it, so this trait is separate. /// @@ -129,7 +183,7 @@ pub trait BoundedIterableAccessor: IterableAccessor { &self, start: Option, end: Option, - ) -> StorableIter<'_, Self::Storable, Self::Storage> + ) -> StorableIter::PairsIterator<'_>> where B: BoundFor, { @@ -147,7 +201,7 @@ pub trait BoundedIterableAccessor: IterableAccessor { &self, start: Option, end: Option, - ) -> StorableKeys<'_, Self::Storable, Self::Storage> + ) -> StorableKeys::KeysIterator<'_>> where B: BoundFor, { @@ -165,7 +219,7 @@ pub trait BoundedIterableAccessor: IterableAccessor { &self, start: Option, end: Option, - ) -> StorableValues<'_, Self::Storable, Self::Storage> + ) -> StorableValues::ValuesIterator<'_>> where B: BoundFor, { @@ -190,19 +244,15 @@ pub trait BoundFor { } /// The iterator over key-value pairs in a collection. -pub struct StorableIter<'i, S, B> -where - S: Storable, - B: IterableStorage + 'i, -{ - inner: B::PairsIterator<'i>, +pub struct StorableIter { + inner: I, phantom: PhantomData, } -impl<'i, S, B> Iterator for StorableIter<'i, S, B> +impl Iterator for StorableIter where S: Storable, - B: IterableStorage + 'i, + I: Iterator, Vec)>, { type Item = Result<(S::Key, S::Value), KVDecodeError>; @@ -218,19 +268,15 @@ where } /// The iterator over keys in a collection. -pub struct StorableKeys<'i, S, B> -where - S: Storable, - B: IterableStorage + 'i, -{ - inner: B::KeysIterator<'i>, +pub struct StorableKeys { + inner: I, phantom: PhantomData, } -impl<'i, S, B> Iterator for StorableKeys<'i, S, B> +impl Iterator for StorableKeys where S: Storable, - B: IterableStorage + 'i, + I: Iterator>, { type Item = Result; @@ -240,19 +286,15 @@ where } /// The iterator over values in a collection. -pub struct StorableValues<'i, S, B> -where - S: Storable, - B: IterableStorage + 'i, -{ - inner: B::ValuesIterator<'i>, +pub struct StorableValues { + inner: I, phantom: PhantomData, } -impl<'i, S, B> Iterator for StorableValues<'i, S, B> +impl Iterator for StorableValues where S: Storable, - B: IterableStorage + 'i, + I: Iterator>, { type Item = Result; From 4fd8080a7d462048a9cd6b70dbc6324a5a83890a Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Wed, 16 Oct 2024 16:55:21 +0200 Subject: [PATCH 2/2] feat: bounded reverse iteration --- packages/storey/src/containers/column.rs | 49 ++++++++++++++- packages/storey/src/containers/mod.rs | 76 ++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 1 deletion(-) diff --git a/packages/storey/src/containers/column.rs b/packages/storey/src/containers/column.rs index 615a7c0..bfb6c36 100644 --- a/packages/storey/src/containers/column.rs +++ b/packages/storey/src/containers/column.rs @@ -457,7 +457,7 @@ pub enum LenError { #[cfg(test)] mod tests { - use crate::containers::RevIterableAccessor as _; + use crate::containers::{BoundedRevIterableAccessor as _, RevIterableAccessor as _}; use super::*; @@ -657,4 +657,51 @@ mod tests { vec![1337, 42, 1] ); } + + #[test] + fn bounded_rev_iteration() { + let mut storage = TestStorage::new(); + + let column = Column::::new(0); + let mut access = column.access(&mut storage); + + access.push(&1337).unwrap(); + access.push(&42).unwrap(); + access.push(&9001).unwrap(); + access.push(&1).unwrap(); + access.push(&2).unwrap(); + access.remove(2).unwrap(); + + // start and end set + assert_eq!( + access + .bounded_rev_pairs(Some(1), Some(4)) + .collect::, _>>() + .unwrap(), + vec![(3, 1), (1, 42)] + ); + assert_eq!( + access + .bounded_rev_keys(Some(1), Some(4)) + .collect::, _>>() + .unwrap(), + vec![3, 1] + ); + assert_eq!( + access + .bounded_rev_values(Some(1), Some(4)) + .collect::, _>>() + .unwrap(), + vec![1, 42] + ); + + // end unset + assert_eq!( + access + .bounded_rev_pairs(Some(1), None) + .collect::, _>>() + .unwrap(), + vec![(4, 2), (3, 1), (1, 42)] + ); + } } diff --git a/packages/storey/src/containers/mod.rs b/packages/storey/src/containers/mod.rs index 0144bbe..0b00fda 100644 --- a/packages/storey/src/containers/mod.rs +++ b/packages/storey/src/containers/mod.rs @@ -233,6 +233,82 @@ pub trait BoundedIterableAccessor: IterableAccessor { } } +/// This trait extends [`BoundedIterableAccessor`] with methods for bounded reverse iteration. +/// Not every iterable collection supports it, so this trait is separate. +/// +/// Bounded reverse iteration allows the user to specify a start and end bound for the iteration, +/// but in reverse order. +/// +/// # Why not always support bounded reverse iteration? +/// +/// The same reasons as for [bounded iteration](BoundedIterableAccessor) apply. +pub trait BoundedRevIterableAccessor +where + Self: BoundedIterableAccessor, + Self::Storage: RevIterableStorage, +{ + /// Iterate over key-value pairs in this collection in reverse order, respecting the given bounds. + fn bounded_rev_pairs( + &self, + start: Option, + end: Option, + ) -> StorableIter::RevPairsIterator<'_>> + where + B: BoundFor, + { + let start = start.map(|b| b.into_bytes()); + let end = end.map(|b| b.into_bytes()); + + StorableIter { + inner: self.storage().rev_pairs(start.as_deref(), end.as_deref()), + phantom: PhantomData, + } + } + + /// Iterate over keys in this collection in reverse order, respecting the given bounds. + fn bounded_rev_keys( + &self, + start: Option, + end: Option, + ) -> StorableKeys::RevKeysIterator<'_>> + where + B: BoundFor, + { + let start = start.map(|b| b.into_bytes()); + let end = end.map(|b| b.into_bytes()); + + StorableKeys { + inner: self.storage().rev_keys(start.as_deref(), end.as_deref()), + phantom: PhantomData, + } + } + + /// Iterate over values in this collection in reverse order, respecting the given bounds. + fn bounded_rev_values( + &self, + start: Option, + end: Option, + ) -> StorableValues::RevValuesIterator<'_>> + where + B: BoundFor, + { + let start = start.map(|b| b.into_bytes()); + let end = end.map(|b| b.into_bytes()); + + StorableValues { + inner: self.storage().rev_values(start.as_deref(), end.as_deref()), + phantom: PhantomData, + } + } +} + +impl BoundedRevIterableAccessor for I +where + I: BoundedIterableAccessor, + I::Storage: RevIterableStorage, +{ +} + /// A type that can be used as bounds for iteration over a given collection. /// /// As an example, a collection `Foo` with string-y keys can accept both `String` and