gear_common/storage/primitives/
double_map.rs

1// This file is part of Gear.
2
3// Copyright (C) 2022-2025 Gear Technologies Inc.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19//! Module for double map storing primitive.
20//!
21//! This primitive defines interface of interaction
22//! with globally stored double-key map (Key1 -> Key2 -> Value).
23
24/// Represents logic of managing globally stored
25/// double-key map for more complicated logic.
26///
27/// In fact, represents custom implementation/wrapper
28/// around of Substrate's `StorageDoubleMap` with `OptionQuery`.
29pub trait DoubleMapStorage {
30    /// Map's first key type.
31    type Key1;
32    /// Map's second key type.
33    type Key2;
34    /// Map's stored value type.
35    type Value;
36
37    /// Returns bool, defining does map contain value under given keys.
38    fn contains_keys(key1: &Self::Key1, key2: &Self::Key2) -> bool;
39
40    /// Gets value stored under given keys, if present.
41    fn get(key1: &Self::Key1, key2: &Self::Key2) -> Option<Self::Value>;
42
43    /// Inserts value with given keys.
44    fn insert(key1: Self::Key1, key2: Self::Key2, value: Self::Value);
45
46    /// Mutates value by `Option` reference, which stored (or not
47    /// in `None` case) under given keys with given function.
48    ///
49    /// May return generic type value.
50    fn mutate<R, F: FnOnce(&mut Option<Self::Value>) -> R>(
51        key1: Self::Key1,
52        key2: Self::Key2,
53        f: F,
54    ) -> R;
55
56    /// Works the same as `Self::mutate`, but triggers if value present.
57    fn mutate_exists<R, F: FnOnce(&mut Self::Value) -> R>(
58        key1: Self::Key1,
59        key2: Self::Key2,
60        f: F,
61    ) -> Option<R> {
62        Self::mutate(key1, key2, |opt_val| opt_val.as_mut().map(f))
63    }
64
65    /// Mutates all stored values with given convert function.
66    fn mutate_values<F: FnMut(Self::Value) -> Self::Value>(f: F);
67
68    /// Removes value stored under the given keys.
69    fn remove(key1: Self::Key1, key2: Self::Key2);
70
71    /// Removes all values.
72    fn clear();
73
74    /// Gets value stored under given keys, if present,
75    /// and removes it from storage.
76    fn take(key1: Self::Key1, key2: Self::Key2) -> Option<Self::Value>;
77
78    /// Remove items from the map matching a `first_key` prefix.
79    fn clear_prefix(first_key: Self::Key1);
80}
81
82/// Creates new type with specified name and key1-key2-value types and
83/// implements `DoubleMapStorage` for it based on specified storage,
84/// which is a `Substrate`'s `StorageDoubleMap`.
85///
86/// This macro main purpose is to follow newtype pattern
87/// and avoid `Substrate` dependencies in `gear_common`.
88///
89/// Requires `PhantomData` be in scope: from `std`, `core` or `sp_std`.
90///
91/// Requires `Config` be in scope of the crate root where it called.
92#[allow(clippy::crate_in_macro_def)]
93#[macro_export]
94macro_rules! wrap_storage_double_map {
95    (storage: $storage: ident, name: $name: ident, key1: $key1: ty,
96        key2: $key2: ty, value: $val: ty) => {
97        pub struct $name<T>(PhantomData<T>);
98
99        impl<T: crate::Config> DoubleMapStorage for $name<T> {
100            type Key1 = $key1;
101            type Key2 = $key2;
102            type Value = $val;
103
104            fn contains_keys(key1: &Self::Key1, key2: &Self::Key2) -> bool {
105                $storage::<T>::contains_key(key1, key2)
106            }
107
108            fn get(key1: &Self::Key1, key2: &Self::Key2) -> Option<Self::Value> {
109                $storage::<T>::get(key1, key2)
110            }
111
112            fn insert(key1: Self::Key1, key2: Self::Key2, value: Self::Value) {
113                $storage::<T>::insert(key1, key2, value)
114            }
115
116            fn mutate<R, F: FnOnce(&mut Option<Self::Value>) -> R>(
117                key1: Self::Key1,
118                key2: Self::Key2,
119                f: F,
120            ) -> R {
121                $storage::<T>::mutate(key1, key2, f)
122            }
123
124            fn mutate_values<F: FnMut(Self::Value) -> Self::Value>(mut f: F) {
125                let f = |v| Some(f(v));
126                $storage::<T>::translate_values(f)
127            }
128
129            fn remove(key1: Self::Key1, key2: Self::Key2) {
130                $storage::<T>::remove(key1, key2)
131            }
132
133            fn clear() {
134                let _ = $storage::<T>::clear(u32::MAX, None);
135            }
136
137            fn take(key1: Self::Key1, key2: Self::Key2) -> Option<Self::Value> {
138                $storage::<T>::take(key1, key2)
139            }
140
141            fn clear_prefix(first_key: Self::Key1) {
142                let _ = $storage::<T>::clear_prefix(first_key, u32::MAX, None);
143            }
144        }
145    };
146}
147
148/// Same as `wrap_storage_double_map!`, but with extra implementations
149/// of `CountedByKey`, `IterableMap` and `IterableByKeyMap`
150/// over double map values.
151///
152/// `PrefixIterator` from `frame_support` and `KeyValueIteratorWrap` from
153/// this crate should be in scope.
154#[allow(clippy::crate_in_macro_def)]
155#[macro_export]
156macro_rules! wrap_extended_storage_double_map {
157    (storage: $storage: ident, name: $name: ident, key1: $key1: ty,
158        key2: $key2: ty, value: $val: ty, length: $len: ty) => {
159        $crate::wrap_storage_double_map!(
160            storage: $storage,
161            name: $name,
162            key1: $key1,
163            key2: $key2,
164            value: $val
165        );
166
167        impl<T: crate::Config> CountedByKey for $name<T> {
168            type Key = $key1;
169            type Length = $len;
170
171            fn len(key: &Self::Key) -> Self::Length {
172                $storage::<T>::iter_prefix(key).count()
173            }
174        }
175
176        impl<T: crate::Config> IterableByKeyMap<$val> for $name<T> {
177            type Key = $key1;
178            type DrainIter = IteratorWrap<PrefixIterator<($key2, $val)>, $val, GetSecondPos>;
179            type Iter = IteratorWrap<PrefixIterator<($key2, $val)>, $val, GetSecondPos>;
180
181            fn drain_key(key: Self::Key) -> Self::DrainIter {
182                $storage::<T>::drain_prefix(key).into()
183            }
184
185            fn iter_key(key: Self::Key) -> Self::Iter {
186                $storage::<T>::iter_prefix(key).into()
187            }
188        }
189
190        impl<T: crate::Config> IterableMap<$val> for $name<T> {
191            type DrainIter = IteratorWrap<PrefixIterator<($key1, $key2, $val)>, $val, GetThirdPos>;
192            type Iter = IteratorWrap<PrefixIterator<($key1, $key2, $val)>, $val, GetThirdPos>;
193
194            fn drain() -> Self::DrainIter {
195                $storage::<T>::drain().into()
196            }
197
198            fn iter() -> Self::Iter {
199                $storage::<T>::iter().into()
200            }
201        }
202
203        impl<T: crate::Config> KeyIterableByKeyMap for $name<T> {
204            type Key1 = $key1;
205            type Key2 = $key2;
206            type DrainIter = IteratorWrap<PrefixIterator<($key2, $val)>, $key2, GetFirstPos>;
207            type Iter = IteratorWrap<PrefixIterator<($key2, $val)>, $key2, GetFirstPos>;
208
209            fn drain_prefix_keys(key: Self::Key1) -> Self::DrainIter {
210                $storage::<T>::drain_prefix(key).into()
211            }
212
213            fn iter_prefix_keys(key: Self::Key1) -> Self::Iter {
214                $storage::<T>::iter_prefix(key).into()
215            }
216        }
217    };
218}