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