multiversx_sc/storage/mappers/
bi_di_mapper.rs

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