multiversx_sc/storage/mappers/
bi_di_mapper.rs

1use core::marker::PhantomData;
2
3use crate::{
4    abi::TypeAbiFrom,
5    codec::{
6        multi_encode_iter_or_handle_err, multi_types::MultiValue2, EncodeErrorHandler,
7        NestedDecode, NestedEncode, TopDecode, TopEncode, TopEncodeMulti, TopEncodeMultiOutput,
8    },
9    types::ManagedAddress,
10};
11
12use super::{
13    source::{CurrentStorage, StorageAddress},
14    unordered_set_mapper, StorageMapper, StorageMapperFromAddress, UnorderedSetMapper,
15};
16use crate::{
17    abi::{TypeAbi, TypeDescriptionContainer, TypeName},
18    api::StorageMapperApi,
19    storage::{storage_set, StorageKey},
20    storage_clear,
21    types::{ManagedType, MultiValueEncoded},
22};
23
24const VALUE_SUFFIX: &[u8] = b"_value";
25const ID_SUFFIX: &[u8] = b"_id";
26const VALUE_TO_ID_SUFFIX: &[u8] = b"_value_to_id";
27const ID_TO_VALUE_SUFFIX: &[u8] = b"_id_to_value";
28
29type Keys<'a, SA, T, A> = unordered_set_mapper::Iter<'a, SA, T, A>;
30
31/// A bi-directional map, from values to ids and viceversa.
32/// The mapper is based on UnorderedSetMapper, reason why the remove is done by swap_remove
33pub struct BiDiMapper<SA, K, V, A = CurrentStorage>
34where
35    SA: StorageMapperApi,
36    A: StorageAddress<SA>,
37    K: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq,
38    V: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq,
39{
40    _phantom_api: PhantomData<SA>,
41    address: A,
42    id_set_mapper: UnorderedSetMapper<SA, K, A>,
43    value_set_mapper: UnorderedSetMapper<SA, V, A>,
44    base_key: StorageKey<SA>,
45}
46
47impl<SA, K, V> StorageMapper<SA> for BiDiMapper<SA, K, V, CurrentStorage>
48where
49    SA: StorageMapperApi,
50    K: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq,
51    V: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq,
52{
53    fn new(base_key: StorageKey<SA>) -> Self {
54        let mut id_key = base_key.clone();
55        id_key.append_bytes(ID_SUFFIX);
56
57        let mut value_key = base_key.clone();
58        value_key.append_bytes(VALUE_SUFFIX);
59        BiDiMapper {
60            _phantom_api: PhantomData,
61            address: CurrentStorage,
62            id_set_mapper: UnorderedSetMapper::<SA, K>::new(id_key),
63            value_set_mapper: UnorderedSetMapper::<SA, V>::new(value_key),
64            base_key,
65        }
66    }
67}
68
69impl<SA, K, V> StorageMapperFromAddress<SA> for BiDiMapper<SA, K, V, ManagedAddress<SA>>
70where
71    SA: StorageMapperApi,
72    K: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq,
73    V: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq,
74{
75    fn new_from_address(address: ManagedAddress<SA>, base_key: StorageKey<SA>) -> Self {
76        let mut id_key = base_key.clone();
77        id_key.append_bytes(ID_SUFFIX);
78
79        let mut value_key = base_key.clone();
80        value_key.append_bytes(VALUE_SUFFIX);
81        BiDiMapper {
82            _phantom_api: PhantomData,
83            address: address.clone(),
84            id_set_mapper: UnorderedSetMapper::new_from_address(address.clone(), id_key),
85            value_set_mapper: UnorderedSetMapper::new_from_address(address, value_key),
86            base_key,
87        }
88    }
89}
90
91impl<SA, K, V, A> BiDiMapper<SA, K, V, A>
92where
93    SA: StorageMapperApi,
94    A: StorageAddress<SA>,
95    K: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq,
96    V: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq,
97{
98    fn get_id_key(&self, value: &V) -> StorageKey<SA> {
99        let mut key = self.base_key.clone();
100        key.append_bytes(VALUE_TO_ID_SUFFIX);
101        key.append_item(value);
102        key
103    }
104
105    fn get_value_key(&self, key: &K) -> StorageKey<SA> {
106        let mut value = self.base_key.clone();
107        value.append_bytes(ID_TO_VALUE_SUFFIX);
108        value.append_item(&key);
109        value
110    }
111
112    pub fn get_id(&self, value: &V) -> K {
113        self.address
114            .address_storage_get(self.get_id_key(value).as_ref())
115    }
116
117    pub fn get_value(&self, id: &K) -> V {
118        self.address
119            .address_storage_get(self.get_value_key(id).as_ref())
120    }
121
122    pub fn contains_id(&self, id: &K) -> bool {
123        self.id_set_mapper.contains(id)
124    }
125
126    pub fn contains_value(&self, value: &V) -> bool {
127        self.value_set_mapper.contains(value)
128    }
129
130    pub fn get_all_values(&self) -> unordered_set_mapper::Iter<'_, SA, V, A> {
131        self.value_set_mapper.iter()
132    }
133
134    pub fn get_all_ids(&self) -> unordered_set_mapper::Iter<'_, SA, K, A> {
135        self.id_set_mapper.iter()
136    }
137
138    pub fn iter(&self) -> Iter<'_, SA, K, V, A> {
139        Iter::new(self)
140    }
141
142    pub fn is_empty(&self) -> bool {
143        self.value_set_mapper.is_empty()
144    }
145
146    pub fn len(&self) -> usize {
147        self.value_set_mapper.len()
148    }
149}
150
151impl<SA, K, V> BiDiMapper<SA, K, V, CurrentStorage>
152where
153    SA: StorageMapperApi,
154    K: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq,
155    V: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq,
156{
157    fn set_id(&mut self, value: &V, id: &K) {
158        storage_set(self.get_id_key(value).as_ref(), id);
159    }
160
161    fn set_value(&mut self, id: &K, value: &V) {
162        storage_set(self.get_value_key(id).as_ref(), value);
163    }
164
165    fn clear_id_by_value(&self, value: &V) {
166        storage_clear(self.get_id_key(value).as_ref());
167    }
168    fn clear_value_by_id(&self, id: &K) {
169        storage_clear(self.get_value_key(id).as_ref());
170    }
171
172    pub fn insert(&mut self, id: K, value: V) -> bool {
173        if self.contains_id(&id) || self.contains_value(&value) {
174            return false;
175        }
176        self.set_id(&value, &id);
177        self.set_value(&id, &value);
178
179        self.id_set_mapper.insert(id);
180        self.value_set_mapper.insert(value);
181        true
182    }
183
184    pub fn remove_by_id(&mut self, id: &K) -> bool {
185        if self.id_set_mapper.swap_remove(id) {
186            let value = self.get_value(id);
187            self.clear_id_by_value(&value);
188            self.clear_value_by_id(id);
189            storage_clear(self.get_value_key(id).as_ref());
190            self.value_set_mapper.swap_remove(&value);
191            return true;
192        }
193        false
194    }
195    pub fn remove_by_value(&mut self, value: &V) -> bool {
196        if self.value_set_mapper.swap_remove(value) {
197            let id = self.get_id(value);
198            self.clear_id_by_value(value);
199            self.clear_value_by_id(&id);
200            self.id_set_mapper.swap_remove(&id);
201            return true;
202        }
203        false
204    }
205
206    pub fn remove_all_by_ids<I>(&mut self, iter: I)
207    where
208        I: IntoIterator<Item = K>,
209    {
210        for item in iter {
211            self.remove_by_id(&item);
212        }
213    }
214
215    pub fn remove_all_by_values<I>(&mut self, iter: I)
216    where
217        I: IntoIterator<Item = V>,
218    {
219        for item in iter {
220            self.remove_by_value(&item);
221        }
222    }
223}
224
225impl<'a, SA, K, V, A> IntoIterator for &'a BiDiMapper<SA, K, V, A>
226where
227    SA: StorageMapperApi,
228    A: StorageAddress<SA>,
229    K: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq,
230    V: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq,
231{
232    type Item = (K, V);
233
234    type IntoIter = Iter<'a, SA, K, V, A>;
235
236    fn into_iter(self) -> Self::IntoIter {
237        self.iter()
238    }
239}
240
241pub struct Iter<'a, SA, K, V, A>
242where
243    SA: StorageMapperApi,
244    A: StorageAddress<SA>,
245    K: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq,
246    V: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq,
247{
248    key_iter: Keys<'a, SA, K, A>,
249    hash_map: &'a BiDiMapper<SA, K, V, A>,
250}
251
252impl<'a, SA, K, V, A> Iter<'a, SA, K, V, A>
253where
254    SA: StorageMapperApi,
255    A: StorageAddress<SA>,
256    K: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq,
257    V: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq,
258{
259    fn new(hash_map: &'a BiDiMapper<SA, K, V, A>) -> Iter<'a, SA, K, V, A> {
260        Iter {
261            key_iter: hash_map.get_all_ids(),
262            hash_map,
263        }
264    }
265}
266
267impl<SA, K, V, A> Iterator for Iter<'_, SA, K, V, A>
268where
269    SA: StorageMapperApi,
270    A: StorageAddress<SA>,
271    K: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq,
272    V: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq,
273{
274    type Item = (K, V);
275
276    #[inline]
277    fn next(&mut self) -> Option<(K, V)> {
278        if let Some(key) = self.key_iter.next() {
279            let value = self.hash_map.get_value(&key);
280            return Some((key, value));
281        }
282        None
283    }
284}
285
286impl<SA, K, V> TopEncodeMulti for BiDiMapper<SA, K, V, CurrentStorage>
287where
288    SA: StorageMapperApi,
289    K: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq,
290    V: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq,
291{
292    fn multi_encode_or_handle_err<O, H>(&self, output: &mut O, h: H) -> Result<(), H::HandledErr>
293    where
294        O: TopEncodeMultiOutput,
295        H: EncodeErrorHandler,
296    {
297        let iter = self.iter().map(MultiValue2::<K, V>::from);
298        multi_encode_iter_or_handle_err(iter, output, h)
299    }
300}
301
302impl<SA, K, V> TypeAbiFrom<BiDiMapper<SA, K, V, CurrentStorage>>
303    for MultiValueEncoded<SA, MultiValue2<K, V>>
304where
305    SA: StorageMapperApi,
306    K: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq,
307    V: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq,
308{
309}
310
311impl<SA, K, V> TypeAbiFrom<Self> for BiDiMapper<SA, K, V, CurrentStorage>
312where
313    SA: StorageMapperApi,
314    K: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq,
315    V: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static + Default + PartialEq,
316{
317}
318
319impl<SA, K, V> TypeAbi for BiDiMapper<SA, K, V, CurrentStorage>
320where
321    SA: StorageMapperApi,
322    K: TopEncode
323        + TopDecode
324        + NestedEncode
325        + NestedDecode
326        + 'static
327        + Default
328        + PartialEq
329        + TypeAbi,
330    V: TopEncode
331        + TopDecode
332        + NestedEncode
333        + NestedDecode
334        + 'static
335        + Default
336        + PartialEq
337        + TypeAbi,
338{
339    type Unmanaged = Self;
340
341    fn type_name() -> TypeName {
342        MultiValueEncoded::<SA, MultiValue2<K, V>>::type_name()
343    }
344
345    fn type_name_rust() -> TypeName {
346        MultiValueEncoded::<SA, MultiValue2<K, V>>::type_name_rust()
347    }
348
349    fn provide_type_descriptions<TDC: TypeDescriptionContainer>(accumulator: &mut TDC) {
350        K::provide_type_descriptions(accumulator);
351        V::provide_type_descriptions(accumulator);
352    }
353    fn is_variadic() -> bool {
354        true
355    }
356}