multiversx_sc/storage/mappers/token/
token_attributes_mapper.rs1use core::marker::PhantomData;
2
3use crate::{
4 codec::{NestedDecode, NestedEncode, TopDecode, TopEncode},
5 storage::mappers::{
6 source::{CurrentStorage, StorageAddress},
7 StorageMapperFromAddress,
8 },
9 types::ManagedAddress,
10};
11
12use super::super::StorageMapper;
13use crate::{
14 api::{ErrorApiImpl, ManagedTypeApi, StorageMapperApi},
15 storage::{storage_clear, storage_get, storage_get_len, storage_set, StorageKey},
16 types::{ManagedType, TokenIdentifier},
17};
18
19const MAPPING_SUFFIX: &[u8] = b".mapping";
20const COUNTER_SUFFIX: &[u8] = b".counter";
21const ATTR_SUFFIX: &[u8] = b".attr";
22const NONCE_SUFFIX: &[u8] = b".nonce";
23
24const VALUE_ALREADY_SET_ERROR_MESSAGE: &[u8] = b"A value was already set";
25
26const UNKNOWN_TOKEN_ID_ERROR_MESSAGE: &[u8] = b"Unknown token id";
27
28const VALUE_NOT_PREVIOUSLY_SET_ERROR_MESSAGE: &[u8] = b"A value was not previously set";
29
30const COUNTER_OVERFLOW_ERROR_MESSAGE: &[u8] =
31 b"Counter overflow. This module can hold evidence for maximum u8::MAX different token IDs";
32
33pub struct TokenAttributesMapper<SA, A = CurrentStorage>
34where
35 SA: StorageMapperApi,
36{
37 _phantom_api: PhantomData<SA>,
38 base_key: StorageKey<SA>,
39 address: A,
40}
41
42impl<SA> StorageMapper<SA> for TokenAttributesMapper<SA, CurrentStorage>
43where
44 SA: StorageMapperApi,
45{
46 fn new(base_key: StorageKey<SA>) -> Self {
47 TokenAttributesMapper {
48 _phantom_api: PhantomData,
49 base_key,
50 address: CurrentStorage,
51 }
52 }
53}
54
55impl<SA> StorageMapperFromAddress<SA> for TokenAttributesMapper<SA, ManagedAddress<SA>>
56where
57 SA: StorageMapperApi,
58{
59 fn new_from_address(address: ManagedAddress<SA>, base_key: StorageKey<SA>) -> Self {
60 Self {
61 _phantom_api: PhantomData,
62 base_key,
63 address,
64 }
65 }
66}
67
68impl<SA> TokenAttributesMapper<SA, CurrentStorage>
69where
70 SA: StorageMapperApi,
71{
72 pub fn set<T: TopEncode + TopDecode + NestedEncode + NestedDecode, M: ManagedTypeApi>(
73 &self,
74 token_id: &TokenIdentifier<M>,
75 token_nonce: u64,
76 attributes: &T,
77 ) {
78 let has_mapping = self.has_mapping_value(token_id);
79
80 let mapping = if has_mapping {
81 self.get_mapping_value(token_id)
82 } else {
83 let mut counter = self.get_counter_value();
84 if counter == u8::MAX {
85 SA::error_api_impl().signal_error(COUNTER_OVERFLOW_ERROR_MESSAGE);
86 }
87
88 counter += 1;
89 self.set_mapping_value(token_id, counter);
90 self.set_counter_value(counter);
91 counter
92 };
93
94 let has_value = self.has_token_attributes_value(mapping, token_nonce);
95 if has_value {
96 SA::error_api_impl().signal_error(VALUE_ALREADY_SET_ERROR_MESSAGE);
97 }
98
99 self.set_token_attributes_value(mapping, token_nonce, attributes);
100 self.set_attributes_to_nonce_mapping(mapping, attributes, token_nonce);
101 }
102
103 pub fn update<T: TopEncode + TopDecode + NestedEncode + NestedDecode, M: ManagedTypeApi>(
105 &self,
106 token_id: &TokenIdentifier<M>,
107 token_nonce: u64,
108 attributes: &T,
109 ) {
110 let has_mapping = self.has_mapping_value(token_id);
111 if !has_mapping {
112 SA::error_api_impl().signal_error(UNKNOWN_TOKEN_ID_ERROR_MESSAGE);
113 }
114
115 let mapping = self.get_mapping_value(token_id);
116 let has_value = self.has_token_attributes_value(mapping, token_nonce);
117 if !has_value {
118 SA::error_api_impl().signal_error(VALUE_NOT_PREVIOUSLY_SET_ERROR_MESSAGE);
119 }
120
121 let old_attr = self.get_token_attributes_value::<T>(mapping, token_nonce);
122 self.clear_attributes_to_nonce_mapping(mapping, &old_attr);
123
124 self.set_token_attributes_value(mapping, token_nonce, attributes);
125 self.set_attributes_to_nonce_mapping(mapping, attributes, token_nonce);
126 }
127
128 pub fn clear<T: TopEncode + TopDecode + NestedEncode + NestedDecode, M: ManagedTypeApi>(
129 &self,
130 token_id: &TokenIdentifier<M>,
131 token_nonce: u64,
132 ) {
133 let has_mapping = self.has_mapping_value(token_id);
134 if !has_mapping {
135 return;
136 }
137
138 let mapping = self.get_mapping_value(token_id);
139 let has_value = self.has_token_attributes_value(mapping, token_nonce);
140 if !has_value {
141 return;
142 }
143
144 let attr: T = self.get_token_attributes_value(mapping, token_nonce);
145 self.clear_token_attributes_value(mapping, token_nonce);
146 self.clear_attributes_to_nonce_mapping(mapping, &attr);
147 }
148
149 fn set_counter_value(&self, value: u8) {
150 storage_set(self.build_key_token_id_counter().as_ref(), &value);
151 }
152
153 fn set_mapping_value<M: ManagedTypeApi>(&self, token_id: &TokenIdentifier<M>, value: u8) {
154 storage_set(self.build_key_token_id_mapping(token_id).as_ref(), &value);
155 }
156
157 fn set_attributes_to_nonce_mapping<T: TopEncode + TopDecode + NestedEncode + NestedDecode>(
158 &self,
159 mapping: u8,
160 attr: &T,
161 token_nonce: u64,
162 ) {
163 storage_set(
164 self.build_key_attr_to_nonce_mapping(mapping, attr).as_ref(),
165 &token_nonce,
166 );
167 }
168
169 fn clear_attributes_to_nonce_mapping<T: TopEncode + TopDecode + NestedEncode + NestedDecode>(
170 &self,
171 mapping: u8,
172 attr: &T,
173 ) {
174 storage_clear(self.build_key_attr_to_nonce_mapping(mapping, attr).as_ref());
175 }
176
177 fn set_token_attributes_value<T: TopEncode + TopDecode + NestedEncode + NestedDecode>(
178 &self,
179 mapping: u8,
180 token_nonce: u64,
181 value: &T,
182 ) {
183 storage_set(
184 self.build_key_token_attr_value(mapping, token_nonce)
185 .as_ref(),
186 value,
187 );
188 }
189
190 fn clear_token_attributes_value(&self, mapping: u8, token_nonce: u64) {
191 storage_clear(
192 self.build_key_token_attr_value(mapping, token_nonce)
193 .as_ref(),
194 );
195 }
196}
197
198impl<SA, A> TokenAttributesMapper<SA, A>
199where
200 SA: StorageMapperApi,
201 A: StorageAddress<SA>,
202{
203 pub fn has_attributes<M: ManagedTypeApi>(
204 &self,
205 token_id: &TokenIdentifier<M>,
206 token_nonce: u64,
207 ) -> bool {
208 let has_mapping = self.has_mapping_value(token_id);
209 if !has_mapping {
210 return true;
211 }
212
213 let mapping = self.get_mapping_value(token_id);
214 self.is_empty_token_attributes_value(mapping, token_nonce)
215 }
216
217 pub fn has_nonce<T: TopEncode + TopDecode + NestedEncode + NestedDecode, M: ManagedTypeApi>(
218 &self,
219 token_id: &TokenIdentifier<M>,
220 attr: &T,
221 ) -> bool {
222 let has_mapping = self.has_mapping_value(token_id);
223 if !has_mapping {
224 return true;
225 }
226
227 let mapping = self.get_mapping_value(token_id);
228 self.is_empty_attributes_to_nonce_mapping(mapping, attr)
229 }
230
231 pub fn get_attributes<
232 T: TopEncode + TopDecode + NestedEncode + NestedDecode,
233 M: ManagedTypeApi,
234 >(
235 &self,
236 token_id: &TokenIdentifier<M>,
237 token_nonce: u64,
238 ) -> T {
239 let has_mapping = self.has_mapping_value(token_id);
240 if !has_mapping {
241 SA::error_api_impl().signal_error(UNKNOWN_TOKEN_ID_ERROR_MESSAGE);
242 }
243
244 let mapping = self.get_mapping_value(token_id);
245 let has_value = self.has_token_attributes_value(mapping, token_nonce);
246 if !has_value {
247 SA::error_api_impl().signal_error(VALUE_NOT_PREVIOUSLY_SET_ERROR_MESSAGE);
248 }
249
250 self.get_token_attributes_value(mapping, token_nonce)
251 }
252
253 pub fn get_nonce<T: TopEncode + TopDecode + NestedEncode + NestedDecode, M: ManagedTypeApi>(
254 &self,
255 token_id: &TokenIdentifier<M>,
256 attr: &T,
257 ) -> u64 {
258 let has_mapping = self.has_mapping_value(token_id);
259 if !has_mapping {
260 SA::error_api_impl().signal_error(UNKNOWN_TOKEN_ID_ERROR_MESSAGE);
261 }
262
263 let mapping = self.get_mapping_value(token_id);
264 let has_value = self.has_attr_to_nonce_mapping::<T>(mapping, attr);
265 if !has_value {
266 SA::error_api_impl().signal_error(VALUE_NOT_PREVIOUSLY_SET_ERROR_MESSAGE);
267 }
268
269 self.get_attributes_to_nonce_mapping(mapping, attr)
270 }
271
272 fn has_mapping_value<M: ManagedTypeApi>(&self, token_id: &TokenIdentifier<M>) -> bool {
273 !self.is_empty_mapping_value(token_id)
274 }
275
276 fn has_token_attributes_value(&self, mapping: u8, token_nonce: u64) -> bool {
277 !self.is_empty_token_attributes_value(mapping, token_nonce)
278 }
279
280 fn has_attr_to_nonce_mapping<T: TopEncode + TopDecode + NestedEncode + NestedDecode>(
281 &self,
282 mapping: u8,
283 attr: &T,
284 ) -> bool {
285 !self.is_empty_attributes_to_nonce_mapping(mapping, attr)
286 }
287
288 fn build_key_token_id_counter(&self) -> StorageKey<SA> {
289 let mut key = self.base_key.clone();
290 key.append_bytes(COUNTER_SUFFIX);
291 key
292 }
293
294 fn build_key_token_id_mapping<M: ManagedTypeApi>(
295 &self,
296 token_id: &TokenIdentifier<M>,
297 ) -> StorageKey<SA> {
298 let mut key = self.base_key.clone();
299 key.append_bytes(MAPPING_SUFFIX);
300 key.append_item(token_id);
301 key
302 }
303
304 fn build_key_token_attr_value(&self, mapping: u8, token_nonce: u64) -> StorageKey<SA> {
305 let mut key = self.base_key.clone();
306 key.append_bytes(ATTR_SUFFIX);
307 key.append_item(&mapping);
308 key.append_item(&token_nonce);
309 key
310 }
311
312 fn build_key_attr_to_nonce_mapping<T: TopEncode + TopDecode + NestedEncode + NestedDecode>(
313 &self,
314 mapping: u8,
315 attr: &T,
316 ) -> StorageKey<SA> {
317 let mut key = self.base_key.clone();
318 key.append_bytes(NONCE_SUFFIX);
319 key.append_item(&mapping);
320 key.append_item(attr);
321 key
322 }
323
324 fn get_counter_value(&self) -> u8 {
325 storage_get(self.build_key_token_id_counter().as_ref())
326 }
327
328 fn get_mapping_value<M: ManagedTypeApi>(&self, token_id: &TokenIdentifier<M>) -> u8 {
329 storage_get(self.build_key_token_id_mapping(token_id).as_ref())
330 }
331
332 fn is_empty_mapping_value<M: ManagedTypeApi>(&self, token_id: &TokenIdentifier<M>) -> bool {
333 storage_get_len(self.build_key_token_id_mapping(token_id).as_ref()) == 0
334 }
335
336 fn get_attributes_to_nonce_mapping<T: TopEncode + TopDecode + NestedEncode + NestedDecode>(
337 &self,
338 mapping: u8,
339 attr: &T,
340 ) -> u64 {
341 storage_get(self.build_key_attr_to_nonce_mapping(mapping, attr).as_ref())
342 }
343
344 fn is_empty_attributes_to_nonce_mapping<
345 T: TopEncode + TopDecode + NestedEncode + NestedDecode,
346 >(
347 &self,
348 mapping: u8,
349 attr: &T,
350 ) -> bool {
351 storage_get_len(self.build_key_attr_to_nonce_mapping(mapping, attr).as_ref()) == 0
352 }
353
354 fn get_token_attributes_value<T: TopEncode + TopDecode + NestedEncode + NestedDecode>(
355 &self,
356 mapping: u8,
357 token_nonce: u64,
358 ) -> T {
359 storage_get(
360 self.build_key_token_attr_value(mapping, token_nonce)
361 .as_ref(),
362 )
363 }
364
365 fn is_empty_token_attributes_value(&self, mapping: u8, token_nonce: u64) -> bool {
366 storage_get_len(
367 self.build_key_token_attr_value(mapping, token_nonce)
368 .as_ref(),
369 ) == 0
370 }
371}