Skip to content

Commit

Permalink
Merge pull request #80 from CosmWasm/71-exclusive-bounds
Browse files Browse the repository at this point in the history
feat: inclusive/exclusive bounds
  • Loading branch information
uint authored Nov 12, 2024
2 parents 9d67cf4 + fdc255c commit c8ea56c
Show file tree
Hide file tree
Showing 9 changed files with 545 additions and 241 deletions.
216 changes: 172 additions & 44 deletions packages/cw-storey/src/backend.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::ops::Bound;

use storey::storage::{IterableStorage, RevIterableStorage, StorageBackend, StorageBackendMut};

/// A wrapper around a type implementing [`cosmwasm_std::Storage`] that integrates it with [`storey`].
Expand Down Expand Up @@ -42,18 +44,34 @@ where
type ValuesIterator<'a> = Box<dyn Iterator<Item = Vec<u8>> + 'a> where Self: 'a;
type PairsIterator<'a> = Box<dyn Iterator<Item = (Vec<u8>, Vec<u8>)> + 'a> where Self: 'a;

fn keys<'a>(&'a self, start: Option<&[u8]>, end: Option<&[u8]>) -> Self::KeysIterator<'a> {
self.0
.range_keys(start, end, cosmwasm_std::Order::Ascending)
fn keys<'a>(&'a self, start: Bound<&[u8]>, end: Bound<&[u8]>) -> Self::KeysIterator<'a> {
let (start, end) = bounds_to_option(start, end);

self.0.range_keys(
start.as_deref(),
end.as_deref(),
cosmwasm_std::Order::Ascending,
)
}

fn values<'a>(&'a self, start: Option<&[u8]>, end: Option<&[u8]>) -> Self::ValuesIterator<'a> {
self.0
.range_values(start, end, cosmwasm_std::Order::Ascending)
fn values<'a>(&'a self, start: Bound<&[u8]>, end: Bound<&[u8]>) -> Self::ValuesIterator<'a> {
let (start, end) = bounds_to_option(start, end);

self.0.range_values(
start.as_deref(),
end.as_deref(),
cosmwasm_std::Order::Ascending,
)
}

fn pairs<'a>(&'a self, start: Option<&[u8]>, end: Option<&[u8]>) -> Self::PairsIterator<'a> {
self.0.range(start, end, cosmwasm_std::Order::Ascending)
fn pairs<'a>(&'a self, start: Bound<&[u8]>, end: Bound<&[u8]>) -> Self::PairsIterator<'a> {
let (start, end) = bounds_to_option(start, end);

self.0.range(
start.as_deref(),
end.as_deref(),
cosmwasm_std::Order::Ascending,
)
}
}

Expand All @@ -65,18 +83,34 @@ where
type ValuesIterator<'a> = Box<dyn Iterator<Item = Vec<u8>> + 'a> where Self: 'a;
type PairsIterator<'a> = Box<dyn Iterator<Item = (Vec<u8>, Vec<u8>)> + 'a> where Self: 'a;

fn keys<'a>(&'a self, start: Option<&[u8]>, end: Option<&[u8]>) -> Self::KeysIterator<'a> {
self.0
.range_keys(start, end, cosmwasm_std::Order::Ascending)
fn keys<'a>(&'a self, start: Bound<&[u8]>, end: Bound<&[u8]>) -> Self::KeysIterator<'a> {
let (start, end) = bounds_to_option(start, end);

self.0.range_keys(
start.as_deref(),
end.as_deref(),
cosmwasm_std::Order::Ascending,
)
}

fn values<'a>(&'a self, start: Option<&[u8]>, end: Option<&[u8]>) -> Self::ValuesIterator<'a> {
self.0
.range_values(start, end, cosmwasm_std::Order::Ascending)
fn values<'a>(&'a self, start: Bound<&[u8]>, end: Bound<&[u8]>) -> Self::ValuesIterator<'a> {
let (start, end) = bounds_to_option(start, end);

self.0.range_values(
start.as_deref(),
end.as_deref(),
cosmwasm_std::Order::Ascending,
)
}

fn pairs<'a>(&'a self, start: Option<&[u8]>, end: Option<&[u8]>) -> Self::PairsIterator<'a> {
self.0.range(start, end, cosmwasm_std::Order::Ascending)
fn pairs<'a>(&'a self, start: Bound<&[u8]>, end: Bound<&[u8]>) -> Self::PairsIterator<'a> {
let (start, end) = bounds_to_option(start, end);

self.0.range(
start.as_deref(),
end.as_deref(),
cosmwasm_std::Order::Ascending,
)
}
}

Expand All @@ -88,30 +122,42 @@ where
type RevValuesIterator<'a> = Box<dyn Iterator<Item = Vec<u8>> + 'a> where Self: 'a;
type RevPairsIterator<'a> = Box<dyn Iterator<Item = (Vec<u8>, Vec<u8>)> + 'a> where Self: 'a;

fn rev_keys<'a>(
&'a self,
start: Option<&[u8]>,
end: Option<&[u8]>,
) -> Self::RevKeysIterator<'a> {
self.0
.range_keys(start, end, cosmwasm_std::Order::Descending)
fn rev_keys<'a>(&'a self, start: Bound<&[u8]>, end: Bound<&[u8]>) -> Self::RevKeysIterator<'a> {
let (start, end) = bounds_to_option(start, end);

