referrerpolicy=no-referrer-when-downgrade

frame_support/traits/
stored_map.rs

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