Skip to content

Commit

Permalink
Merge pull request #78 from CosmWasm/70-reverse-iteration-order
Browse files Browse the repository at this point in the history
Reverse iteration order
  • Loading branch information
uint authored Oct 23, 2024
2 parents 2203ab7 + 4fd8080 commit 1b621ae
Show file tree
Hide file tree
Showing 2 changed files with 225 additions and 30 deletions.
77 changes: 77 additions & 0 deletions packages/storey/src/containers/column.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,8 @@ pub enum LenError {

#[cfg(test)]
mod tests {
use crate::containers::{BoundedRevIterableAccessor as _, RevIterableAccessor as _};

use super::*;

use mocks::backend::TestStorage;
Expand Down Expand Up @@ -544,6 +546,34 @@ mod tests {
);
}

#[test]
fn rev_iteration() {
let mut storage = TestStorage::new();

let column = Column::<u64, TestEncoding>::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::<Result<Vec<_>, _>>().unwrap(),
vec![(2, 9001), (0, 1337)]
);

assert_eq!(
access.rev_keys().collect::<Result<Vec<_>, _>>().unwrap(),
vec![2, 0]
);

assert_eq!(
access.rev_values().collect::<Result<Vec<_>, _>>().unwrap(),
vec![9001, 1337]
);
}

#[test]
fn bounded_iteration() {
let mut storage = TestStorage::new();
Expand Down Expand Up @@ -627,4 +657,51 @@ mod tests {
vec![1337, 42, 1]
);
}

#[test]
fn bounded_rev_iteration() {
let mut storage = TestStorage::new();

let column = Column::<u64, TestEncoding>::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::<Result<Vec<_>, _>>()
.unwrap(),
vec![(3, 1), (1, 42)]
);
assert_eq!(
access
.bounded_rev_keys(Some(1), Some(4))
.collect::<Result<Vec<_>, _>>()
.unwrap(),
vec![3, 1]
);
assert_eq!(
access
.bounded_rev_values(Some(1), Some(4))
.collect::<Result<Vec<_>, _>>()
.unwrap(),
vec![1, 42]
);

// end unset
assert_eq!(
access
.bounded_rev_pairs(Some(1), None)
.collect::<Result<Vec<_>, _>>()
.unwrap(),
vec![(4, 2), (3, 1), (1, 42)]
);
}
}
178 changes: 148 additions & 30 deletions packages/storey/src/containers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -84,30 +85,83 @@ 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<Self::Storable, <Self::Storage as IterableStorage>::PairsIterator<'_>> {
StorableIter {
inner: self.storage().pairs(None, None),
phantom: PhantomData,
}
}

/// Iterate over keys in this collection.
fn keys(&self) -> StorableKeys<'_, Self::Storable, Self::Storage> {
fn keys(
&self,
) -> StorableKeys<Self::Storable, <Self::Storage as IterableStorage>::KeysIterator<'_>> {
StorableKeys {
inner: self.storage().keys(None, None),
phantom: PhantomData,
}
}

/// Iterate over values in this collection.
fn values(&self) -> StorableValues<'_, Self::Storable, Self::Storage> {
fn values(
&self,
) -> StorableValues<Self::Storable, <Self::Storage as IterableStorage>::ValuesIterator<'_>>
{
StorableValues {
inner: self.storage().values(None, None),
phantom: PhantomData,
}
}
}

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<Self::Storable, <Self::Storage as RevIterableStorage>::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<Self::Storable, <Self::Storage as RevIterableStorage>::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<Self::Storable, <Self::Storage as RevIterableStorage>::RevValuesIterator<'_>>
{
StorableValues {
inner: self.storage().rev_values(None, None),
phantom: PhantomData,
}
}
}

impl<I> 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.
///
Expand All @@ -129,7 +183,7 @@ pub trait BoundedIterableAccessor: IterableAccessor {
&self,
start: Option<B>,
end: Option<B>,
) -> StorableIter<'_, Self::Storable, Self::Storage>
) -> StorableIter<Self::Storable, <Self::Storage as IterableStorage>::PairsIterator<'_>>
where
B: BoundFor<Self::Storable>,
{
Expand All @@ -147,7 +201,7 @@ pub trait BoundedIterableAccessor: IterableAccessor {
&self,
start: Option<B>,
end: Option<B>,
) -> StorableKeys<'_, Self::Storable, Self::Storage>
) -> StorableKeys<Self::Storable, <Self::Storage as IterableStorage>::KeysIterator<'_>>
where
B: BoundFor<Self::Storable>,
{
Expand All @@ -165,7 +219,7 @@ pub trait BoundedIterableAccessor: IterableAccessor {
&self,
start: Option<B>,
end: Option<B>,
) -> StorableValues<'_, Self::Storable, Self::Storage>
) -> StorableValues<Self::Storable, <Self::Storage as IterableStorage>::ValuesIterator<'_>>
where
B: BoundFor<Self::Storable>,
{
Expand All @@ -179,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<B>(
&self,
start: Option<B>,
end: Option<B>,
) -> StorableIter<Self::Storable, <Self::Storage as RevIterableStorage>::RevPairsIterator<'_>>
where
B: BoundFor<Self::Storable>,
{
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<B>(
&self,
start: Option<B>,
end: Option<B>,
) -> StorableKeys<Self::Storable, <Self::Storage as RevIterableStorage>::RevKeysIterator<'_>>
where
B: BoundFor<Self::Storable>,
{
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<B>(
&self,
start: Option<B>,
end: Option<B>,
) -> StorableValues<Self::Storable, <Self::Storage as RevIterableStorage>::RevValuesIterator<'_>>
where
B: BoundFor<Self::Storable>,
{
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<I> 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
Expand All @@ -190,19 +320,15 @@ pub trait BoundFor<T> {
}

/// 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<S, I> {
inner: I,
phantom: PhantomData<S>,
}

impl<'i, S, B> Iterator for StorableIter<'i, S, B>
impl<S, I> Iterator for StorableIter<S, I>
where
S: Storable,
B: IterableStorage + 'i,
I: Iterator<Item = (Vec<u8>, Vec<u8>)>,
{
type Item = Result<(S::Key, S::Value), KVDecodeError<S::KeyDecodeError, S::ValueDecodeError>>;

Expand All @@ -218,19 +344,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<S, I> {
inner: I,
phantom: PhantomData<S>,
}

impl<'i, S, B> Iterator for StorableKeys<'i, S, B>
impl<S, I> Iterator for StorableKeys<S, I>
where
S: Storable,
B: IterableStorage + 'i,
I: Iterator<Item = Vec<u8>>,
{
type Item = Result<S::Key, S::KeyDecodeError>;

Expand All @@ -240,19 +362,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<S, I> {
inner: I,
phantom: PhantomData<S>,
}

impl<'i, S, B> Iterator for StorableValues<'i, S, B>
impl<S, I> Iterator for StorableValues<S, I>
where
S: Storable,
B: IterableStorage + 'i,
I: Iterator<Item = Vec<u8>>,
{
type Item = Result<S::Value, S::ValueDecodeError>;

Expand Down

0 comments on commit 1b621ae

Please sign in to comment.