numbat_codec/
nested_de.rs

1use alloc::boxed::Box;
2use alloc::string::String;
3use alloc::vec::Vec;
4use core::num::NonZeroUsize;
5
6use crate::codec_err::DecodeError;
7use crate::nested_de_input::NestedDecodeInput;
8use crate::num_conv::bytes_to_number;
9use crate::TypeInfo;
10
11/// Trait that allows zero-copy read of value-references from slices in LE format.
12pub trait NestedDecode: Sized {
13    // !INTERNAL USE ONLY!
14    // This const helps numbat-wasm to optimize the encoding/decoding by doing fake specialization.
15    #[doc(hidden)]
16    const TYPE_INFO: TypeInfo = TypeInfo::Unknown;
17
18    /// Attempt to deserialise the value from input,
19    /// using the format of an object nested inside another structure.
20    /// In case of success returns the deserialized value and the number of bytes consumed during the operation.
21    fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError>;
22
23    /// Version of `top_decode` that exits quickly in case of error.
24    /// Its purpose is to create smaller implementations
25    /// in cases where the application is supposed to exit directly on decode error.
26    fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
27        input: &mut I,
28        c: ExitCtx,
29        exit: fn(ExitCtx, DecodeError) -> !,
30    ) -> Self {
31        match Self::dep_decode(input) {
32            Ok(v) => v,
33            Err(e) => exit(c, e),
34        }
35    }
36}
37
38/// Convenience method, to avoid having to specify type when calling `dep_decode`.
39/// Especially useful in the macros.
40/// Also checks that the entire slice was used.
41/// The input doesn't need to be mutable because we are not changing the underlying data.
42pub fn dep_decode_from_byte_slice<D: NestedDecode>(input: &[u8]) -> Result<D, DecodeError> {
43    let mut_slice = &mut &*input;
44    let result = D::dep_decode(mut_slice);
45    if !mut_slice.is_empty() {
46        return Err(DecodeError::INPUT_TOO_LONG);
47    }
48    result
49}
50
51pub fn dep_decode_from_byte_slice_or_exit<D: NestedDecode, ExitCtx: Clone>(
52    input: &[u8],
53    c: ExitCtx,
54    exit: fn(ExitCtx, DecodeError) -> !,
55) -> D {
56    let mut_slice = &mut &*input;
57    let result = D::dep_decode_or_exit(mut_slice, c.clone(), exit);
58    if !mut_slice.is_empty() {
59        exit(c, DecodeError::INPUT_TOO_LONG);
60    }
61    result
62}
63
64impl NestedDecode for () {
65    const TYPE_INFO: TypeInfo = TypeInfo::Unit;
66
67    fn dep_decode<I: NestedDecodeInput>(_: &mut I) -> Result<(), DecodeError> {
68        Ok(())
69    }
70
71    fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
72        _: &mut I,
73        _: ExitCtx,
74        _: fn(ExitCtx, DecodeError) -> !,
75    ) -> Self {
76    }
77}
78
79impl NestedDecode for u8 {
80    const TYPE_INFO: TypeInfo = TypeInfo::U8;
81
82    fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
83        input.read_byte()
84    }
85
86    fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
87        input: &mut I,
88        c: ExitCtx,
89        exit: fn(ExitCtx, DecodeError) -> !,
90    ) -> Self {
91        input.read_byte_or_exit(c, exit)
92    }
93}
94
95impl<T: NestedDecode> NestedDecode for Vec<T> {
96    fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
97        let size = usize::dep_decode(input)?;
98        match T::TYPE_INFO {
99            TypeInfo::U8 => {
100                let bytes = input.read_slice(size)?;
101                let bytes_copy = bytes.to_vec(); // copy is needed because result might outlive input
102                let cast_vec: Vec<T> = unsafe { core::mem::transmute(bytes_copy) };
103                Ok(cast_vec)
104            },
105            _ => {
106                let mut result: Vec<T> = Vec::with_capacity(size);
107                for _ in 0..size {
108                    result.push(T::dep_decode(input)?);
109                }
110                Ok(result)
111            },
112        }
113    }
114
115    fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
116        input: &mut I,
117        c: ExitCtx,
118        exit: fn(ExitCtx, DecodeError) -> !,
119    ) -> Self {
120        let size = usize::dep_decode_or_exit(input, c.clone(), exit);
121        match T::TYPE_INFO {
122            TypeInfo::U8 => {
123                let bytes = input.read_slice_or_exit(size, c, exit);
124                let bytes_copy = bytes.to_vec(); // copy is needed because result might outlive input
125                let cast_vec: Vec<T> = unsafe { core::mem::transmute(bytes_copy) };
126                cast_vec
127            },
128            _ => {
129                let mut result: Vec<T> = Vec::with_capacity(size);
130                for _ in 0..size {
131                    result.push(T::dep_decode_or_exit(input, c.clone(), exit));
132                }
133                result
134            },
135        }
136    }
137}
138
139impl NestedDecode for String {
140    fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
141        let raw = Vec::<u8>::dep_decode(input)?;
142        match String::from_utf8(raw) {
143            Ok(s) => Ok(s),
144            Err(_) => Err(DecodeError::UTF8_DECODE_ERROR),
145        }
146    }
147
148    fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
149        input: &mut I,
150        c: ExitCtx,
151        exit: fn(ExitCtx, DecodeError) -> !,
152    ) -> Self {
153        let raw = Vec::<u8>::dep_decode_or_exit(input, c.clone(), exit);
154        match String::from_utf8(raw) {
155            Ok(s) => s,
156            Err(_) => exit(c, DecodeError::UTF8_DECODE_ERROR),
157        }
158    }
159}
160
161impl NestedDecode for Box<str> {
162    #[inline]
163    fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
164        Ok(String::dep_decode(input)?.into_boxed_str())
165    }
166
167    #[inline]
168    fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
169        input: &mut I,
170        c: ExitCtx,
171        exit: fn(ExitCtx, DecodeError) -> !,
172    ) -> Self {
173        String::dep_decode_or_exit(input, c, exit).into_boxed_str()
174    }
175}
176
177macro_rules! decode_num_unsigned {
178    ($ty:ty, $num_bytes:expr, $type_info:expr) => {
179        impl NestedDecode for $ty {
180            const TYPE_INFO: TypeInfo = $type_info;
181
182            fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
183                let bytes = input.read_slice($num_bytes)?;
184                let num = bytes_to_number(bytes, false) as $ty;
185                Ok(num)
186            }
187
188            fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
189                input: &mut I,
190                c: ExitCtx,
191                exit: fn(ExitCtx, DecodeError) -> !,
192            ) -> Self {
193                let bytes = input.read_slice_or_exit($num_bytes, c, exit);
194                let num = bytes_to_number(bytes, false) as $ty;
195                num
196            }
197        }
198    };
199}
200
201decode_num_unsigned!(u16, 2, TypeInfo::U16);
202decode_num_unsigned!(u32, 4, TypeInfo::U32);
203decode_num_unsigned!(usize, 4, TypeInfo::USIZE);
204decode_num_unsigned!(u64, 8, TypeInfo::U64);
205
206macro_rules! decode_num_signed {
207    ($ty:ty, $num_bytes:expr, $type_info:expr) => {
208        impl NestedDecode for $ty {
209            const TYPE_INFO: TypeInfo = $type_info;
210
211            fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
212                let bytes = input.read_slice($num_bytes)?;
213                let num = bytes_to_number(bytes, true) as $ty;
214                Ok(num)
215            }
216
217            fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
218                input: &mut I,
219                c: ExitCtx,
220                exit: fn(ExitCtx, DecodeError) -> !,
221            ) -> Self {
222                let bytes = input.read_slice_or_exit($num_bytes, c, exit);
223                let num = bytes_to_number(bytes, true) as $ty;
224                num
225            }
226        }
227    };
228}
229
230decode_num_signed!(i8, 1, TypeInfo::I8);
231decode_num_signed!(i16, 2, TypeInfo::I16);
232decode_num_signed!(i32, 4, TypeInfo::I32);
233decode_num_signed!(isize, 4, TypeInfo::ISIZE);
234decode_num_signed!(i64, 8, TypeInfo::I64);
235
236impl NestedDecode for bool {
237    const TYPE_INFO: TypeInfo = TypeInfo::Bool;
238
239    fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
240        match input.read_byte()? {
241            0 => Ok(false),
242            1 => Ok(true),
243            _ => Err(DecodeError::INVALID_VALUE),
244        }
245    }
246
247    fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
248        input: &mut I,
249        c: ExitCtx,
250        exit: fn(ExitCtx, DecodeError) -> !,
251    ) -> Self {
252        match input.read_byte_or_exit(c.clone(), exit) {
253            0 => false,
254            1 => true,
255            _ => exit(c, DecodeError::INVALID_VALUE),
256        }
257    }
258}
259
260impl<T: NestedDecode> NestedDecode for Option<T> {
261    fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
262        match input.read_byte()? {
263            0 => Ok(None),
264            1 => Ok(Some(T::dep_decode(input)?)),
265            _ => Err(DecodeError::INVALID_VALUE),
266        }
267    }
268
269    fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
270        input: &mut I,
271        c: ExitCtx,
272        exit: fn(ExitCtx, DecodeError) -> !,
273    ) -> Self {
274        match input.read_byte_or_exit(c.clone(), exit) {
275            0 => None,
276            1 => Some(T::dep_decode_or_exit(input, c, exit)),
277            _ => exit(c, DecodeError::INVALID_VALUE),
278        }
279    }
280}
281
282impl<T: NestedDecode> NestedDecode for Box<T> {
283    fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
284        Ok(Box::new(T::dep_decode(input)?))
285    }
286
287    fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
288        input: &mut I,
289        c: ExitCtx,
290        exit: fn(ExitCtx, DecodeError) -> !,
291    ) -> Self {
292        Box::new(T::dep_decode_or_exit(input, c, exit))
293    }
294}
295
296macro_rules! tuple_impls {
297    ($($len:expr => ($($n:tt $name:ident)+))+) => {
298        $(
299            impl<$($name),+> NestedDecode for ($($name,)+)
300            where
301                $($name: NestedDecode,)+
302            {
303                fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
304                    Ok((
305                        $(
306                            $name::dep_decode(input)?,
307                        )+
308                    ))
309                }
310
311                fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(input: &mut I, c: ExitCtx, exit: fn(ExitCtx, DecodeError) -> !) -> Self {
312                    (
313                        $(
314                            $name::dep_decode_or_exit(input, c.clone(), exit),
315                        )+
316                    )
317                }
318            }
319        )+
320    }
321}
322
323tuple_impls! {
324    1 => (0 T0)
325    2 => (0 T0 1 T1)
326    3 => (0 T0 1 T1 2 T2)
327    4 => (0 T0 1 T1 2 T2 3 T3)
328    5 => (0 T0 1 T1 2 T2 3 T3 4 T4)
329    6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5)
330    7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6)
331    8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7)
332    9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8)
333    10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9)
334    11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10)
335    12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11)
336    13 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12)
337    14 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13)
338    15 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14)
339    16 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15)
340}
341
342impl NestedDecode for NonZeroUsize {
343    fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
344        if let Some(nz) = NonZeroUsize::new(usize::dep_decode(input)?) {
345            Ok(nz)
346        } else {
347            Err(DecodeError::INVALID_VALUE)
348        }
349    }
350
351    fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
352        input: &mut I,
353        c: ExitCtx,
354        exit: fn(ExitCtx, DecodeError) -> !,
355    ) -> Self {
356        if let Some(nz) = NonZeroUsize::new(usize::dep_decode_or_exit(input, c.clone(), exit)) {
357            nz
358        } else {
359            exit(c, DecodeError::INVALID_VALUE)
360        }
361    }
362}
363
364////////////////////////////////////////////////////////////////////////////////
365
366#[cfg(test)]
367mod tests {
368    use super::super::test_struct::*;
369    use super::*;
370    use crate::test_util::check_dep_decode;
371    use core::fmt::Debug;
372
373    fn deser_ok<V>(element: V, bytes: &[u8])
374    where
375        V: NestedDecode + PartialEq + Debug + 'static,
376    {
377        let input = bytes.to_vec();
378        let deserialized: V = check_dep_decode::<V>(&input[..]);
379        assert_eq!(deserialized, element);
380    }
381
382    #[test]
383    fn test_dep_decode_numbers() {
384        // unsigned positive
385        deser_ok(5u8, &[5]);
386        deser_ok(5u16, &[0, 5]);
387        deser_ok(5u32, &[0, 0, 0, 5]);
388        deser_ok(5usize, &[0, 0, 0, 5]);
389        deser_ok(5u64, &[0, 0, 0, 0, 0, 0, 0, 5]);
390        // signed positive
391        deser_ok(5i8, &[5]);
392        deser_ok(5i16, &[0, 5]);
393        deser_ok(5i32, &[0, 0, 0, 5]);
394        deser_ok(5isize, &[0, 0, 0, 5]);
395        deser_ok(5i64, &[0, 0, 0, 0, 0, 0, 0, 5]);
396        // signed negative
397        deser_ok(-5i8, &[251]);
398        deser_ok(-5i16, &[255, 251]);
399        deser_ok(-5i32, &[255, 255, 255, 251]);
400        deser_ok(-5isize, &[255, 255, 255, 251]);
401        deser_ok(-5i64, &[255, 255, 255, 255, 255, 255, 255, 251]);
402        // non zero usize
403        deser_ok(NonZeroUsize::new(5).unwrap(), &[0, 0, 0, 5]);
404    }
405
406    #[test]
407	#[rustfmt::skip]
408	fn test_dep_decode_str() {
409		deser_ok(String::from("abc"), &[0, 0, 0, 3, b'a', b'b', b'c']);
410		deser_ok(String::from("abc").into_boxed_str(), &[0, 0, 0, 3, b'a', b'b', b'c']);
411	}
412
413    #[test]
414    fn test_struct() {
415        let test = Test {
416            int: 1,
417            seq: [5, 6].to_vec(),
418            another_byte: 7,
419        };
420        deser_ok(test, &[0, 1, 0, 0, 0, 2, 5, 6, 7]);
421    }
422
423    #[test]
424    fn test_enum() {
425        let u = E::Unit;
426        let expected: &[u8] = &[/*variant index*/ 0, 0, 0, 0];
427        deser_ok(u, expected);
428
429        let n = E::Newtype(1);
430        let expected: &[u8] = &[/*variant index*/ 0, 0, 0, 1, /*data*/ 0, 0, 0, 1];
431        deser_ok(n, expected);
432
433        let t = E::Tuple(1, 2);
434        let expected: &[u8] = &[
435            /*variant index*/ 0, 0, 0, 2, /*(*/ 0, 0, 0, 1, /*,*/ 0, 0, 0,
436            2, /*)*/
437        ];
438        deser_ok(t, expected);
439
440        let s = E::Struct { a: 1 };
441        let expected: &[u8] = &[/*variant index*/ 0, 0, 0, 3, /*data*/ 0, 0, 0, 1];
442        deser_ok(s, expected);
443    }
444}