Skip to main content

topsoil_core/traits/
stored_map.rs

1// This file is part of Soil.
2
3// Copyright (C) Soil contributors.
4// Copyright (C) Parity Technologies (UK) Ltd.
5// SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later WITH Classpath-exception-2.0
6
7//! Traits and associated datatypes for managing abstract stored values.
8
9use crate::storage::StorageMap;
10use codec::FullCodec;
11use subsoil::runtime::DispatchError;
12
13/// An abstraction of a value stored within storage, but possibly as part of a larger composite
14/// item.
15pub trait StoredMap<K, T: Default> {
16	/// Get the item, or its default if it doesn't yet exist; we make no distinction between the
17	/// two.
18	fn get(k: &K) -> T;
19
20	/// Maybe mutate the item only if an `Ok` value is returned from `f`. Do nothing if an `Err` is
21	/// returned. It is removed or reset to default value if it has been mutated to `None`.
22	/// `f` will always be called with an option representing if the storage item exists (`Some<V>`)
23	/// or if the storage item does not exist (`None`), independent of the `QueryType`.
24	fn try_mutate_exists<R, E: From<DispatchError>>(
25		k: &K,
26		f: impl FnOnce(&mut Option<T>) -> Result<R, E>,
27	) -> Result<R, E>;
28
29	// Everything past here has a default implementation.
30
31	/// Mutate the item.
32	fn mutate<R>(k: &K, f: impl FnOnce(&mut T) -> R) -> Result<R, DispatchError> {
33		Self::mutate_exists(k, |maybe_account| match maybe_account {
34			Some(ref mut account) => f(account),
35			x @ None => {
36				let mut account = Default::default();
37				let r = f(&mut account);
38				*x = Some(account);
39				r
40			},
41		})
42	}
43
44	/// Mutate the item, removing or resetting to default value if it has been mutated to `None`.
45	///
46	/// This is infallible as long as the value does not get destroyed.
47	fn mutate_exists<R>(k: &K, f: impl FnOnce(&mut Option<T>) -> R) -> Result<R, DispatchError> {
48		Self::try_mutate_exists(k, |x| -> Result<R, DispatchError> { Ok(f(x)) })
49	}
50
51	/// Set the item to something new.
52	fn insert(k: &K, t: T) -> Result<(), DispatchError> {
53		Self::mutate(k, |i| *i = t)
54	}
55
56	/// Remove the item or otherwise replace it with its default value; we don't care which.
57	fn remove(k: &K) -> Result<(), DispatchError> {
58		Self::mutate_exists(k, |x| *x = None)
59	}
60}
61
62/// A shim for placing around a storage item in order to use it as a `StoredValue`. Ideally this
63/// wouldn't be needed as `StorageValue`s should blanket implement `StoredValue`s, however this
64/// would break the ability to have custom impls of `StoredValue`. The other workaround is to
65/// implement it directly in the macro.
66///
67/// This form has the advantage that two additional types are provides, `Created` and `Removed`,
68/// which are both generic events that can be tied to handlers to do something in the case of being
69/// about to create an account where one didn't previously exist (at all; not just where it used to
70/// be the default value), or where the account is being removed or reset back to the default value
71/// where previously it did exist (though may have been in a default state). This works well with
72/// system module's `CallOnCreatedAccount` and `CallKillAccount`.
73pub struct StorageMapShim<S, K, T>(core::marker::PhantomData<(S, K, T)>);
74impl<S: StorageMap<K, T, Query = T>, K: FullCodec, T: FullCodec + Default> StoredMap<K, T>
75	for StorageMapShim<S, K, T>
76{
77	fn get(k: &K) -> T {
78		S::get(k)
79	}
80	fn insert(k: &K, t: T) -> Result<(), DispatchError> {
81		S::insert(k, t);
82		Ok(())
83	}
84	fn remove(k: &K) -> Result<(), DispatchError> {
85		if S::contains_key(&k) {
86			S::remove(k);
87		}
88		Ok(())
89	}
90	fn mutate<R>(k: &K, f: impl FnOnce(&mut T) -> R) -> Result<R, DispatchError> {
91		Ok(S::mutate(k, f))
92	}
93	fn mutate_exists<R>(k: &K, f: impl FnOnce(&mut Option<T>) -> R) -> Result<R, DispatchError> {
94		S::try_mutate_exists(k, |maybe_value| {
95			let r = f(maybe_value);
96			Ok(r)
97		})
98	}
99	fn try_mutate_exists<R, E: From<DispatchError>>(
100		k: &K,
101		f: impl FnOnce(&mut Option<T>) -> Result<R, E>,
102	) -> Result<R, E> {
103		S::try_mutate_exists(k, |maybe_value| {
104			let r = f(maybe_value)?;
105			Ok(r)
106		})
107	}
108}