multiversx_sc/storage/mappers/
single_value_mapper.rs

1use core::{borrow::Borrow, marker::PhantomData};
2
3pub use super::{
4    source::{CurrentStorage, StorageAddress},
5    StorageMapper, StorageMapperFromAddress,
6};
7use crate::{
8    abi::{TypeAbi, TypeAbiFrom, TypeDescriptionContainer, TypeName},
9    api::StorageMapperApi,
10    codec::{
11        multi_types::PlaceholderOutput, DecodeErrorHandler, EncodeErrorHandler, TopDecode,
12        TopDecodeInput, TopEncode, TopEncodeMulti, TopEncodeMultiOutput, TopEncodeOutput,
13    },
14    storage::{storage_clear, storage_set, StorageKey},
15    types::{ManagedAddress, ManagedType},
16};
17
18/// Manages a single serializable item in storage.
19pub struct SingleValueMapper<SA, T, A = CurrentStorage>
20where
21    SA: StorageMapperApi,
22    A: StorageAddress<SA>,
23    T: TopEncode + TopDecode + 'static,
24{
25    address: A,
26    key: StorageKey<SA>,
27    _phantom_api: PhantomData<SA>,
28    _phantom_item: PhantomData<T>,
29}
30
31impl<SA, T> StorageMapper<SA> for SingleValueMapper<SA, T, CurrentStorage>
32where
33    SA: StorageMapperApi,
34    T: TopEncode + TopDecode,
35{
36    #[inline]
37    fn new(base_key: StorageKey<SA>) -> Self {
38        SingleValueMapper {
39            address: CurrentStorage,
40            key: base_key,
41            _phantom_api: PhantomData,
42            _phantom_item: PhantomData,
43        }
44    }
45}
46
47impl<SA, T> StorageMapperFromAddress<SA> for SingleValueMapper<SA, T, ManagedAddress<SA>>
48where
49    SA: StorageMapperApi,
50    T: TopEncode + TopDecode,
51{
52    #[inline]
53    fn new_from_address(address: ManagedAddress<SA>, base_key: StorageKey<SA>) -> Self {
54        SingleValueMapper {
55            address,
56            key: base_key,
57            _phantom_api: PhantomData,
58            _phantom_item: PhantomData,
59        }
60    }
61}
62
63impl<SA, T, A> SingleValueMapper<SA, T, A>
64where
65    SA: StorageMapperApi,
66    A: StorageAddress<SA>,
67    T: TopEncode + TopDecode,
68{
69    /// Retrieves current value from storage.
70    pub fn get(&self) -> T {
71        self.address.address_storage_get(self.key.as_ref())
72    }
73
74    /// Returns whether the storage managed by this mapper is empty.
75    pub fn is_empty(&self) -> bool {
76        self.raw_byte_length() == 0
77    }
78
79    pub fn raw_byte_length(&self) -> usize {
80        self.address.address_storage_get_len(self.key.as_ref())
81    }
82}
83
84impl<SA, T> SingleValueMapper<SA, T, CurrentStorage>
85where
86    SA: StorageMapperApi,
87    T: TopEncode + TopDecode,
88{
89    /// Saves argument to storage.
90    ///
91    /// Accepts owned item of type `T`, or any borrowed form of it, such as `&T`.
92    #[inline]
93    pub fn set<BT>(&self, new_value: BT)
94    where
95        BT: Borrow<T>,
96    {
97        storage_set(self.key.as_ref(), new_value.borrow());
98    }
99
100    /// Saves argument to storage only if the storage is empty.
101    /// Does nothing otherwise.
102    pub fn set_if_empty<BT>(&self, value: BT)
103    where
104        BT: Borrow<T>,
105    {
106        if self.is_empty() {
107            self.set(value);
108        }
109    }
110
111    /// Clears the storage for this mapper.
112    pub fn clear(&self) {
113        storage_clear(self.key.as_ref());
114    }
115
116    /// Syntactic sugar, to more compactly express a get, update and set in one line.
117    /// Takes whatever lies in storage, apples the given closure and saves the final value back to storage.
118    /// Propagates the return value of the given function.
119    pub fn update<R, F: FnOnce(&mut T) -> R>(&self, f: F) -> R {
120        let mut value = self.get();
121        let result = f(&mut value);
122        self.set(value);
123        result
124    }
125
126    /// Takes the value out of the storage, clearing it in the process.
127    pub fn take(&self) -> T {
128        let value = self.get();
129        self.clear();
130        value
131    }
132
133    // Replaces the actual value in the storage by the value given in parameter, returning the old value.
134    pub fn replace<BT>(&self, new_value: BT) -> T
135    where
136        BT: Borrow<T>,
137    {
138        let value = self.get();
139        self.set(new_value);
140        value
141    }
142}
143
144impl<SA, T> TopEncodeMulti for SingleValueMapper<SA, T, CurrentStorage>
145where
146    SA: StorageMapperApi,
147    T: TopEncode + TopDecode,
148{
149    fn multi_encode_or_handle_err<O, H>(&self, output: &mut O, h: H) -> Result<(), H::HandledErr>
150    where
151        O: TopEncodeMultiOutput,
152        H: EncodeErrorHandler,
153    {
154        output.push_single_value(&self.get(), h)
155    }
156}
157
158/// Intermediary type for deserializing the result of an endpoint that returns a `SingleValueMapper`.
159///
160/// Necessary because we cannot implement `TypeAbiFrom` directly on `T`.
161pub struct SingleValue<T: TopDecode>(T);
162
163impl<T: TopEncode + TopDecode> TopEncode for SingleValue<T> {
164    fn top_encode_or_handle_err<O, H>(&self, output: O, h: H) -> Result<(), H::HandledErr>
165    where
166        O: TopEncodeOutput,
167        H: EncodeErrorHandler,
168    {
169        self.0.top_encode_or_handle_err(output, h)
170    }
171}
172
173impl<T: TopDecode> TopDecode for SingleValue<T> {
174    fn top_decode_or_handle_err<I, H>(input: I, h: H) -> Result<Self, H::HandledErr>
175    where
176        I: TopDecodeInput,
177        H: DecodeErrorHandler,
178    {
179        Ok(SingleValue::<T>(T::top_decode_or_handle_err(input, h)?))
180    }
181}
182
183impl<T: TopDecode> From<T> for SingleValue<T> {
184    fn from(value: T) -> Self {
185        SingleValue::<T>(value)
186    }
187}
188
189impl<T: TopDecode> SingleValue<T> {
190    #[inline]
191    pub fn into(self) -> T {
192        self.0
193    }
194}
195
196impl<SA, T, R> TypeAbiFrom<SingleValueMapper<SA, T, CurrentStorage>> for SingleValue<R>
197where
198    SA: StorageMapperApi,
199    T: TopEncode + TopDecode,
200    R: TopDecode + TypeAbiFrom<T>,
201{
202}
203
204impl<SA, T> TypeAbiFrom<SingleValueMapper<SA, T>> for PlaceholderOutput
205where
206    SA: StorageMapperApi,
207    T: TopEncode + TopDecode,
208{
209}
210
211impl<SA, T> TypeAbiFrom<Self> for SingleValueMapper<SA, T, CurrentStorage>
212where
213    SA: StorageMapperApi,
214    T: TopEncode + TopDecode + TypeAbi,
215{
216}
217
218impl<SA, T> TypeAbi for SingleValueMapper<SA, T, CurrentStorage>
219where
220    SA: StorageMapperApi,
221    T: TopEncode + TopDecode + TypeAbi,
222{
223    type Unmanaged = T::Unmanaged;
224
225    fn type_name() -> TypeName {
226        T::type_name()
227    }
228
229    fn type_name_rust() -> TypeName {
230        T::type_name_rust()
231    }
232
233    fn provide_type_descriptions<TDC: TypeDescriptionContainer>(accumulator: &mut TDC) {
234        T::provide_type_descriptions(accumulator)
235    }
236}