sbor/codec/
array.rs

1use crate::rust::mem::MaybeUninit;
2use crate::value_kind::*;
3use crate::*;
4
5impl<X: CustomValueKind, T> Categorize<X> for [T] {
6    #[inline]
7    fn value_kind() -> ValueKind<X> {
8        ValueKind::Array
9    }
10}
11
12impl<X: CustomValueKind, T, const N: usize> Categorize<X> for [T; N] {
13    #[inline]
14    fn value_kind() -> ValueKind<X> {
15        ValueKind::Array
16    }
17}
18
19impl<X: CustomValueKind, E: Encoder<X>, T: Encode<X, E> + Categorize<X>> Encode<X, E> for [T] {
20    #[inline]
21    fn encode_value_kind(&self, encoder: &mut E) -> Result<(), EncodeError> {
22        encoder.write_value_kind(Self::value_kind())
23    }
24
25    #[inline]
26    fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> {
27        encoder.write_value_kind(T::value_kind())?;
28        encoder.write_size(self.len())?;
29        if T::value_kind() == ValueKind::U8 || T::value_kind() == ValueKind::I8 {
30            let ptr = self.as_ptr().cast::<u8>();
31            let slice = unsafe { sbor::rust::slice::from_raw_parts(ptr, self.len()) };
32            encoder.write_slice(slice)?;
33        } else {
34            for v in self {
35                encoder.encode_deeper_body(v)?;
36            }
37        }
38        Ok(())
39    }
40}
41
42impl<X: CustomValueKind, E: Encoder<X>, T: Encode<X, E> + Categorize<X>, const N: usize>
43    Encode<X, E> for [T; N]
44{
45    #[inline]
46    fn encode_value_kind(&self, encoder: &mut E) -> Result<(), EncodeError> {
47        encoder.write_value_kind(Self::value_kind())
48    }
49    #[inline]
50    fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> {
51        self.as_slice().encode_body(encoder)
52    }
53}
54
55#[allow(clippy::forget_non_drop)]
56impl<X: CustomValueKind, D: Decoder<X>, T: Decode<X, D> + Categorize<X>, const N: usize>
57    Decode<X, D> for [T; N]
58{
59    #[inline]
60    fn decode_body_with_value_kind(
61        decoder: &mut D,
62        value_kind: ValueKind<X>,
63    ) -> Result<Self, DecodeError> {
64        decoder.check_preloaded_value_kind(value_kind, Self::value_kind())?;
65        let element_value_kind = decoder.read_and_check_value_kind(T::value_kind())?;
66        decoder.read_and_check_size(N)?;
67
68        // Please read:
69        // * https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#initializing-an-array-element-by-element
70        // * https://github.com/rust-lang/rust/issues/61956
71        //
72        // TODO: replace with `uninit_array` and `assume_array_init` once they're stable
73
74        // Create an uninitialized array
75        let mut data: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() };
76
77        // Decode element by element
78        for elem in &mut data[..] {
79            elem.write(decoder.decode_deeper_body_with_value_kind(element_value_kind)?);
80        }
81
82        // Use &mut as an assertion of unique "ownership"
83        let ptr = &mut data as *mut _ as *mut [T; N];
84        let res = unsafe { ptr.read() };
85        core::mem::forget(data);
86
87        Ok(res)
88    }
89}
90
91mod schema {
92    use super::*;
93
94    impl<C: CustomTypeKind<RustTypeId>, T: Describe<C>> Describe<C> for [T] {
95        const TYPE_ID: RustTypeId = match T::TYPE_ID {
96            RustTypeId::WellKnown(basic_well_known_types::U8_TYPE) => {
97                RustTypeId::WellKnown(basic_well_known_types::BYTES_TYPE)
98            }
99            _ => RustTypeId::novel("Array", &[T::TYPE_ID]),
100        };
101
102        fn type_data() -> TypeData<C, RustTypeId> {
103            match T::TYPE_ID {
104                RustTypeId::WellKnown(basic_well_known_types::U8_TYPE) => {
105                    basic_well_known_types::bytes_type_data()
106                }
107                _ => TypeData::new(
108                    TypeKind::Array {
109                        element_type: T::TYPE_ID,
110                    },
111                    TypeMetadata::unnamed(),
112                ),
113            }
114        }
115
116        fn add_all_dependencies(aggregator: &mut TypeAggregator<C>) {
117            aggregator.add_child_type_and_descendents::<T>();
118        }
119    }
120
121    impl<C: CustomTypeKind<RustTypeId>, T: Describe<C>, const N: usize> Describe<C> for [T; N] {
122        const TYPE_ID: RustTypeId = RustTypeId::novel_validated(
123            "Array",
124            &[T::TYPE_ID],
125            &[("min", &N.to_le_bytes()), ("max", &N.to_le_bytes())],
126        );
127
128        fn type_data() -> TypeData<C, RustTypeId> {
129            let size = N
130                .try_into()
131                .expect("The array length is too large for a u32 for the SBOR schema");
132
133            TypeData::new(
134                TypeKind::Array {
135                    element_type: T::TYPE_ID,
136                },
137                TypeMetadata::unnamed(),
138            )
139            .with_validation(TypeValidation::Array(LengthValidation {
140                min: Some(size),
141                max: Some(size),
142            }))
143        }
144
145        fn add_all_dependencies(aggregator: &mut TypeAggregator<C>) {
146            aggregator.add_child_type_and_descendents::<T>();
147        }
148    }
149}