Skip to content

Commit

Permalink
Add remove method to Mapping (use-ink#1023)
Browse files Browse the repository at this point in the history
* Add `remove` method to `Mapping`

* Avoid loading entries during clean-up if no deep clean is required

* Change API to just clear storage instead of also returning value

* Reduce trait bound to just `EncodeLike`

* Rename `clear_entry` back to `remove`

* Replace dummy `DeepClean` type with `Pack`

* RustFmt
  • Loading branch information
HCastano authored and xgreenx committed Feb 8, 2022
1 parent efa5d0a commit 4a84f11
Showing 1 changed file with 71 additions and 3 deletions.
74 changes: 71 additions & 3 deletions crates/storage/src/lazy/mapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ where
Q: scale::EncodeLike<K>,
R: scale::EncodeLike<V> + PackedLayout,
{
push_packed_root(value, &self.storage_key(key));
push_packed_root(value, &self.storage_key(&key));
}

/// Get the `value` at `key` from the contract storage.
Expand All @@ -85,14 +85,30 @@ where
where
Q: scale::EncodeLike<K>,
{
pull_packed_root_opt(&self.storage_key(key))
pull_packed_root_opt(&self.storage_key(&key))
}

/// Clears the value at `key` from storage.
pub fn remove<Q>(&self, key: Q)
where
Q: scale::EncodeLike<K>,
{
let storage_key = self.storage_key(&key);
if <V as SpreadLayout>::REQUIRES_DEEP_CLEAN_UP {
// There are types which need to perform some action before being cleared. Here we
// indicate to those types that they should start tidying up.
if let Some(value) = self.get(key) {
<V as PackedLayout>::clear_packed(&value, &storage_key);
}
}
ink_env::clear_contract_storage(&storage_key);
}

/// Returns a `Key` pointer used internally by the storage API.
///
/// This key is a combination of the `Mapping`'s internal `offset_key`
/// and the user provided `key`.
fn storage_key<Q>(&self, key: Q) -> Key
fn storage_key<Q>(&self, key: &Q) -> Key
where
Q: scale::EncodeLike<K>,
{
Expand Down Expand Up @@ -186,4 +202,56 @@ mod tests {
})
.unwrap()
}

#[test]
fn can_clear_entries() {
ink_env::test::run_test::<ink_env::DefaultEnvironment, _>(|_| {
// We use `Pack` here since it `REQUIRES_DEEP_CLEAN_UP`
use crate::Pack;

// Given
let mut mapping: Mapping<u8, u8> = Mapping::new([0u8; 32].into());
let mut deep_mapping: Mapping<u8, Pack<u8>> = Mapping::new([1u8; 32].into());

mapping.insert(&1, &2);
assert_eq!(mapping.get(&1), Some(2));

deep_mapping.insert(&1u8, &Pack::new(Pack::new(2u8)));
assert_eq!(deep_mapping.get(&1), Some(Pack::new(2u8)));

// When
mapping.remove(&1);
deep_mapping.remove(&1);

// Then
assert_eq!(mapping.get(&1), None);
assert_eq!(deep_mapping.get(&1), None);

Ok(())
})
.unwrap()
}

#[test]
fn can_clear_unexistent_entries() {
ink_env::test::run_test::<ink_env::DefaultEnvironment, _>(|_| {
// We use `Pack` here since it `REQUIRES_DEEP_CLEAN_UP`
use crate::Pack;

// Given
let mapping: Mapping<u8, u8> = Mapping::new([0u8; 32].into());
let deep_mapping: Mapping<u8, Pack<u8>> = Mapping::new([1u8; 32].into());

// When
mapping.remove(&1);
deep_mapping.remove(&1);

// Then
assert_eq!(mapping.get(&1), None);
assert_eq!(deep_mapping.get(&1), None);

Ok(())
})
.unwrap()
}
}

0 comments on commit 4a84f11

Please sign in to comment.