From 4fd8080a7d462048a9cd6b70dbc6324a5a83890a Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Wed, 16 Oct 2024 16:55:21 +0200 Subject: [PATCH] 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