multiversx_sc/storage/mappers/
unique_id_mapper.rs

1use crate::{
2    abi::TypeAbiFrom,
3    codec::{
4        EncodeErrorHandler, TopEncodeMulti, TopEncodeMultiOutput, multi_encode_iter_or_handle_err,
5    },
6    types::ManagedAddress,
7};
8
9use super::{
10    StorageMapper, StorageMapperFromAddress, VecMapper,
11    source::{CurrentStorage, StorageAddress},
12};
13use crate::{
14    abi::{TypeAbi, TypeDescriptionContainer, TypeName},
15    api::{ErrorApiImpl, StorageMapperApi},
16    storage::StorageKey,
17    storage_set,
18    types::{ManagedType, MultiValueEncoded},
19};
20
21pub type UniqueId = usize;
22const EMPTY_ENTRY: UniqueId = 0;
23
24/// Holds the values from 1 to N with as little storage interaction as possible
25/// If Mapper[i] = i, then it stores nothing, i.e. "0"
26/// If Mapper[i] is equal to another value, then it stores the value
27pub struct UniqueIdMapper<SA, A = CurrentStorage>
28where
29    SA: StorageMapperApi,
30    A: StorageAddress<SA>,
31{
32    _address: A,
33    base_key: StorageKey<SA>,
34    vec_mapper: VecMapper<SA, UniqueId, A>,
35}
36
37impl<SA> StorageMapper<SA> for UniqueIdMapper<SA, CurrentStorage>
38where
39    SA: StorageMapperApi,
40{
41    fn new(base_key: StorageKey<SA>) -> Self {
42        Self {
43            _address: CurrentStorage,
44            base_key: base_key.clone(),
45            vec_mapper: VecMapper::new(base_key),
46        }
47    }
48}
49
50impl<SA> StorageMapperFromAddress<SA> for UniqueIdMapper<SA, ManagedAddress<SA>>
51where
52    SA: StorageMapperApi,
53{
54    fn new_from_address(address: ManagedAddress<SA>, base_key: StorageKey<SA>) -> Self {
55        Self {
56            _address: address.clone(),
57            base_key: base_key.clone(),
58            vec_mapper: VecMapper::new_from_address(address, base_key),
59        }
60    }
61}
62
63impl<SA, A> UniqueIdMapper<SA, A>
64where
65    SA: StorageMapperApi,
66    A: StorageAddress<SA>,
67{
68    #[inline]
69    pub fn len(&self) -> usize {
70        self.vec_mapper.len()
71    }
72
73    #[inline]
74    pub fn is_empty(&self) -> bool {
75        self.vec_mapper.is_empty()
76    }
77
78    /// Gets the value for the given `index`. If the entry is empty, `index` is returned.
79    pub fn get(&self, index: usize) -> UniqueId {
80        let id: UniqueId = self.vec_mapper.get(index);
81        if id == EMPTY_ENTRY { index } else { id }
82    }
83
84    /// Provides a forward iterator.
85    pub fn iter(&self) -> Iter<'_, SA, A> {
86        Iter::new(self)
87    }
88}
89
90impl<SA> UniqueIdMapper<SA, CurrentStorage>
91where
92    SA: StorageMapperApi,
93{
94    /// Initializes the mapper's length. This may not be set again afterwards.
95    pub fn set_initial_len(&mut self, len: usize) {
96        if !self.vec_mapper.is_empty() {
97            SA::error_api_impl().signal_error(b"len already set");
98        }
99
100        self.set_internal_mapper_len(len);
101    }
102
103    /// Gets the value from the index and removes it.
104    /// The value is replaced by the last item, and length is decremented.
105    pub fn swap_remove(&mut self, index: usize) -> UniqueId {
106        let last_item_index = self.len();
107        let last_item = self.get(last_item_index);
108
109        let current_item = if index != last_item_index {
110            let item_at_index = self.get(index);
111            self.set(index, last_item);
112
113            item_at_index
114        } else {
115            last_item
116        };
117
118        self.vec_mapper.set(last_item_index, &EMPTY_ENTRY);
119        self.set_internal_mapper_len(last_item_index - 1);
120
121        current_item
122    }
123
124    /// Sets the value at the given index. If index == id, then the entry is cleared.
125    pub fn set(&mut self, index: usize, id: UniqueId) {
126        if index == id {
127            self.vec_mapper.set(index, &EMPTY_ENTRY);
128        } else {
129            self.vec_mapper.set(index, &id);
130        }
131    }
132
133    // Manually sets the internal VecMapper's len value
134    fn set_internal_mapper_len(&mut self, new_len: usize) {
135        let mut len_key = self.base_key.clone();
136        len_key.append_bytes(&b".len"[..]);
137        storage_set(len_key.as_ref(), &new_len);
138    }
139}
140
141impl<'a, SA, A> IntoIterator for &'a UniqueIdMapper<SA, A>
142where
143    SA: StorageMapperApi,
144    A: StorageAddress<SA>,
145{
146    type Item = usize;
147
148    type IntoIter = Iter<'a, SA, A>;
149
150    fn into_iter(self) -> Self::IntoIter {
151        self.iter()
152    }
153}
154
155pub struct Iter<'a, SA, A>
156where
157    SA: StorageMapperApi,
158    A: StorageAddress<SA>,
159{
160    index: usize,
161    len: usize,
162    id_mapper: &'a UniqueIdMapper<SA, A>,
163}
164
165impl<'a, SA, A> Iter<'a, SA, A>
166where
167    SA: StorageMapperApi,
168    A: StorageAddress<SA>,
169{
170    fn new(id_mapper: &'a UniqueIdMapper<SA, A>) -> Iter<'a, SA, A> {
171        Iter {
172            index: 1,
173            len: id_mapper.len(),
174            id_mapper,
175        }
176    }
177}
178
179impl<SA, A> Iterator for Iter<'_, SA, A>
180where
181    SA: StorageMapperApi,
182    A: StorageAddress<SA>,
183{
184    type Item = usize;
185
186    #[inline]
187    fn next(&mut self) -> Option<Self::Item> {
188        let current_index = self.index;
189        if current_index > self.len {
190            return None;
191        }
192
193        self.index += 1;
194        Some(self.id_mapper.get(current_index))
195    }
196}
197
198/// Behaves like a MultiResultVec when an endpoint result.
199impl<SA> TopEncodeMulti for UniqueIdMapper<SA, CurrentStorage>
200where
201    SA: StorageMapperApi,
202{
203    fn multi_encode_or_handle_err<O, H>(&self, output: &mut O, h: H) -> Result<(), H::HandledErr>
204    where
205        O: TopEncodeMultiOutput,
206        H: EncodeErrorHandler,
207    {
208        multi_encode_iter_or_handle_err(self.iter(), output, h)
209    }
210}
211
212impl<SA> TypeAbiFrom<UniqueIdMapper<SA, CurrentStorage>> for MultiValueEncoded<SA, usize> where
213    SA: StorageMapperApi
214{
215}
216
217impl<SA> TypeAbiFrom<Self> for UniqueIdMapper<SA, CurrentStorage> where SA: StorageMapperApi {}
218
219/// Behaves like a MultiResultVec when an endpoint result.
220impl<SA> TypeAbi for UniqueIdMapper<SA, CurrentStorage>
221where
222    SA: StorageMapperApi,
223{
224    type Unmanaged = Self;
225
226    fn type_name() -> TypeName {
227        crate::abi::type_name_variadic::<usize>()
228    }
229
230    fn type_name_rust() -> TypeName {
231        crate::abi::type_name_multi_value_encoded::<usize>()
232    }
233
234    fn provide_type_descriptions<TDC: TypeDescriptionContainer>(accumulator: &mut TDC) {
235        usize::provide_type_descriptions(accumulator);
236    }
237
238    fn is_variadic() -> bool {
239        true
240    }
241}