multiversx_sc/types/managed/wrapped/
managed_byte_array.rs

1use core::convert::TryFrom;
2
3use alloc::format;
4
5use crate::{
6    abi::{TypeAbi, TypeAbiFrom, TypeName},
7    api::ManagedTypeApi,
8    codec::{
9        DecodeError, DecodeErrorHandler, EncodeErrorHandler, NestedDecode, NestedDecodeInput,
10        NestedEncode, NestedEncodeOutput, TopDecode, TopDecodeInput, TopEncode, TopEncodeOutput,
11        TryStaticCast,
12    },
13    formatter::{hex_util::encode_bytes_as_hex, FormatByteReceiver, SCLowerHex},
14    types::{ManagedBuffer, ManagedType},
15};
16
17const DECODE_ERROR_BAD_LENGTH: &str = "bad array length";
18
19/// A list of items that lives inside a managed buffer.
20/// Items can be either stored there in full (e.g. `u32`),
21/// or just via handle (e.g. `BigUint<M>`).
22#[repr(transparent)]
23#[derive(Clone)]
24pub struct ManagedByteArray<M, const N: usize>
25where
26    M: ManagedTypeApi,
27{
28    pub(crate) buffer: ManagedBuffer<M>,
29}
30
31impl<M, const N: usize> ManagedType<M> for ManagedByteArray<M, N>
32where
33    M: ManagedTypeApi,
34{
35    type OwnHandle = M::ManagedBufferHandle;
36
37    #[inline]
38    unsafe fn from_handle(handle: M::ManagedBufferHandle) -> Self {
39        ManagedByteArray {
40            buffer: ManagedBuffer::from_handle(handle),
41        }
42    }
43
44    fn get_handle(&self) -> M::ManagedBufferHandle {
45        self.buffer.get_handle()
46    }
47
48    unsafe fn forget_into_handle(self) -> Self::OwnHandle {
49        self.buffer.forget_into_handle()
50    }
51
52    fn transmute_from_handle_ref(handle_ref: &M::ManagedBufferHandle) -> &Self {
53        unsafe { core::mem::transmute(handle_ref) }
54    }
55
56    fn transmute_from_handle_ref_mut(handle_ref: &mut M::ManagedBufferHandle) -> &mut Self {
57        unsafe { core::mem::transmute(handle_ref) }
58    }
59}
60
61impl<M, const N: usize> Default for ManagedByteArray<M, N>
62where
63    M: ManagedTypeApi,
64{
65    #[inline]
66    fn default() -> Self {
67        Self::new_from_bytes(&[0u8; N])
68    }
69}
70
71impl<M, const N: usize> From<&[u8; N]> for ManagedByteArray<M, N>
72where
73    M: ManagedTypeApi,
74{
75    #[inline]
76    fn from(bytes: &[u8; N]) -> Self {
77        Self::new_from_bytes(bytes)
78    }
79}
80
81impl<M, const N: usize> ManagedByteArray<M, N>
82where
83    M: ManagedTypeApi,
84{
85    #[inline]
86    pub fn new_from_bytes(bytes: &[u8; N]) -> Self {
87        ManagedByteArray {
88            buffer: ManagedBuffer::new_from_bytes(&bytes[..]),
89        }
90    }
91
92    /// Creates a new object, without initializing it.
93    ///
94    /// ## Safety
95    ///
96    /// The value needs to be initialized after creation, otherwise the VM will halt the first time the value is attempted to be read.
97    pub unsafe fn new_uninit() -> Self {
98        ManagedByteArray {
99            buffer: ManagedBuffer::new_uninit(),
100        }
101    }
102
103    /// Number of items.
104    #[inline]
105    pub fn len(&self) -> usize {
106        self.buffer.len()
107    }
108
109    #[inline]
110    pub fn is_empty(&self) -> bool {
111        self.len() == 0
112    }
113
114    #[inline]
115    pub fn as_managed_buffer(&self) -> &ManagedBuffer<M> {
116        &self.buffer
117    }
118
119    #[inline]
120    pub fn to_byte_array(&self) -> [u8; N] {
121        let mut result = [0u8; N];
122        self.buffer.load_slice(0, &mut result[..]);
123        result
124    }
125}
126
127impl<M, const N: usize> PartialEq for ManagedByteArray<M, N>
128where
129    M: ManagedTypeApi,
130{
131    #[inline]
132    fn eq(&self, other: &Self) -> bool {
133        self.buffer == other.buffer
134    }
135}
136
137impl<M, const N: usize> Eq for ManagedByteArray<M, N> where M: ManagedTypeApi {}
138
139impl<M, const N: usize> TryFrom<ManagedBuffer<M>> for ManagedByteArray<M, N>
140where
141    M: ManagedTypeApi,
142{
143    type Error = DecodeError;
144
145    fn try_from(value: ManagedBuffer<M>) -> Result<Self, Self::Error> {
146        if value.len() != N {
147            return Err(DecodeError::from(DECODE_ERROR_BAD_LENGTH));
148        }
149        Ok(ManagedByteArray { buffer: value })
150    }
151}
152
153impl<M, const N: usize> TopEncode for ManagedByteArray<M, N>
154where
155    M: ManagedTypeApi,
156{
157    #[inline]
158    fn top_encode_or_handle_err<O, H>(&self, output: O, h: H) -> Result<(), H::HandledErr>
159    where
160        O: TopEncodeOutput,
161        H: EncodeErrorHandler,
162    {
163        self.buffer.top_encode_or_handle_err(output, h)
164    }
165}
166
167impl<M, const N: usize> TopDecode for ManagedByteArray<M, N>
168where
169    M: ManagedTypeApi,
170{
171    fn top_decode_or_handle_err<I, H>(input: I, h: H) -> Result<Self, H::HandledErr>
172    where
173        I: TopDecodeInput,
174        H: DecodeErrorHandler,
175    {
176        let buffer = ManagedBuffer::top_decode_or_handle_err(input, h)?;
177        if buffer.len() != N {
178            return Err(h.handle_error(DecodeError::from(DECODE_ERROR_BAD_LENGTH)));
179        }
180        Ok(ManagedByteArray { buffer })
181    }
182}
183
184#[derive(Clone)]
185pub(crate) struct ManagedBufferSizeContext(pub usize);
186
187impl TryStaticCast for ManagedBufferSizeContext {}
188
189impl<M, const N: usize> NestedEncode for ManagedByteArray<M, N>
190where
191    M: ManagedTypeApi,
192{
193    #[inline]
194    fn dep_encode_or_handle_err<O, H>(&self, dest: &mut O, h: H) -> Result<(), H::HandledErr>
195    where
196        O: NestedEncodeOutput,
197        H: EncodeErrorHandler,
198    {
199        if O::supports_specialized_type::<ManagedBuffer<M>>() {
200            dest.push_specialized((), &self.buffer, h)
201        } else {
202            dest.write(self.buffer.to_boxed_bytes().as_slice());
203            Ok(())
204        }
205    }
206}
207
208impl<M, const N: usize> NestedDecode for ManagedByteArray<M, N>
209where
210    M: ManagedTypeApi,
211{
212    fn dep_decode_or_handle_err<I, H>(input: &mut I, h: H) -> Result<Self, H::HandledErr>
213    where
214        I: NestedDecodeInput,
215        H: DecodeErrorHandler,
216    {
217        let buffer = if I::supports_specialized_type::<ManagedBuffer<M>>() {
218            input.read_specialized(ManagedBufferSizeContext(N), h)?
219        } else {
220            let byte_array = <[u8; N]>::dep_decode_or_handle_err(input, h)?;
221            byte_array.as_ref().into()
222        };
223        Ok(ManagedByteArray { buffer })
224    }
225}
226
227impl<M, const N: usize> TypeAbiFrom<ManagedByteArray<M, N>> for [u8; N] where M: ManagedTypeApi {}
228
229impl<M, const N: usize> TypeAbiFrom<Self> for ManagedByteArray<M, N> where M: ManagedTypeApi {}
230impl<M, const N: usize> TypeAbiFrom<&Self> for ManagedByteArray<M, N> where M: ManagedTypeApi {}
231
232impl<M, const N: usize> TypeAbi for ManagedByteArray<M, N>
233where
234    M: ManagedTypeApi,
235{
236    type Unmanaged = [u8; N];
237
238    /// It is semantically equivalent to `[u8; N]`.
239    fn type_name() -> TypeName {
240        <[u8; N] as TypeAbi>::type_name()
241    }
242
243    fn type_name_rust() -> TypeName {
244        format!("ManagedByteArray<$API, {N}usize>")
245    }
246}
247
248impl<M, const N: usize> SCLowerHex for ManagedByteArray<M, N>
249where
250    M: ManagedTypeApi,
251{
252    fn fmt<F: FormatByteReceiver>(&self, f: &mut F) {
253        SCLowerHex::fmt(&self.buffer, f)
254    }
255}
256
257impl<M, const N: usize> core::fmt::Debug for ManagedByteArray<M, N>
258where
259    M: ManagedTypeApi,
260{
261    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
262        f.debug_struct("ManagedByteArray")
263            .field("handle", &self.buffer.handle)
264            .field("size", &N)
265            .field("hex-value", &encode_bytes_as_hex(&self.to_byte_array()))
266            .finish()
267    }
268}