Skip to main content

multiversx_sc/types/managed/multi_value/
multi_value_encoded.rs

1use multiversx_sc_codec::MultiValueLength;
2use multiversx_sc_codec::multi_types::MultiValue3;
3use unwrap_infallible::UnwrapInfallible;
4
5use crate::codec::multi_types::MultiValueVec;
6use crate::types::{
7    BigUint, EgldOrEsdtTokenIdentifier, EgldOrEsdtTokenPayment, EgldOrEsdtTokenPaymentMultiValue,
8    EsdtTokenIdentifier, EsdtTokenPayment, NonZeroBigUint, Payment, PaymentMultiValue, TokenId,
9};
10use crate::{
11    abi::{TypeAbi, TypeAbiFrom, TypeDescriptionContainer, TypeName},
12    api::{ErrorApi, ManagedTypeApi},
13    codec::{
14        DecodeErrorHandler, EncodeErrorHandler, MultiValueConstLength, TopDecode, TopDecodeMulti,
15        TopDecodeMultiInput, TopEncode, TopEncodeMulti, TopEncodeMultiOutput,
16        try_cast_execute_or_else,
17    },
18    contract_base::{ExitCodecErrorHandler, ManagedSerializer},
19    err_msg,
20    types::{ManagedArgBuffer, ManagedBuffer, ManagedType, ManagedVec, ManagedVecItem},
21};
22use core::{iter::FromIterator, marker::PhantomData};
23
24use super::MultiValueEncodedIterator;
25
26/// A multi-value container, that keeps raw values as ManagedBuffer
27/// It allows encoding and decoding of multi-values.
28///
29/// Since items are kept raw, the item type does not need to implement `ManagedVecItem`.
30///
31/// Behavior:
32/// - It is lazy when decoding, in that it keeps them raw and will not decode the values until they are requested.
33/// - It is eager when encoding, items are serialized before being added to this structure.
34///
35/// Since it can contain multi-values, the number of actual items it contains cannot be determined without fully decoding.
36///
37#[derive(Clone, Default, Debug, PartialEq)]
38pub struct MultiValueEncoded<M, T>
39where
40    M: ManagedTypeApi,
41{
42    pub(super) raw_buffers: ManagedVec<M, ManagedBuffer<M>>,
43    _phantom: PhantomData<T>,
44}
45
46#[deprecated(
47    since = "0.29.0",
48    note = "Alias kept for backwards compatibility. Replace with `MultiValueEncoded`"
49)]
50pub type ManagedVarArgs<M, T> = MultiValueEncoded<M, T>;
51
52#[deprecated(
53    since = "0.29.0",
54    note = "Alias kept for backwards compatibility. Replace with `MultiValueEncoded`"
55)]
56pub type ManagedMultiResultVec<M, T> = MultiValueEncoded<M, T>;
57
58impl<M, T> MultiValueEncoded<M, T>
59where
60    M: ManagedTypeApi,
61{
62    #[inline]
63    fn from_raw_vec(raw_buffers: ManagedVec<M, ManagedBuffer<M>>) -> Self {
64        MultiValueEncoded {
65            raw_buffers,
66            _phantom: PhantomData,
67        }
68    }
69
70    #[inline]
71    pub fn new() -> Self {
72        MultiValueEncoded::from_raw_vec(ManagedVec::new())
73    }
74}
75
76impl<M, T> MultiValueEncoded<M, T>
77where
78    M: ManagedTypeApi + ErrorApi,
79    T: TopEncodeMulti,
80{
81    pub fn push(&mut self, item: T) {
82        item.multi_encode_or_handle_err(
83            &mut self.raw_buffers,
84            ExitCodecErrorHandler::<M>::from(err_msg::SERIALIZER_ENCODE_ERROR),
85        )
86        .unwrap_infallible()
87    }
88}
89
90impl<M, T> From<ManagedVec<M, T>> for MultiValueEncoded<M, T>
91where
92    M: ManagedTypeApi,
93    T: ManagedVecItem + TopEncode + 'static,
94{
95    #[inline]
96    fn from(v: ManagedVec<M, T>) -> Self {
97        try_cast_execute_or_else(
98            v,
99            MultiValueEncoded::from_raw_vec,
100            MultiValueEncoded::from_iter,
101        )
102    }
103}
104
105impl<M, T> MultiValueEncoded<M, T>
106where
107    M: ManagedTypeApi,
108{
109    pub fn to_arg_buffer(&self) -> ManagedArgBuffer<M> {
110        unsafe { ManagedArgBuffer::from_handle(self.raw_buffers.get_handle()) }
111    }
112}
113
114impl<M> MultiValueEncoded<M, ManagedBuffer<M>>
115where
116    M: ManagedTypeApi,
117{
118    pub fn into_vec_of_buffers(self) -> ManagedVec<M, ManagedBuffer<M>> {
119        self.raw_buffers
120    }
121}
122
123impl<M, T> MultiValueEncoded<M, T>
124where
125    M: ManagedTypeApi + ErrorApi,
126{
127    /// Length of the underlying data.
128    ///
129    /// Note:
130    /// In general, it is **not** the number of items that can be decoded.
131    /// It is the same as `len()` only for single encode items.
132    #[inline]
133    pub fn raw_len(&self) -> usize {
134        self.raw_buffers.len()
135    }
136
137    pub fn is_empty(&self) -> bool {
138        self.raw_buffers.is_empty()
139    }
140}
141
142impl<M, T> IntoIterator for MultiValueEncoded<M, T>
143where
144    M: ManagedTypeApi + ErrorApi,
145    T: TopDecodeMulti,
146{
147    type Item = T;
148    type IntoIter = MultiValueEncodedIterator<M, T>;
149    fn into_iter(self) -> Self::IntoIter {
150        MultiValueEncodedIterator::new(self.raw_buffers)
151    }
152}
153
154impl<M, T> MultiValueLength for MultiValueEncoded<M, T>
155where
156    M: ManagedTypeApi + ErrorApi,
157    T: MultiValueConstLength,
158{
159    #[inline]
160    fn multi_value_len(&self) -> usize {
161        self.raw_len()
162    }
163}
164
165impl<M, T> MultiValueEncoded<M, T>
166where
167    M: ManagedTypeApi + ErrorApi,
168    T: MultiValueConstLength,
169{
170    /// Number of items. Only available for multi-encode items.
171    #[inline]
172    pub fn len(&self) -> usize {
173        self.raw_len() / T::MULTI_VALUE_CONST_LEN
174    }
175}
176
177impl<M, T> MultiValueEncoded<M, T>
178where
179    M: ManagedTypeApi + ErrorApi,
180    T: ManagedVecItem + TopDecode,
181{
182    pub fn to_vec(&self) -> ManagedVec<M, T> {
183        let mut result = ManagedVec::new();
184        let serializer = ManagedSerializer::<M>::new();
185        for item in &self.raw_buffers {
186            result.push(serializer.top_decode_from_managed_buffer(&item));
187        }
188        result
189    }
190}
191
192impl<M> MultiValueEncoded<M, MultiValue3<EgldOrEsdtTokenIdentifier<M>, u64, BigUint<M>>>
193where
194    M: ManagedTypeApi + ErrorApi,
195{
196    /// Convenience function to convert a payment multi-argument into a usable structure.
197    pub fn convert_payment_multi_triples(self) -> ManagedVec<M, EgldOrEsdtTokenPayment<M>> {
198        let mut payments_vec = ManagedVec::new();
199
200        for multi_arg in self.into_iter() {
201            let (token_identifier, token_nonce, amount) = multi_arg.into_tuple();
202            let payment = EgldOrEsdtTokenPayment::new(token_identifier, token_nonce, amount);
203
204            payments_vec.push(payment);
205        }
206
207        payments_vec
208    }
209}
210
211impl<M> MultiValueEncoded<M, MultiValue3<EsdtTokenIdentifier<M>, u64, BigUint<M>>>
212where
213    M: ManagedTypeApi + ErrorApi,
214{
215    /// Convenience function to convert a payment multi-argument into a usable structure.
216    pub fn convert_payment_multi_triples(self) -> ManagedVec<M, EsdtTokenPayment<M>> {
217        let mut payments_vec = ManagedVec::new();
218
219        for multi_arg in self.into_iter() {
220            let (token_identifier, token_nonce, amount) = multi_arg.into_tuple();
221            let payment = EsdtTokenPayment::new(token_identifier, token_nonce, amount);
222
223            payments_vec.push(payment);
224        }
225
226        payments_vec
227    }
228}
229
230impl<M> MultiValueEncoded<M, MultiValue3<TokenId<M>, u64, NonZeroBigUint<M>>>
231where
232    M: ManagedTypeApi + ErrorApi,
233{
234    /// Convenience function to convert a payment multi-argument into a usable structure.
235    pub fn convert_payment_multi_triples(self) -> ManagedVec<M, Payment<M>> {
236        let mut payments_vec = ManagedVec::new();
237
238        for multi_arg in self.into_iter() {
239            let (token_identifier, token_nonce, amount) = multi_arg.into_tuple();
240            let payment = Payment::new(token_identifier, token_nonce, amount);
241
242            payments_vec.push(payment);
243        }
244
245        payments_vec
246    }
247}
248
249impl<M> MultiValueEncoded<M, EgldOrEsdtTokenPaymentMultiValue<M>>
250where
251    M: ManagedTypeApi + ErrorApi,
252{
253    /// Convenience function to convert a payment multi-argument into a usable structure.
254    pub fn convert_payment(self) -> ManagedVec<M, EgldOrEsdtTokenPayment<M>> {
255        let mut payments_vec = ManagedVec::new();
256
257        for multi_arg in self.into_iter() {
258            payments_vec.push(multi_arg.into_inner());
259        }
260
261        payments_vec
262    }
263
264    /// Constructs a multi-value from a list of payments.
265    pub fn from_vec(v: ManagedVec<M, EgldOrEsdtTokenPayment<M>>) -> Self {
266        let mut encoded = MultiValueEncoded::new();
267
268        for payment in v {
269            encoded.push(EgldOrEsdtTokenPaymentMultiValue::from(payment));
270        }
271
272        encoded
273    }
274}
275
276impl<M> MultiValueEncoded<M, PaymentMultiValue<M>>
277where
278    M: ManagedTypeApi + ErrorApi,
279{
280    /// Convenience function to convert a payment multi-argument into a usable structure.
281    pub fn convert_payment(self) -> ManagedVec<M, Payment<M>> {
282        let mut payments_vec = ManagedVec::new();
283
284        for multi_arg in self.into_iter() {
285            payments_vec.push(multi_arg.into_inner());
286        }
287
288        payments_vec
289    }
290}
291
292impl<M, T> TopEncodeMulti for &MultiValueEncoded<M, T>
293where
294    M: ManagedTypeApi + ErrorApi,
295    T: TopEncodeMulti,
296{
297    fn multi_encode_or_handle_err<O, H>(&self, output: &mut O, h: H) -> Result<(), H::HandledErr>
298    where
299        O: TopEncodeMultiOutput,
300        H: EncodeErrorHandler,
301    {
302        for elem in &self.raw_buffers {
303            elem.multi_encode_or_handle_err(output, h)?;
304        }
305        Ok(())
306    }
307}
308
309impl<M, T> TopEncodeMulti for MultiValueEncoded<M, T>
310where
311    M: ManagedTypeApi + ErrorApi,
312    T: TopEncodeMulti,
313{
314    fn multi_encode_or_handle_err<O, H>(&self, output: &mut O, h: H) -> Result<(), H::HandledErr>
315    where
316        O: TopEncodeMultiOutput,
317        H: EncodeErrorHandler,
318    {
319        (&self).multi_encode_or_handle_err(output, h)
320    }
321}
322
323impl<M, T> TopDecodeMulti for MultiValueEncoded<M, T>
324where
325    M: ManagedTypeApi + ErrorApi,
326    T: TopDecodeMulti,
327{
328    fn multi_decode_or_handle_err<I, H>(input: &mut I, h: H) -> Result<Self, H::HandledErr>
329    where
330        I: TopDecodeMultiInput,
331        H: DecodeErrorHandler,
332    {
333        let mut raw_buffers = ManagedVec::new();
334        while input.has_next() {
335            raw_buffers.push(input.next_value(h)?);
336        }
337        Ok(Self {
338            raw_buffers,
339            _phantom: PhantomData,
340        })
341    }
342}
343
344impl<M, T> TypeAbiFrom<Self> for MultiValueEncoded<M, T>
345where
346    M: ManagedTypeApi,
347    T: TypeAbi,
348{
349}
350
351impl<M, T> TypeAbiFrom<&Self> for MultiValueEncoded<M, T>
352where
353    M: ManagedTypeApi,
354    T: TypeAbi,
355{
356}
357
358impl<M, T> TypeAbi for MultiValueEncoded<M, T>
359where
360    M: ManagedTypeApi,
361    T: TypeAbi,
362{
363    type Unmanaged = MultiValueVec<T::Unmanaged>;
364
365    fn type_name() -> TypeName {
366        crate::abi::type_name_variadic::<T>()
367    }
368
369    fn type_name_rust() -> TypeName {
370        crate::abi::type_name_multi_value_encoded::<T>()
371    }
372
373    fn provide_type_descriptions<TDC: TypeDescriptionContainer>(accumulator: &mut TDC) {
374        T::provide_type_descriptions(accumulator);
375    }
376
377    fn is_variadic() -> bool {
378        true
379    }
380}
381
382impl<M, T, U> TypeAbiFrom<MultiValueVec<T>> for MultiValueEncoded<M, U>
383where
384    M: ManagedTypeApi + ErrorApi,
385    T: TopEncodeMulti,
386    U: TypeAbiFrom<T>,
387{
388}
389
390impl<M, T, U> TypeAbiFrom<MultiValueEncoded<M, T>> for MultiValueVec<U>
391where
392    M: ManagedTypeApi + ErrorApi,
393    T: TopEncodeMulti,
394    U: TypeAbiFrom<T>,
395{
396}
397
398impl<M, V> FromIterator<V> for MultiValueEncoded<M, V>
399where
400    M: ManagedTypeApi,
401    V: TopEncodeMulti,
402{
403    fn from_iter<T: IntoIterator<Item = V>>(iter: T) -> Self {
404        let mut result: MultiValueEncoded<M, V> = MultiValueEncoded::new();
405        iter.into_iter().for_each(|f| result.push(f));
406        result
407    }
408}