From 435438c2d8e5b6c56e8912ae06b9063409d34105 Mon Sep 17 00:00:00 2001 From: Manuel Turetta Date: Fri, 16 Sep 2022 18:40:54 +0200 Subject: [PATCH 1/5] Add clear method to Map --- packages/storage-plus/src/map.rs | 48 ++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/packages/storage-plus/src/map.rs b/packages/storage-plus/src/map.rs index 4dcc5398b..4ba02f908 100644 --- a/packages/storage-plus/src/map.rs +++ b/packages/storage-plus/src/map.rs @@ -260,6 +260,33 @@ where } } +#[cfg(feature = "iterator")] +impl<'a, K, T> Map<'a, K, T> +where + T: Serialize + DeserializeOwned, + K: PrimaryKey<'a>, +{ + /// Clears the map, removing all elements. + pub fn clear(&self, store: &mut dyn Storage) { + const TAKE: usize = 10; + let prefix = self.no_prefix_raw(); + let mut cleared = false; + + while !cleared { + let paths = prefix + .keys_raw(store, None, None, cosmwasm_std::Order::Ascending) + .map(|raw_key| Path::::new(self.namespace, &[raw_key.as_slice()])) + // Take just TAKE elements to prevent possible heap overflow if the Map is big. + .take(TAKE) + .collect::>(); + + paths.iter().for_each(|path| store.remove(path)); + + cleared = paths.len() < TAKE; + } + } +} + #[cfg(test)] mod test { use super::*; @@ -1511,4 +1538,25 @@ mod test { assert_eq!(include.len(), 1); assert_eq!(include, vec![456]); } + + #[test] + #[cfg(feature = "iterator")] + fn clear() { + const TEST_MAP: Map<&str, u32> = Map::new("test_map"); + + let mut storage = MockStorage::new(); + TEST_MAP.save(&mut storage, "key0", &0u32).unwrap(); + TEST_MAP.save(&mut storage, "key1", &1u32).unwrap(); + TEST_MAP.save(&mut storage, "key2", &2u32).unwrap(); + TEST_MAP.save(&mut storage, "key3", &3u32).unwrap(); + TEST_MAP.save(&mut storage, "key4", &4u32).unwrap(); + + TEST_MAP.clear(&mut storage); + + assert!(!TEST_MAP.has(&mut storage, "key0")); + assert!(!TEST_MAP.has(&mut storage, "key1")); + assert!(!TEST_MAP.has(&mut storage, "key2")); + assert!(!TEST_MAP.has(&mut storage, "key3")); + assert!(!TEST_MAP.has(&mut storage, "key4")); + } } From 25a6a701179080196130ac025cafbd2a37dab98a Mon Sep 17 00:00:00 2001 From: Manuel Turetta Date: Mon, 19 Sep 2022 14:16:23 +0200 Subject: [PATCH 2/5] Add is_empty method to Map --- packages/storage-plus/src/map.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/storage-plus/src/map.rs b/packages/storage-plus/src/map.rs index 4ba02f908..b5d4730dd 100644 --- a/packages/storage-plus/src/map.rs +++ b/packages/storage-plus/src/map.rs @@ -285,6 +285,14 @@ where cleared = paths.len() < TAKE; } } + + /// Returns `true` if the map is empty. + pub fn is_empty(&self, store: &dyn Storage) -> bool { + self.no_prefix_raw() + .keys_raw(store, None, None, cosmwasm_std::Order::Ascending) + .next() + .is_none() + } } #[cfg(test)] @@ -1541,7 +1549,7 @@ mod test { #[test] #[cfg(feature = "iterator")] - fn clear() { + fn clear_works() { const TEST_MAP: Map<&str, u32> = Map::new("test_map"); let mut storage = MockStorage::new(); @@ -1559,4 +1567,19 @@ mod test { assert!(!TEST_MAP.has(&mut storage, "key3")); assert!(!TEST_MAP.has(&mut storage, "key4")); } + + #[test] + #[cfg(feature = "iterator")] + fn is_empty_works() { + const TEST_MAP: Map<&str, u32> = Map::new("test_map"); + + let mut storage = MockStorage::new(); + + assert!(TEST_MAP.is_empty(&storage)); + + TEST_MAP.save(&mut storage, "key1", &1u32).unwrap(); + TEST_MAP.save(&mut storage, "key2", &2u32).unwrap(); + + assert!(!TEST_MAP.is_empty(&storage)); + } } From 34dfdf7bd41cded8d3a06a2823b6a99a118d41b2 Mon Sep 17 00:00:00 2001 From: Manuel Turetta Date: Mon, 19 Sep 2022 15:08:26 +0200 Subject: [PATCH 3/5] Fix lint errors --- packages/storage-plus/src/map.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/storage-plus/src/map.rs b/packages/storage-plus/src/map.rs index b5d4730dd..237861e90 100644 --- a/packages/storage-plus/src/map.rs +++ b/packages/storage-plus/src/map.rs @@ -1561,11 +1561,11 @@ mod test { TEST_MAP.clear(&mut storage); - assert!(!TEST_MAP.has(&mut storage, "key0")); - assert!(!TEST_MAP.has(&mut storage, "key1")); - assert!(!TEST_MAP.has(&mut storage, "key2")); - assert!(!TEST_MAP.has(&mut storage, "key3")); - assert!(!TEST_MAP.has(&mut storage, "key4")); + assert!(!TEST_MAP.has(&storage, "key0")); + assert!(!TEST_MAP.has(&storage, "key1")); + assert!(!TEST_MAP.has(&storage, "key2")); + assert!(!TEST_MAP.has(&storage, "key3")); + assert!(!TEST_MAP.has(&storage, "key4")); } #[test] From 90db17231e15eef99b2dbacd80793859fcab072a Mon Sep 17 00:00:00 2001 From: Manuel Turetta Date: Mon, 26 Sep 2022 23:35:19 +0200 Subject: [PATCH 4/5] Apply review suggestions --- packages/storage-plus/src/map.rs | 65 +++++++++++++++----------------- 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/packages/storage-plus/src/map.rs b/packages/storage-plus/src/map.rs index 237861e90..322cdeec7 100644 --- a/packages/storage-plus/src/map.rs +++ b/packages/storage-plus/src/map.rs @@ -109,6 +109,36 @@ where from_slice(&result).map(Some) } } + + /// Clears the map, removing all elements. + #[cfg(feature = "iterator")] + pub fn clear(&self, store: &mut dyn Storage) { + const TAKE: usize = 10; + let mut cleared = false; + + while !cleared { + let paths = self + .no_prefix_raw() + .keys_raw(store, None, None, cosmwasm_std::Order::Ascending) + .map(|raw_key| Path::::new(self.namespace, &[raw_key.as_slice()])) + // Take just TAKE elements to prevent possible heap overflow if the Map is big. + .take(TAKE) + .collect::>(); + + paths.iter().for_each(|path| store.remove(path)); + + cleared = paths.len() < TAKE; + } + } + + /// Returns `true` if the map is empty. + #[cfg(feature = "iterator")] + pub fn is_empty(&self, store: &dyn Storage) -> bool { + self.no_prefix_raw() + .keys_raw(store, None, None, cosmwasm_std::Order::Ascending) + .next() + .is_none() + } } #[cfg(feature = "iterator")] @@ -260,41 +290,6 @@ where } } -#[cfg(feature = "iterator")] -impl<'a, K, T> Map<'a, K, T> -where - T: Serialize + DeserializeOwned, - K: PrimaryKey<'a>, -{ - /// Clears the map, removing all elements. - pub fn clear(&self, store: &mut dyn Storage) { - const TAKE: usize = 10; - let prefix = self.no_prefix_raw(); - let mut cleared = false; - - while !cleared { - let paths = prefix - .keys_raw(store, None, None, cosmwasm_std::Order::Ascending) - .map(|raw_key| Path::::new(self.namespace, &[raw_key.as_slice()])) - // Take just TAKE elements to prevent possible heap overflow if the Map is big. - .take(TAKE) - .collect::>(); - - paths.iter().for_each(|path| store.remove(path)); - - cleared = paths.len() < TAKE; - } - } - - /// Returns `true` if the map is empty. - pub fn is_empty(&self, store: &dyn Storage) -> bool { - self.no_prefix_raw() - .keys_raw(store, None, None, cosmwasm_std::Order::Ascending) - .next() - .is_none() - } -} - #[cfg(test)] mod test { use super::*; From 4acfd1211eec09821febfb871e4f573a5f7098b8 Mon Sep 17 00:00:00 2001 From: Manuel Turetta Date: Mon, 26 Sep 2022 23:47:08 +0200 Subject: [PATCH 5/5] Add clear and is_empty to IndexedMap --- packages/storage-plus/src/indexed_map.rs | 53 ++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/packages/storage-plus/src/indexed_map.rs b/packages/storage-plus/src/indexed_map.rs index 8fe7f725c..4ea2e4e27 100644 --- a/packages/storage-plus/src/indexed_map.rs +++ b/packages/storage-plus/src/indexed_map.rs @@ -139,6 +139,34 @@ where fn no_prefix_raw(&self) -> Prefix, T, K> { Prefix::new(self.pk_namespace, &[]) } + + /// Clears the map, removing all elements. + pub fn clear(&self, store: &mut dyn Storage) { + const TAKE: usize = 10; + let mut cleared = false; + + while !cleared { + let paths = self + .no_prefix_raw() + .keys_raw(store, None, None, cosmwasm_std::Order::Ascending) + .map(|raw_key| Path::::new(self.pk_namespace, &[raw_key.as_slice()])) + // Take just TAKE elements to prevent possible heap overflow if the Map is big. + .take(TAKE) + .collect::>(); + + paths.iter().for_each(|path| store.remove(path)); + + cleared = paths.len() < TAKE; + } + } + + /// Returns `true` if the map is empty. + pub fn is_empty(&self, store: &dyn Storage) -> bool { + self.no_prefix_raw() + .keys_raw(store, None, None, cosmwasm_std::Order::Ascending) + .next() + .is_none() + } } #[cfg(feature = "iterator")] @@ -1679,4 +1707,29 @@ mod test { ); } } + + #[test] + fn clear_works() { + let mut storage = MockStorage::new(); + let map = build_map(); + let (pks, _) = save_data(&mut storage, &map); + + map.clear(&mut storage); + + for key in pks { + assert!(!map.has(&storage, key)); + } + } + + #[test] + fn is_empty_works() { + let mut storage = MockStorage::new(); + let map = build_map(); + + assert!(map.is_empty(&storage)); + + save_data(&mut storage, &map); + + assert!(!map.is_empty(&storage)); + } }