Skip to main content

gear_common/storage/primitives/
map.rs

1// Copyright (C) Gear Technologies Inc.
2// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
3
4//! Module for map storing primitive.
5//!
6//! This primitive defines interface of interaction
7//! with globally stored single-key map (Key -> Value).
8
9use sp_runtime::codec::{Encode, EncodeAppend, EncodeLike};
10/// Represents logic of managing globally stored
11/// single-key map for more complicated logic.
12///
13/// In fact, represents custom implementation/wrapper
14/// around of Substrate's `StorageMap` with `OptionQuery`.
15pub trait MapStorage {
16    /// Map's key type.
17    type Key;
18    /// Map's stored value type.
19    type Value;
20
21    /// Returns bool, defining does map contain value under given key.
22    fn contains_key(key: &Self::Key) -> bool;
23
24    /// Gets value stored under given key, if present.
25    fn get(key: &Self::Key) -> Option<Self::Value>;
26
27    /// Inserts value with given key.
28    fn insert(key: Self::Key, value: Self::Value);
29
30    /// Mutates value by `Option` reference, which stored (or not
31    /// in `None` case) under given key with given function.
32    ///
33    /// May return generic type value.
34    fn mutate<R, F: FnOnce(&mut Option<Self::Value>) -> R>(key: Self::Key, f: F) -> R;
35
36    /// Works the same as `Self::mutate`, but triggers if value present.
37    fn mutate_exists<R, F: FnOnce(&mut Self::Value) -> R>(key: Self::Key, f: F) -> Option<R> {
38        Self::mutate(key, |opt_val| opt_val.as_mut().map(f))
39    }
40
41    /// Mutates all stored values with given convert function.
42    fn mutate_values<F: FnMut(Self::Value) -> Self::Value>(f: F);
43
44    /// Removes value stored under the given key.
45    fn remove(key: Self::Key);
46
47    /// Removes all values.
48    fn clear();
49
50    /// Gets value stored under given key, if present,
51    /// and removes it from storage.
52    fn take(key: Self::Key) -> Option<Self::Value>;
53}
54
55pub trait AppendMapStorage<Item, Key, Value>: MapStorage<Key = Key, Value = Value>
56where
57    Item: Encode,
58    Key: Encode,
59    Value: EncodeAppend<Item = Item>,
60{
61    fn append<EncodeLikeKey, EncodeLikeItem>(key: EncodeLikeKey, item: EncodeLikeItem)
62    where
63        EncodeLikeKey: EncodeLike<Key>,
64        EncodeLikeItem: EncodeLike<Item>;
65}
66
67/// Creates new type with specified name and key-value types and implements
68/// `MapStorage` for it based on specified storage,
69/// which is a `Substrate`'s `StorageMap`.
70///
71/// This macro main purpose is to follow newtype pattern
72/// and avoid `Substrate` dependencies in `gear_common`.
73///
74/// Requires `PhantomData` be in scope: from `std`, `core` or `sp_std`.
75///
76/// Requires `Config` be in scope of the crate root where it called.
77///
78/// Has two implementations to provide auto addition of `Counted` logic
79/// (for `Substrate`'s `CountedStorageMap`) due to storage's
80/// arguments difference.
81#[allow(clippy::crate_in_macro_def)]
82#[macro_export]
83macro_rules! wrap_storage_map {
84    (storage: $storage: ident, name: $name: ident, key: $key: ty, value: $val: ty) => {
85        pub struct $name<T>(PhantomData<T>);
86
87        impl<T: crate::Config> MapStorage for $name<T> {
88            type Key = $key;
89            type Value = $val;
90
91            fn contains_key(key: &Self::Key) -> bool {
92                $storage::<T>::contains_key(key)
93            }
94
95            fn get(key: &Self::Key) -> Option<Self::Value> {
96                $storage::<T>::get(key)
97            }
98
99            fn insert(key: Self::Key, value: Self::Value) {
100                $storage::<T>::insert(key, value)
101            }
102
103            fn mutate<R, F: FnOnce(&mut Option<Self::Value>) -> R>(key: Self::Key, f: F) -> R {
104                $storage::<T>::mutate(key, f)
105            }
106
107            fn mutate_values<F: FnMut(Self::Value) -> Self::Value>(mut f: F) {
108                let f = |v| Some(f(v));
109                $storage::<T>::translate_values(f)
110            }
111
112            fn remove(key: Self::Key) {
113                $storage::<T>::remove(key)
114            }
115
116            fn clear() {
117                let _ = $storage::<T>::clear(u32::MAX, None);
118            }
119
120            fn take(key: Self::Key) -> Option<Self::Value> {
121                $storage::<T>::take(key)
122            }
123        }
124    };
125}
126
127/// Same as `wrap_storage_map!`, but with length type parameter
128/// to auto-impl `Counted` trait of `gear_common` storage primitives.
129///
130/// Better to use Rust's numeric types as `Length`.
131#[allow(clippy::crate_in_macro_def)]
132#[macro_export]
133macro_rules! wrap_counted_storage_map {
134    (storage: $storage: ident, name: $name: ident, key: $key: ty, value: $val: ty, length: $len: ty) => {
135        $crate::wrap_storage_map!(storage: $storage, name: $name, key: $key, value: $val);
136
137        impl<T: crate::Config> Counted for $name<T> {
138            type Length = $len;
139
140            fn len() -> Self::Length {
141                $storage::<T>::count() as Self::Length
142            }
143        }
144    };
145}