multiversx_sc/storage/mappers/
set_mapper.rs

1use core::marker::PhantomData;
2
3pub use super::queue_mapper::Iter;
4use super::{QueueMapper, StorageClearable, StorageMapper, StorageMapperFromAddress};
5use crate::{
6    abi::{TypeAbi, TypeAbiFrom, TypeDescriptionContainer, TypeName},
7    api::StorageMapperApi,
8    codec::{
9        self, multi_encode_iter_or_handle_err, EncodeErrorHandler, NestedDecode, NestedEncode,
10        TopDecode, TopEncode, TopEncodeMulti, TopEncodeMultiOutput,
11    },
12    storage::{
13        mappers::source::{CurrentStorage, StorageAddress},
14        storage_set, StorageKey,
15    },
16    types::{ManagedAddress, ManagedType, MultiValueEncoded},
17};
18
19const NULL_ENTRY: u32 = 0;
20const NODE_ID_IDENTIFIER: &[u8] = b".node_id";
21
22pub struct SetMapper<SA, T, A = CurrentStorage>
23where
24    SA: StorageMapperApi,
25    A: StorageAddress<SA>,
26    T: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static,
27{
28    _phantom_api: PhantomData<SA>,
29    address: A,
30    base_key: StorageKey<SA>,
31    queue_mapper: QueueMapper<SA, T, A>,
32}
33
34impl<SA, T> StorageMapper<SA> for SetMapper<SA, T, CurrentStorage>
35where
36    SA: StorageMapperApi,
37    T: TopEncode + TopDecode + NestedEncode + NestedDecode,
38{
39    fn new(base_key: StorageKey<SA>) -> Self {
40        SetMapper {
41            _phantom_api: PhantomData,
42            address: CurrentStorage,
43            base_key: base_key.clone(),
44            queue_mapper: QueueMapper::new(base_key),
45        }
46    }
47}
48
49impl<SA, T> StorageClearable for SetMapper<SA, T, CurrentStorage>
50where
51    SA: StorageMapperApi,
52    T: TopEncode + TopDecode + NestedEncode + NestedDecode,
53{
54    fn clear(&mut self) {
55        for value in self.queue_mapper.iter() {
56            self.clear_node_id(&value);
57        }
58        self.queue_mapper.clear();
59    }
60}
61
62impl<SA, T> StorageMapperFromAddress<SA> for SetMapper<SA, T, ManagedAddress<SA>>
63where
64    SA: StorageMapperApi,
65    T: TopEncode + TopDecode + NestedEncode + NestedDecode,
66{
67    fn new_from_address(address: ManagedAddress<SA>, base_key: StorageKey<SA>) -> Self {
68        SetMapper {
69            _phantom_api: PhantomData,
70            address: address.clone(),
71            base_key: base_key.clone(),
72            queue_mapper: QueueMapper::new_from_address(address, base_key),
73        }
74    }
75}
76
77impl<SA, T> SetMapper<SA, T, CurrentStorage>
78where
79    SA: StorageMapperApi,
80    T: TopEncode + TopDecode + NestedEncode + NestedDecode,
81{
82    fn set_node_id(&self, value: &T, node_id: u32) {
83        storage_set(
84            self.build_named_value_key(NODE_ID_IDENTIFIER, value)
85                .as_ref(),
86            &node_id,
87        );
88    }
89
90    fn clear_node_id(&self, value: &T) {
91        storage_set(
92            self.build_named_value_key(NODE_ID_IDENTIFIER, value)
93                .as_ref(),
94            &codec::Empty,
95        );
96    }
97
98    /// Adds a value to the set.
99    ///
100    /// If the set did not have this value present, `true` is returned.
101    ///
102    /// If the set did have this value present, `false` is returned.
103    pub fn insert(&mut self, value: T) -> bool {
104        if self.contains(&value) {
105            return false;
106        }
107        let new_node_id = self.queue_mapper.push_back_node_id(&value);
108        self.set_node_id(&value, new_node_id);
109        true
110    }
111
112    /// Removes a value from the set. Returns whether the value was
113    /// present in the set.
114    pub fn remove(&mut self, value: &T) -> bool {
115        let node_id = self.get_node_id(value);
116        if node_id == NULL_ENTRY {
117            return false;
118        }
119        self.queue_mapper.remove_by_node_id(node_id);
120        self.clear_node_id(value);
121        true
122    }
123
124    pub fn remove_all<I>(&mut self, iter: I)
125    where
126        I: IntoIterator<Item = T>,
127    {
128        for item in iter {
129            self.remove(&item);
130        }
131    }
132}
133
134impl<SA, A, T> SetMapper<SA, T, A>
135where
136    SA: StorageMapperApi,
137    A: StorageAddress<SA>,
138    T: TopEncode + TopDecode + NestedEncode + NestedDecode,
139{
140    pub fn build_named_value_key(&self, name: &[u8], value: &T) -> StorageKey<SA> {
141        let mut named_key = self.base_key.clone();
142        named_key.append_bytes(name);
143        named_key.append_item(value);
144        named_key
145    }
146
147    /// An iterator visiting all elements in arbitrary order.
148    /// The iterator element type is `&'a T`.
149    pub fn iter(&self) -> Iter<'_, SA, A, T> {
150        self.queue_mapper.iter()
151    }
152
153    pub fn iter_from(&self, value: &T) -> Iter<'_, SA, A, T> {
154        let node_id = self.get_node_id(value);
155        self.queue_mapper.iter_from_node_id(node_id)
156    }
157
158    fn get_node_id(&self, value: &T) -> u32 {
159        self.address.address_storage_get(
160            self.build_named_value_key(NODE_ID_IDENTIFIER, value)
161                .as_ref(),
162        )
163    }
164
165    /// Returns `true` if the set contains a value.
166    pub fn contains(&self, value: &T) -> bool {
167        self.get_node_id(value) != NULL_ENTRY
168    }
169
170    /// Returns `true` if the set contains no elements.
171    pub fn is_empty(&self) -> bool {
172        self.queue_mapper.is_empty()
173    }
174
175    /// Returns the number of elements in the set.
176    pub fn len(&self) -> usize {
177        self.queue_mapper.len()
178    }
179
180    /// Checks the internal consistency of the collection. Used for unit tests.
181    pub fn check_internal_consistency(&self) -> bool {
182        self.queue_mapper.check_internal_consistency()
183    }
184
185    pub fn next(&self, value: &T) -> Option<T> {
186        let node_id = self.get_node_id(value);
187        if node_id == NULL_ENTRY {
188            return None;
189        }
190
191        let next_node_id = self.queue_mapper.get_node(node_id).next;
192
193        self.queue_mapper.get_value_option(next_node_id)
194    }
195
196    pub fn previous(&self, value: &T) -> Option<T> {
197        let node_id = self.get_node_id(value);
198        if node_id == NULL_ENTRY {
199            return None;
200        }
201
202        let next_node_id = self.queue_mapper.get_node(node_id).previous;
203
204        self.queue_mapper.get_value_option(next_node_id)
205    }
206
207    pub fn front(&self) -> Option<T> {
208        self.queue_mapper.front()
209    }
210
211    pub fn back(&self) -> Option<T> {
212        self.queue_mapper.back()
213    }
214}
215
216impl<'a, SA, A, T> IntoIterator for &'a SetMapper<SA, T, A>
217where
218    SA: StorageMapperApi,
219    A: StorageAddress<SA>,
220    T: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static,
221{
222    type Item = T;
223
224    type IntoIter = Iter<'a, SA, A, T>;
225
226    fn into_iter(self) -> Self::IntoIter {
227        self.iter()
228    }
229}
230
231impl<SA, T> Extend<T> for SetMapper<SA, T, CurrentStorage>
232where
233    SA: StorageMapperApi,
234    T: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static,
235{
236    fn extend<I>(&mut self, iter: I)
237    where
238        I: IntoIterator<Item = T>,
239    {
240        for item in iter {
241            self.insert(item);
242        }
243    }
244}
245
246/// Behaves like a MultiResultVec when an endpoint result.
247impl<SA, T> TopEncodeMulti for SetMapper<SA, T, CurrentStorage>
248where
249    SA: StorageMapperApi,
250    T: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static,
251{
252    fn multi_encode_or_handle_err<O, H>(&self, output: &mut O, h: H) -> Result<(), H::HandledErr>
253    where
254        O: TopEncodeMultiOutput,
255        H: EncodeErrorHandler,
256    {
257        multi_encode_iter_or_handle_err(self.iter(), output, h)
258    }
259}
260
261impl<SA, T> TypeAbiFrom<SetMapper<SA, T, CurrentStorage>> for MultiValueEncoded<SA, T>
262where
263    SA: StorageMapperApi,
264    T: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static,
265{
266}
267
268impl<SA, T> TypeAbiFrom<Self> for SetMapper<SA, T, CurrentStorage>
269where
270    SA: StorageMapperApi,
271    T: TopEncode + TopDecode + NestedEncode + NestedDecode + 'static,
272{
273}
274
275/// Behaves like a MultiResultVec when an endpoint result.
276impl<SA, T> TypeAbi for SetMapper<SA, T, CurrentStorage>
277where
278    SA: StorageMapperApi,
279    T: TopEncode + TopDecode + NestedEncode + NestedDecode + TypeAbi,
280{
281    type Unmanaged = Self;
282
283    fn type_name() -> TypeName {
284        crate::abi::type_name_variadic::<T>()
285    }
286
287    fn type_name_rust() -> TypeName {
288        crate::abi::type_name_multi_value_encoded::<T>()
289    }
290
291    fn provide_type_descriptions<TDC: TypeDescriptionContainer>(accumulator: &mut TDC) {
292        T::provide_type_descriptions(accumulator);
293    }
294
295    fn is_variadic() -> bool {
296        true
297    }
298}