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}