From 3c0fd0d7897045bf1f9a89c53302c31befb599dc Mon Sep 17 00:00:00 2001 From: Eshel Date: Mon, 13 Feb 2023 00:13:18 +0200 Subject: [PATCH 1/6] Deque's pop_front() and pop_back() now return StdResult> instead of StdResult, get_at() was renamed to get() and now returns StdResult> too. --- packages/storage/src/deque_store.rs | 194 ++++++++++++++-------------- 1 file changed, 97 insertions(+), 97 deletions(-) diff --git a/packages/storage/src/deque_store.rs b/packages/storage/src/deque_store.rs index 8db35ac..727771e 100644 --- a/packages/storage/src/deque_store.rs +++ b/packages/storage/src/deque_store.rs @@ -146,12 +146,12 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { } /// gets the element at pos if within bounds - pub fn get_at(&self, storage: &dyn Storage, pos: u32) -> StdResult { + pub fn get(&self, storage: &dyn Storage, pos: u32) -> StdResult> { let len = self.get_len(storage)?; if pos >= len { - return Err(StdError::generic_err("deque_store access out of bounds")); + return Ok(None) } - self.get_at_unchecked(storage, pos) + self.get_at_unchecked(storage, pos).map(Some) } /// Used to get the indexes stored in the given page number @@ -279,25 +279,25 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { } /// Pops an item from the back - pub fn pop_back(&self, storage: &mut dyn Storage) -> StdResult { + pub fn pop_back(&self, storage: &mut dyn Storage) -> StdResult> { if let Some(len) = self.get_len(storage)?.checked_sub(1) { self.set_len(storage, len); - self.get_at_unchecked(storage, len) + self.get_at_unchecked(storage, len).map(Some) } else { - Err(StdError::generic_err("cannot pop from empty deque_store")) + Ok(None) } } /// Pops an item from the front - pub fn pop_front(&self, storage: &mut dyn Storage) -> StdResult { + pub fn pop_front(&self, storage: &mut dyn Storage) -> StdResult> { if let Some(len) = self.get_len(storage)?.checked_sub(1) { let off = self.get_off(storage)?; self.set_len(storage, len); let item = self.get_at_unchecked(storage, 0); self.set_off(storage, off.overflowing_add(1).0); - item + item.map(Some) } else { - Err(StdError::generic_err("cannot pop from empty deque_store")) + Ok(None) } } @@ -600,15 +600,15 @@ mod tests { deque_store.push_front(&mut storage, &1)?; deque_store.push_back(&mut storage, &8)?; - assert_eq!(deque_store.pop_front(&mut storage), Ok(1)); - assert_eq!(deque_store.pop_back(&mut storage), Ok(8)); - assert_eq!(deque_store.pop_front(&mut storage), Ok(2)); - assert_eq!(deque_store.pop_back(&mut storage), Ok(7)); - assert_eq!(deque_store.pop_front(&mut storage), Ok(3)); - assert_eq!(deque_store.pop_back(&mut storage), Ok(6)); - assert_eq!(deque_store.pop_front(&mut storage), Ok(4)); - assert_eq!(deque_store.pop_back(&mut storage), Ok(5)); - assert!(deque_store.pop_back(&mut storage).is_err()); + assert_eq!(deque_store.pop_front(&mut storage)?, Some(1)); + assert_eq!(deque_store.pop_back(&mut storage)?, Some(8)); + assert_eq!(deque_store.pop_front(&mut storage)?, Some(2)); + assert_eq!(deque_store.pop_back(&mut storage)?, Some(7)); + assert_eq!(deque_store.pop_front(&mut storage)?, Some(3)); + assert_eq!(deque_store.pop_back(&mut storage)?, Some(6)); + assert_eq!(deque_store.pop_front(&mut storage)?, Some(4)); + assert_eq!(deque_store.pop_back(&mut storage)?, Some(5)); + assert!(deque_store.pop_back(&mut storage)?.is_none()); Ok(()) } @@ -639,10 +639,10 @@ mod tests { assert_eq!(deque_store.get_len(&storage), Ok(4)); - assert_eq!(deque_store.get_at(&storage, 0), Ok(1234)); - assert_eq!(deque_store.get_at(&storage, 1), Ok(2143)); - assert_eq!(deque_store.get_at(&storage, 2), Ok(3412)); - assert_eq!(deque_store.get_at(&storage, 3), Ok(4321)); + assert_eq!(deque_store.get(&storage, 0)?, Some(1234)); + assert_eq!(deque_store.get(&storage, 1)?, Some(2143)); + assert_eq!(deque_store.get(&storage, 2)?, Some(3412)); + assert_eq!(deque_store.get(&storage, 3)?, Some(4321)); Ok(()) } @@ -663,46 +663,46 @@ mod tests { assert!(deque_store.remove(&mut storage, 9).is_err()); assert_eq!(deque_store.remove(&mut storage, 7), Ok(8)); - assert_eq!(deque_store.get_at(&storage, 6), Ok(7)); - assert_eq!(deque_store.get_at(&storage, 5), Ok(6)); - assert_eq!(deque_store.get_at(&storage, 4), Ok(5)); - assert_eq!(deque_store.get_at(&storage, 3), Ok(4)); - assert_eq!(deque_store.get_at(&storage, 2), Ok(3)); - assert_eq!(deque_store.get_at(&storage, 1), Ok(2)); - assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + assert_eq!(deque_store.get(&storage, 6)?, Some(7)); + assert_eq!(deque_store.get(&storage, 5)?, Some(6)); + assert_eq!(deque_store.get(&storage, 4)?, Some(5)); + assert_eq!(deque_store.get(&storage, 3)?, Some(4)); + assert_eq!(deque_store.get(&storage, 2)?, Some(3)); + assert_eq!(deque_store.get(&storage, 1)?, Some(2)); + assert_eq!(deque_store.get(&storage, 0)?, Some(1)); assert_eq!(deque_store.remove(&mut storage, 6), Ok(7)); - assert_eq!(deque_store.get_at(&storage, 5), Ok(6)); - assert_eq!(deque_store.get_at(&storage, 4), Ok(5)); - assert_eq!(deque_store.get_at(&storage, 3), Ok(4)); - assert_eq!(deque_store.get_at(&storage, 2), Ok(3)); - assert_eq!(deque_store.get_at(&storage, 1), Ok(2)); - assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + assert_eq!(deque_store.get(&storage, 5)?, Some(6)); + assert_eq!(deque_store.get(&storage, 4)?, Some(5)); + assert_eq!(deque_store.get(&storage, 3)?, Some(4)); + assert_eq!(deque_store.get(&storage, 2)?, Some(3)); + assert_eq!(deque_store.get(&storage, 1)?, Some(2)); + assert_eq!(deque_store.get(&storage, 0)?, Some(1)); assert_eq!(deque_store.remove(&mut storage, 3), Ok(4)); - assert_eq!(deque_store.get_at(&storage, 4), Ok(6)); - assert_eq!(deque_store.get_at(&storage, 3), Ok(5)); - assert_eq!(deque_store.get_at(&storage, 2), Ok(3)); - assert_eq!(deque_store.get_at(&storage, 1), Ok(2)); - assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + assert_eq!(deque_store.get(&storage, 4)?, Some(6)); + assert_eq!(deque_store.get(&storage, 3)?, Some(5)); + assert_eq!(deque_store.get(&storage, 2)?, Some(3)); + assert_eq!(deque_store.get(&storage, 1)?, Some(2)); + assert_eq!(deque_store.get(&storage, 0)?, Some(1)); assert_eq!(deque_store.remove(&mut storage, 1), Ok(2)); - assert_eq!(deque_store.get_at(&storage, 3), Ok(6)); - assert_eq!(deque_store.get_at(&storage, 2), Ok(5)); - assert_eq!(deque_store.get_at(&storage, 1), Ok(3)); - assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + assert_eq!(deque_store.get(&storage, 3)?, Some(6)); + assert_eq!(deque_store.get(&storage, 2)?, Some(5)); + assert_eq!(deque_store.get(&storage, 1)?, Some(3)); + assert_eq!(deque_store.get(&storage, 0)?, Some(1)); assert_eq!(deque_store.remove(&mut storage, 2), Ok(5)); - assert_eq!(deque_store.get_at(&storage, 2), Ok(6)); - assert_eq!(deque_store.get_at(&storage, 1), Ok(3)); - assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + assert_eq!(deque_store.get(&storage, 2)?, Some(6)); + assert_eq!(deque_store.get(&storage, 1)?, Some(3)); + assert_eq!(deque_store.get(&storage, 0)?, Some(1)); assert_eq!(deque_store.remove(&mut storage, 1), Ok(3)); - assert_eq!(deque_store.get_at(&storage, 1), Ok(6)); - assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + assert_eq!(deque_store.get(&storage, 1)?, Some(6)); + assert_eq!(deque_store.get(&storage, 0)?, Some(1)); assert_eq!(deque_store.remove(&mut storage, 1), Ok(6)); - assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + assert_eq!(deque_store.get(&storage, 0)?, Some(1)); assert_eq!(deque_store.remove(&mut storage, 0), Ok(1)); @@ -737,59 +737,59 @@ mod tests { assert!(deque_store.remove(&mut storage, 9).is_err()); assert_eq!(deque_store.remove(&mut storage, 7), Ok(8)); - assert_eq!(deque_store.get_at(&storage, 6), Ok(7)); - assert_eq!(deque_store.get_at(&storage, 5), Ok(6)); - assert_eq!(deque_store.get_at(&storage, 4), Ok(5)); - assert_eq!(deque_store.get_at(&storage, 3), Ok(4)); - assert_eq!(deque_store.get_at(&storage, 2), Ok(3)); - assert_eq!(deque_store.get_at(&storage, 1), Ok(2)); - assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + assert_eq!(deque_store.get(&storage, 6)?, Some(7)); + assert_eq!(deque_store.get(&storage, 5)?, Some(6)); + assert_eq!(deque_store.get(&storage, 4)?, Some(5)); + assert_eq!(deque_store.get(&storage, 3)?, Some(4)); + assert_eq!(deque_store.get(&storage, 2)?, Some(3)); + assert_eq!(deque_store.get(&storage, 1)?, Some(2)); + assert_eq!(deque_store.get(&storage, 0)?, Some(1)); assert_eq!(deque_store.remove(&mut storage, 6), Ok(7)); - assert_eq!(deque_store.get_at(&storage, 5), Ok(6)); - assert_eq!(deque_store.get_at(&storage, 4), Ok(5)); - assert_eq!(deque_store.get_at(&storage, 3), Ok(4)); - assert_eq!(deque_store.get_at(&storage, 2), Ok(3)); - assert_eq!(deque_store.get_at(&storage, 1), Ok(2)); - assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + assert_eq!(deque_store.get(&storage, 5)?, Some(6)); + assert_eq!(deque_store.get(&storage, 4)?, Some(5)); + assert_eq!(deque_store.get(&storage, 3)?, Some(4)); + assert_eq!(deque_store.get(&storage, 2)?, Some(3)); + assert_eq!(deque_store.get(&storage, 1)?, Some(2)); + assert_eq!(deque_store.get(&storage, 0)?, Some(1)); assert_eq!(deque_store.remove(&mut storage, 3), Ok(4)); - assert_eq!(deque_store.get_at(&storage, 4), Ok(6)); - assert_eq!(deque_store.get_at(&storage, 3), Ok(5)); - assert_eq!(deque_store.get_at(&storage, 2), Ok(3)); - assert_eq!(deque_store.get_at(&storage, 1), Ok(2)); - assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); - assert!(deque_store.get_at(&storage, 5).is_err()); + assert_eq!(deque_store.get(&storage, 4)?, Some(6)); + assert_eq!(deque_store.get(&storage, 3)?, Some(5)); + assert_eq!(deque_store.get(&storage, 2)?, Some(3)); + assert_eq!(deque_store.get(&storage, 1)?, Some(2)); + assert_eq!(deque_store.get(&storage, 0)?, Some(1)); + assert!(deque_store.get(&storage, 5)?.is_none()); deque_store.push_back(&mut storage, &5)?; - assert_eq!(deque_store.get_at(&storage, 5), Ok(5)); - assert_eq!(deque_store.get_at(&storage, 4), Ok(6)); - assert_eq!(deque_store.get_at(&storage, 3), Ok(5)); - assert_eq!(deque_store.get_at(&storage, 2), Ok(3)); - assert_eq!(deque_store.get_at(&storage, 1), Ok(2)); - assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + assert_eq!(deque_store.get(&storage, 5)?, Some(5)); + assert_eq!(deque_store.get(&storage, 4)?, Some(6)); + assert_eq!(deque_store.get(&storage, 3)?, Some(5)); + assert_eq!(deque_store.get(&storage, 2)?, Some(3)); + assert_eq!(deque_store.get(&storage, 1)?, Some(2)); + assert_eq!(deque_store.get(&storage, 0)?, Some(1)); assert_eq!(deque_store.remove(&mut storage, 1), Ok(2)); - assert_eq!(deque_store.get_at(&storage, 4), Ok(5)); - assert_eq!(deque_store.get_at(&storage, 3), Ok(6)); - assert_eq!(deque_store.get_at(&storage, 2), Ok(5)); - assert_eq!(deque_store.get_at(&storage, 1), Ok(3)); - assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + assert_eq!(deque_store.get(&storage, 4)?, Some(5)); + assert_eq!(deque_store.get(&storage, 3)?, Some(6)); + assert_eq!(deque_store.get(&storage, 2)?, Some(5)); + assert_eq!(deque_store.get(&storage, 1)?, Some(3)); + assert_eq!(deque_store.get(&storage, 0)?, Some(1)); assert_eq!(deque_store.remove(&mut storage, 2), Ok(5)); - assert_eq!(deque_store.get_at(&storage, 3), Ok(5)); - assert_eq!(deque_store.get_at(&storage, 2), Ok(6)); - assert_eq!(deque_store.get_at(&storage, 1), Ok(3)); - assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + assert_eq!(deque_store.get(&storage, 3)?, Some(5)); + assert_eq!(deque_store.get(&storage, 2)?, Some(6)); + assert_eq!(deque_store.get(&storage, 1)?, Some(3)); + assert_eq!(deque_store.get(&storage, 0)?, Some(1)); assert_eq!(deque_store.remove(&mut storage, 1), Ok(3)); - assert_eq!(deque_store.get_at(&storage, 2), Ok(5)); - assert_eq!(deque_store.get_at(&storage, 1), Ok(6)); - assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + assert_eq!(deque_store.get(&storage, 2)?, Some(5)); + assert_eq!(deque_store.get(&storage, 1)?, Some(6)); + assert_eq!(deque_store.get(&storage, 0)?, Some(1)); assert_eq!(deque_store.remove(&mut storage, 1), Ok(6)); - assert_eq!(deque_store.get_at(&storage, 1), Ok(5)); - assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + assert_eq!(deque_store.get(&storage, 1)?, Some(5)); + assert_eq!(deque_store.get(&storage, 0)?, Some(1)); assert_eq!(deque_store.remove(&mut storage, 0), Ok(1)); assert_eq!(deque_store.remove(&mut storage, 0), Ok(5)); @@ -805,14 +805,14 @@ mod tests { deque_store.push_back(&mut storage, &7)?; deque_store.push_back(&mut storage, &8)?; - assert_eq!(deque_store.get_at(&storage, 7), Ok(8)); - assert_eq!(deque_store.get_at(&storage, 6), Ok(7)); - assert_eq!(deque_store.get_at(&storage, 5), Ok(6)); - assert_eq!(deque_store.get_at(&storage, 4), Ok(5)); - assert_eq!(deque_store.get_at(&storage, 3), Ok(4)); - assert_eq!(deque_store.get_at(&storage, 2), Ok(3)); - assert_eq!(deque_store.get_at(&storage, 1), Ok(2)); - assert_eq!(deque_store.get_at(&storage, 0), Ok(1)); + assert_eq!(deque_store.get(&storage, 7)?, Some(8)); + assert_eq!(deque_store.get(&storage, 6)?, Some(7)); + assert_eq!(deque_store.get(&storage, 5)?, Some(6)); + assert_eq!(deque_store.get(&storage, 4)?, Some(5)); + assert_eq!(deque_store.get(&storage, 3)?, Some(4)); + assert_eq!(deque_store.get(&storage, 2)?, Some(3)); + assert_eq!(deque_store.get(&storage, 1)?, Some(2)); + assert_eq!(deque_store.get(&storage, 0)?, Some(1)); Ok(()) } From 4e3159073f161b008458999f53600452d5f9c701 Mon Sep 17 00:00:00 2001 From: Eshel Date: Tue, 14 Feb 2023 17:38:15 +0200 Subject: [PATCH 2/6] get_len() -> len() --- packages/storage/src/deque_store.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/storage/src/deque_store.rs b/packages/storage/src/deque_store.rs index 727771e..3060efa 100644 --- a/packages/storage/src/deque_store.rs +++ b/packages/storage/src/deque_store.rs @@ -96,7 +96,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { } /// gets the length from storage, and otherwise sets it to 0 - pub fn get_len(&self, storage: &dyn Storage) -> StdResult { + pub fn len(&self, storage: &dyn Storage) -> StdResult { let mut may_len = self.length.lock().unwrap(); match *may_len { Some(len) => Ok(len), @@ -142,12 +142,12 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { /// checks if the collection has any elements pub fn is_empty(&self, storage: &dyn Storage) -> StdResult { - Ok(self.get_len(storage)? == 0) + Ok(self.len(storage)? == 0) } /// gets the element at pos if within bounds pub fn get(&self, storage: &dyn Storage, pos: u32) -> StdResult> { - let len = self.get_len(storage)?; + let len = self.len(storage)?; if pos >= len { return Ok(None) } @@ -242,7 +242,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { /// Replaces data at a position within bounds pub fn set_at(&self, storage: &mut dyn Storage, pos: u32, item: &T) -> StdResult<()> { - let len = self.get_len(storage)?; + let len = self.len(storage)?; if pos >= len { return Err(StdError::generic_err("deque_store access out of bounds")); } @@ -262,7 +262,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { /// Pushes an item to the back pub fn push_back(&self, storage: &mut dyn Storage, item: &T) -> StdResult<()> { - let len = self.get_len(storage)?; + let len = self.len(storage)?; self.set_at_unchecked(storage, len, item)?; self.set_len(storage, len + 1); Ok(()) @@ -271,7 +271,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { /// Pushes an item to the front pub fn push_front(&self, storage: &mut dyn Storage, item: &T) -> StdResult<()> { let off = self.get_off(storage)?; - let len = self.get_len(storage)?; + let len = self.len(storage)?; self.set_off(storage, off.overflowing_sub(1).0); self.set_at_unchecked(storage, 0, item)?; self.set_len(storage, len + 1); @@ -280,7 +280,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { /// Pops an item from the back pub fn pop_back(&self, storage: &mut dyn Storage) -> StdResult> { - if let Some(len) = self.get_len(storage)?.checked_sub(1) { + if let Some(len) = self.len(storage)?.checked_sub(1) { self.set_len(storage, len); self.get_at_unchecked(storage, len).map(Some) } else { @@ -290,7 +290,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { /// Pops an item from the front pub fn pop_front(&self, storage: &mut dyn Storage) -> StdResult> { - if let Some(len) = self.get_len(storage)?.checked_sub(1) { + if let Some(len) = self.len(storage)?.checked_sub(1) { let off = self.get_off(storage)?; self.set_len(storage, len); let item = self.get_at_unchecked(storage, 0); @@ -312,7 +312,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { /// has the worst runtime and gas cost. pub fn remove(&self, storage: &mut dyn Storage, pos: u32) -> StdResult { let off = self.get_off(storage)?; - let len = self.get_len(storage)?; + let len = self.len(storage)?; if pos >= len { return Err(StdError::generic_err("deque_store access out of bounds")); } @@ -392,7 +392,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { /// Returns a readonly iterator pub fn iter(&self, storage: &'a dyn Storage) -> StdResult> { - let len = self.get_len(storage)?; + let len = self.len(storage)?; let iter = DequeStoreIter::new(self, storage, 0, len); Ok(iter) } @@ -633,11 +633,11 @@ mod tests { deque_store.push_front(&mut storage, &1234)?; deque_store.push_back(&mut storage, &4321)?; - assert_eq!(deque_store.get_len(&storage), Ok(5)); + assert_eq!(deque_store.len(&storage), Ok(5)); assert_eq!(deque_store.remove(&mut storage, 3), Ok(3333)); - assert_eq!(deque_store.get_len(&storage), Ok(4)); + assert_eq!(deque_store.len(&storage), Ok(4)); assert_eq!(deque_store.get(&storage, 0)?, Some(1234)); assert_eq!(deque_store.get(&storage, 1)?, Some(2143)); From 43090a64c11324d64fd40ec04e1363dfd1e95fce Mon Sep 17 00:00:00 2001 From: Eshel Date: Tue, 14 Feb 2023 18:00:30 +0200 Subject: [PATCH 3/6] now iter() will not skip past the end, as in cw-storage-plus() --- packages/storage/src/deque_store.rs | 38 ++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/packages/storage/src/deque_store.rs b/packages/storage/src/deque_store.rs index 3060efa..183b9dd 100644 --- a/packages/storage/src/deque_store.rs +++ b/packages/storage/src/deque_store.rs @@ -501,11 +501,22 @@ where // In practice, this enables cheap paging over the storage by calling: // `deque_store.iter().skip(start).take(length).collect()` fn nth(&mut self, n: usize) -> Option { - self.start = self.start.saturating_add(n as u32); + // make sure that we don't skip past the end + if calc_len(self.start, self.end) < n as u32 { + // mark as empty + self.start = self.end; + } else { + self.start = self.start.saturating_add(n as u32); + } self.next() } } +#[inline] +fn calc_len(head: u32, tail: u32) -> u32 { + tail.saturating_sub(head) +} + impl<'a, T, Ser> DoubleEndedIterator for DequeStoreIter<'a, T, Ser> where T: Serialize + DeserializeOwned, @@ -977,4 +988,29 @@ mod tests { Ok(()) } + + #[test] + fn test_iterator_detect_skip() { + let deque: DequeStore = DequeStore::new("test".as_bytes()); + let mut store = MockStorage::new(); + + // push some items + deque.push_back(&mut store, &1).unwrap(); + deque.push_back(&mut store, &2).unwrap(); + deque.push_back(&mut store, &3).unwrap(); + deque.push_back(&mut store, &4).unwrap(); + + let items: StdResult> = deque.iter(&store).unwrap().collect(); + assert_eq!(items.unwrap(), [1, 2, 3, 4]); + + // nth should work correctly + let mut iter = deque.iter(&store).unwrap(); + assert_eq!(iter.nth(6), None); + assert_eq!(iter.start, iter.end, "iter should detect skipping too far"); + assert_eq!(iter.next(), None); + + let mut iter = deque.iter(&store).unwrap(); + assert_eq!(iter.nth(1).unwrap().unwrap(), 2); + assert_eq!(iter.next().unwrap().unwrap(), 3); + } } From 65e75597af71889a9c6aa25ef33a2acefeaa684a Mon Sep 17 00:00:00 2001 From: Eshel Date: Tue, 14 Feb 2023 19:01:59 +0200 Subject: [PATCH 4/6] added front(), back() methods to deque, as in cosmwasm-storage-plus --- packages/storage/src/deque_store.rs | 37 +++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/packages/storage/src/deque_store.rs b/packages/storage/src/deque_store.rs index 183b9dd..0d83fef 100644 --- a/packages/storage/src/deque_store.rs +++ b/packages/storage/src/deque_store.rs @@ -154,6 +154,26 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { self.get_at_unchecked(storage, pos).map(Some) } + /// Returns the last element of the deque without removing it + pub fn front(&self, storage: &dyn Storage) -> StdResult> { + if self.len(storage)? > 0 { + let item = self.get_at_unchecked(storage, 0); + item.map(Some) + } else { + Ok(None) + } + } + + /// Returns the first element of the deque without removing it + pub fn back(&self, storage: &dyn Storage) -> StdResult> { + if let Some(len) = self.len(storage)?.checked_sub(1) { + let item = self.get_at_unchecked(storage, len); + item.map(Some) + } else { + Ok(None) + } + } + /// Used to get the indexes stored in the given page number fn get_indexes(&self, storage: &dyn Storage, page: u32) -> StdResult>> { let indexes_key = [self.as_slice(), INDEXES, page.to_be_bytes().as_slice()].concat(); @@ -1013,4 +1033,21 @@ mod tests { assert_eq!(iter.nth(1).unwrap().unwrap(), 2); assert_eq!(iter.next().unwrap().unwrap(), 3); } + + #[test] + fn front_back() { + let deque: DequeStore = DequeStore::new(b"test"); + let mut store = MockStorage::new(); + + assert_eq!(deque.back(&store).unwrap(), None); + deque.push_back(&mut store, &1).unwrap(); + assert_eq!(deque.back(&store).unwrap(), Some(1)); + assert_eq!(deque.front(&store).unwrap(), Some(1)); + deque.push_back(&mut store, &2).unwrap(); + assert_eq!(deque.back(&store).unwrap(), Some(2)); + assert_eq!(deque.front(&store).unwrap(), Some(1)); + deque.push_front(&mut store, &3).unwrap(); + assert_eq!(deque.back(&store).unwrap(), Some(2)); + assert_eq!(deque.front(&store).unwrap(), Some(3)); + } } From 2f58e5d6a8e4b2873f97ba718c5762fd398ddf9f Mon Sep 17 00:00:00 2001 From: Eshel Date: Tue, 14 Feb 2023 19:02:25 +0200 Subject: [PATCH 5/6] added the readme from cw-storage-plus as a test to see that it can be interchangable --- packages/storage/src/deque_store.rs | 59 +++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/packages/storage/src/deque_store.rs b/packages/storage/src/deque_store.rs index 0d83fef..8155e2d 100644 --- a/packages/storage/src/deque_store.rs +++ b/packages/storage/src/deque_store.rs @@ -1050,4 +1050,63 @@ mod tests { assert_eq!(deque.back(&store).unwrap(), Some(2)); assert_eq!(deque.front(&store).unwrap(), Some(3)); } + + #[test] + fn test_cw_storage_plus_readme() -> StdResult<()> { + use serde::Deserialize; + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Data { + pub name: String, + pub age: i32, + } + + const DATA: DequeStore = DequeStore::new(b"data"); + let mut store = MockStorage::new(); + + // read methods return a wrapped Option, so None if the deque is empty + let empty = DATA.front(&store)?; + assert_eq!(None, empty); + + // some example entries + let p1 = Data { + name: "admin".to_string(), + age: 1234, + }; + let p2 = Data { + name: "user".to_string(), + age: 123, + }; + + // use it like a queue by pushing and popping at opposite ends + DATA.push_back(&mut store, &p1)?; + DATA.push_back(&mut store, &p2)?; + + let admin = DATA.pop_front(&mut store)?; + assert_eq!(admin.as_ref(), Some(&p1)); + let user = DATA.pop_front(&mut store)?; + assert_eq!(user.as_ref(), Some(&p2)); + + // or push and pop at the same end to use it as a stack + DATA.push_back(&mut store, &p1)?; + DATA.push_back(&mut store, &p2)?; + + let user = DATA.pop_back(&mut store)?; + assert_eq!(user.as_ref(), Some(&p2)); + let admin = DATA.pop_back(&mut store)?; + assert_eq!(admin.as_ref(), Some(&p1)); + + // you can also iterate over it + DATA.push_front(&mut store, &p1)?; + DATA.push_front(&mut store, &p2)?; + + let all: StdResult> = DATA.iter(&store)?.collect(); + assert_eq!(all?, [p2.clone(), p1.clone()]); + + // or access an index directly + assert_eq!(DATA.get(&store, 0)?, Some(p2)); + assert_eq!(DATA.get(&store, 1)?, Some(p1)); + assert_eq!(DATA.get(&store, 3)?, None); + + Ok(()) + } } From 57a7e74c1a3a53e8d04b30090f31b25b03521d07 Mon Sep 17 00:00:00 2001 From: Eshel Date: Tue, 14 Feb 2023 19:09:31 +0200 Subject: [PATCH 6/6] clippy deque fix --- packages/storage/src/deque_store.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/storage/src/deque_store.rs b/packages/storage/src/deque_store.rs index 8155e2d..f6b94ce 100644 --- a/packages/storage/src/deque_store.rs +++ b/packages/storage/src/deque_store.rs @@ -96,6 +96,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> { } /// gets the length from storage, and otherwise sets it to 0 + #[allow(clippy::len_without_is_empty)] pub fn len(&self, storage: &dyn Storage) -> StdResult { let mut may_len = self.length.lock().unwrap(); match *may_len {