multiversx_sc/io/
arg_de_input.rs

1use core::marker::PhantomData;
2
3use crate::{
4    api::{EndpointArgumentApi, EndpointArgumentApiImpl, ManagedTypeApi},
5    codec::{
6        try_execute_then_cast, DecodeError, DecodeErrorHandler, TopDecodeInput, TryStaticCast,
7    },
8    types::{
9        heap::Box, BigInt, BigUint, ManagedBuffer, ManagedBufferNestedDecodeInput, ManagedType,
10    },
11};
12
13/// Adapter from the API to the TopDecodeInput trait.
14/// Allows objects to be deserialized directly from the API as arguments.
15///
16/// Of course the implementation provides shortcut deserialization computation paths directly from API:
17/// into_u64, into_i64, ...
18///
19/// This is a performance-critical struct.
20/// Since the wasm EndpointArgumentApi (VmApiImpl) is zero-size,
21/// it means that this structures translates to a single glorified i32 in wasm.
22pub struct ArgDecodeInput<AA>
23where
24    AA: ManagedTypeApi + EndpointArgumentApi,
25{
26    _phantom: PhantomData<AA>,
27    arg_index: i32,
28}
29
30impl<AA> ArgDecodeInput<AA>
31where
32    AA: ManagedTypeApi + EndpointArgumentApi,
33{
34    #[inline]
35    pub fn new(arg_index: i32) -> Self {
36        ArgDecodeInput {
37            _phantom: PhantomData,
38            arg_index,
39        }
40    }
41
42    fn to_managed_buffer(&self) -> ManagedBuffer<AA> {
43        unsafe {
44            let result = ManagedBuffer::new_uninit();
45            AA::argument_api_impl()
46                .load_argument_managed_buffer(self.arg_index, result.get_handle());
47            result
48        }
49    }
50
51    fn to_big_int(&self) -> BigInt<AA> {
52        unsafe {
53            let result = BigInt::new_uninit();
54            AA::argument_api_impl()
55                .load_argument_big_int_signed(self.arg_index, result.get_handle());
56            result
57        }
58    }
59
60    fn to_big_uint(&self) -> BigUint<AA> {
61        unsafe {
62            let result = BigUint::new_uninit();
63            AA::argument_api_impl()
64                .load_argument_big_int_unsigned(self.arg_index, result.get_handle());
65            result
66        }
67    }
68}
69
70impl<AA> TopDecodeInput for ArgDecodeInput<AA>
71where
72    AA: ManagedTypeApi + EndpointArgumentApi,
73{
74    type NestedBuffer = ManagedBufferNestedDecodeInput<AA>;
75
76    #[inline]
77    fn byte_len(&self) -> usize {
78        AA::argument_api_impl().get_argument_len(self.arg_index)
79    }
80
81    #[inline]
82    fn into_boxed_slice_u8(self) -> Box<[u8]> {
83        AA::argument_api_impl()
84            .get_argument_boxed_bytes(self.arg_index)
85            .into_box()
86    }
87
88    #[inline]
89    fn into_max_size_buffer<H, const MAX_LEN: usize>(
90        self,
91        buffer: &mut [u8; MAX_LEN],
92        h: H,
93    ) -> Result<&[u8], H::HandledErr>
94    where
95        H: DecodeErrorHandler,
96    {
97        self.to_managed_buffer().into_max_size_buffer(buffer, h)
98    }
99
100    #[inline]
101    fn into_max_size_buffer_align_right<H, const MAX_LEN: usize>(
102        self,
103        buffer: &mut [u8; MAX_LEN],
104        h: H,
105    ) -> Result<usize, H::HandledErr>
106    where
107        H: DecodeErrorHandler,
108    {
109        self.to_managed_buffer()
110            .into_max_size_buffer_align_right(buffer, h)
111    }
112
113    #[inline]
114    fn into_u64<H>(self, _h: H) -> Result<u64, H::HandledErr>
115    where
116        H: DecodeErrorHandler,
117    {
118        Ok(AA::argument_api_impl().get_argument_u64(self.arg_index))
119    }
120
121    #[inline]
122    fn into_i64<H>(self, _h: H) -> Result<i64, H::HandledErr>
123    where
124        H: DecodeErrorHandler,
125    {
126        Ok(AA::argument_api_impl().get_argument_i64(self.arg_index))
127    }
128
129    #[inline]
130    fn supports_specialized_type<T: TryStaticCast>() -> bool {
131        T::type_eq::<ManagedBuffer<AA>>()
132            || T::type_eq::<BigUint<AA>>()
133            || T::type_eq::<BigInt<AA>>()
134    }
135
136    #[inline]
137    fn into_specialized<T, H>(self, h: H) -> Result<T, H::HandledErr>
138    where
139        T: TryStaticCast,
140        H: DecodeErrorHandler,
141    {
142        if let Some(result) = try_execute_then_cast(|| self.to_managed_buffer()) {
143            Ok(result)
144        } else if let Some(result) = try_execute_then_cast(|| self.to_big_uint()) {
145            Ok(result)
146        } else if let Some(result) = try_execute_then_cast(|| self.to_big_int()) {
147            Ok(result)
148        } else {
149            Err(h.handle_error(DecodeError::UNSUPPORTED_OPERATION))
150        }
151    }
152
153    #[inline]
154    fn into_nested_buffer(self) -> Self::NestedBuffer {
155        ManagedBufferNestedDecodeInput::new(self.to_managed_buffer())
156    }
157}