self.0.range_keys(
start.as_deref(),
end.as_deref(),
cosmwasm_std::Order::Descending,
)
}

fn rev_values<'a>(
&'a self,
start: Option<&[u8]>,
end: Option<&[u8]>,
start: Bound<&[u8]>,
end: Bound<&[u8]>,
) -> Self::RevValuesIterator<'a> {
self.0
.range_values(start, end, cosmwasm_std::Order::Descending)
let (start, end) = bounds_to_option(start, end);

self.0.range_values(
start.as_deref(),
end.as_deref(),
cosmwasm_std::Order::Descending,
)
}

fn rev_pairs<'a>(
&'a self,
start: Option<&[u8]>,
end: Option<&[u8]>,
start: Bound<&[u8]>,
end: Bound<&[u8]>,
) -> Self::RevPairsIterator<'a> {
self.0.range(start, end, cosmwasm_std::Order::Descending)
let (start, end) = bounds_to_option(start, end);

self.0.range(
start.as_deref(),
end.as_deref(),
cosmwasm_std::Order::Descending,
)
}
}

Expand All @@ -123,29 +169,111 @@ where
type RevValuesIterator<'a> = Box<dyn Iterator<Item = Vec<u8>> + 'a> where Self: 'a;
type RevPairsIterator<'a> = Box<dyn Iterator<Item = (Vec<u8>, Vec<u8>)> + 'a> where Self: 'a;

fn rev_keys<'a>(
&'a self,
start: Option<&[u8]>,
end: Option<&[u8]>,
) -> Self::RevKeysIterator<'a> {
self.0
.range_keys(start, end, cosmwasm_std::Order::Descending)
fn rev_keys<'a>(&'a self, start: Bound<&[u8]>, end: Bound<&[u8]>) -> Self::RevKeysIterator<'a> {
let (start, end) = bounds_to_option(start, end);

self.0.range_keys(
start.as_deref(),
end.as_deref(),
cosmwasm_std::Order::Descending,
)
}

fn rev_values<'a>(
&'a self,
start: Option<&[u8]>,
end: Option<&[u8]>,
start: Bound<&[u8]>,
end: Bound<&[u8]>,
) -> Self::RevValuesIterator<'a> {
self.0
.range_values(start, end, cosmwasm_std::Order::Descending)
let (start, end) = bounds_to_option(start, end);

self.0.range_values(
start.as_deref(),
end.as_deref(),
cosmwasm_std::Order::Descending,
)
}

fn rev_pairs<'a>(
&'a self,
start: Option<&[u8]>,
end: Option<&[u8]>,
start: Bound<&[u8]>,
end: Bound<&[u8]>,
) -> Self::RevPairsIterator<'a> {
self.0.range(start, end, cosmwasm_std::Order::Descending)
let (start, end) = bounds_to_option(start, end);

self.0.range(
start.as_deref(),
end.as_deref(),
cosmwasm_std::Order::Descending,
)
}
}

fn bounds_to_option(start: Bound<&[u8]>, end: Bound<&[u8]>) -> (Option<Vec<u8>>, Option<Vec<u8>>) {
let start = match start {
Bound::Included(key) => Some(key.to_vec()),
Bound::Excluded(key) => {
let mut key = key.to_vec();
key.push(0);
Some(key)
}
Bound::Unbounded => None,
};

let end = match end {
Bound::Included(key) => {
let mut key = key.to_vec();
key.push(0);
Some(key)
}
Bound::Excluded(key) => Some(key.to_vec()),
Bound::Unbounded => None,
};

(start, end)
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_bounds() {
let mut cw_storage = cosmwasm_std::MemoryStorage::new();
let mut storage = CwStorage(&mut cw_storage);

storage.set(b"key1", b"value1");
storage.set(b"key2", b"value2");
storage.set(b"key3", b"value3");

let keys: Vec<Vec<u8>> = storage
.keys(Bound::Included(b"key1"), Bound::Excluded(b"key3"))
.collect();
assert_eq!(keys, vec![b"key1".to_vec(), b"key2".to_vec()]);

let keys: Vec<Vec<u8>> = storage
.keys(Bound::Excluded(b"key1"), Bound::Included(b"key3"))
.collect();
assert_eq!(keys, vec![b"key2".to_vec(), b"key3".to_vec()]);
}

#[test]
fn test_unbounded() {
let mut cw_storage = cosmwasm_std::MemoryStorage::new();
let mut storage = CwStorage(&mut cw_storage);

storage.set(b"key1", b"value1");
storage.set(b"key2", b"value2");
storage.set(b"key3", b"value3");

let keys: Vec<Vec<u8>> = storage.keys(Bound::Unbounded, Bound::Unbounded).collect();
assert_eq!(
keys,
vec![b"key1".to_vec(), b"key2".to_vec(), b"key3".to_vec()]
);

let keys: Vec<Vec<u8>> = storage
.keys(Bound::Unbounded, Bound::Excluded(b"key3"))
.collect();
assert_eq!(keys, vec![b"key1".to_vec(), b"key2".to_vec()]);
}
}
Loading

0 comments on commit c8ea56c

Please sign in to comment.