numbat_codec/
nested_ser.rs

1use alloc::boxed::Box;
2use alloc::string::String;
3use alloc::vec::Vec;
4use core::num::NonZeroUsize;
5
6use crate::codec_err::EncodeError;
7use crate::nested_ser_output::NestedEncodeOutput;
8use crate::TypeInfo;
9
10/// Most types will be encoded without any possibility of error.
11/// The trait is used to provide these implementations.
12/// This is currently not a substitute for implementing a proper TopEncode.
13pub trait NestedEncodeNoErr: Sized {
14    fn dep_encode_no_err<O: NestedEncodeOutput>(&self, dest: &mut O);
15}
16
17/// Trait that allows zero-copy write of value-references to slices in LE format.
18///
19/// Implementations should override `using_top_encoded` for value types and `dep_encode` and `size_hint` for allocating types.
20/// Wrapper types should override all methods.
21pub trait NestedEncode: Sized {
22    // !INTERNAL USE ONLY!
23    // This const helps SCALE to optimize the encoding/decoding by doing fake specialization.
24    #[doc(hidden)]
25    const TYPE_INFO: TypeInfo = TypeInfo::Unknown;
26
27    /// NestedEncode to output, using the format of an object nested inside another structure.
28    /// Does not provide compact version.
29    fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError>;
30
31    /// Version of `top_decode` that exits quickly in case of error.
32    /// Its purpose is to create smaller implementations
33    /// in cases where the application is supposed to exit directly on decode error.
34    fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
35        &self,
36        dest: &mut O,
37        c: ExitCtx,
38        exit: fn(ExitCtx, EncodeError) -> !,
39    ) {
40        match self.dep_encode(dest) {
41            Ok(v) => v,
42            Err(e) => exit(c, e),
43        }
44    }
45}
46
47macro_rules! dep_encode_from_no_err {
48    ($type:ty, $type_info:expr) => {
49        impl NestedEncode for $type {
50            const TYPE_INFO: TypeInfo = $type_info;
51
52            #[inline]
53            fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
54                self.dep_encode_no_err(dest);
55                Ok(())
56            }
57
58            #[inline]
59            fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
60                &self,
61                dest: &mut O,
62                _: ExitCtx,
63                _: fn(ExitCtx, EncodeError) -> !,
64            ) {
65                self.dep_encode_no_err(dest);
66            }
67        }
68    };
69}
70
71/// Convenience function for getting an object nested-encoded to a Vec<u8> directly.
72pub fn dep_encode_to_vec<T: NestedEncode>(obj: &T) -> Result<Vec<u8>, EncodeError> {
73    let mut bytes = Vec::<u8>::new();
74    obj.dep_encode(&mut bytes)?;
75    Ok(bytes)
76}
77
78/// Adds the concantenated encoded contents of a slice to an output buffer,
79/// without serializing the slice length.
80/// Byte slice is treated separately, via direct transmute.
81pub fn dep_encode_slice_contents<T: NestedEncode, O: NestedEncodeOutput>(
82    slice: &[T],
83    dest: &mut O,
84) -> Result<(), EncodeError> {
85    match T::TYPE_INFO {
86        TypeInfo::U8 => {
87            // cast &[T] to &[u8]
88            let slice: &[u8] =
89                unsafe { core::slice::from_raw_parts(slice.as_ptr() as *const u8, slice.len()) };
90            dest.write(slice);
91        },
92        _ => {
93            for x in slice {
94                x.dep_encode(dest)?;
95            }
96        },
97    }
98    Ok(())
99}
100
101pub fn dep_encode_slice_contents_or_exit<T, O, ExitCtx>(
102    slice: &[T],
103    dest: &mut O,
104    c: ExitCtx,
105    exit: fn(ExitCtx, EncodeError) -> !,
106) where
107    T: NestedEncode,
108    O: NestedEncodeOutput,
109    ExitCtx: Clone,
110{
111    match T::TYPE_INFO {
112        TypeInfo::U8 => {
113            // cast &[T] to &[u8]
114            let slice: &[u8] =
115                unsafe { core::slice::from_raw_parts(slice.as_ptr() as *const u8, slice.len()) };
116            dest.write(slice);
117        },
118        _ => {
119            for x in slice {
120                x.dep_encode_or_exit(dest, c.clone(), exit);
121            }
122        },
123    }
124}
125
126impl NestedEncodeNoErr for () {
127    fn dep_encode_no_err<O: NestedEncodeOutput>(&self, _: &mut O) {}
128}
129
130dep_encode_from_no_err! {(), TypeInfo::Unit}
131
132impl<T: NestedEncode> NestedEncode for &[T] {
133    fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
134        // push size
135        self.len().dep_encode(dest)?;
136        // actual data
137        dep_encode_slice_contents(self, dest)
138    }
139
140    fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
141        &self,
142        dest: &mut O,
143        c: ExitCtx,
144        exit: fn(ExitCtx, EncodeError) -> !,
145    ) {
146        // push size
147        self.len().dep_encode_or_exit(dest, c.clone(), exit);
148        // actual data
149        dep_encode_slice_contents_or_exit(self, dest, c, exit);
150    }
151}
152
153impl<T: NestedEncode> NestedEncode for &T {
154    #[inline]
155    fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
156        (*self).dep_encode(dest)
157    }
158
159    fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
160        &self,
161        dest: &mut O,
162        c: ExitCtx,
163        exit: fn(ExitCtx, EncodeError) -> !,
164    ) {
165        (*self).dep_encode_or_exit(dest, c, exit);
166    }
167}
168
169impl NestedEncode for &str {
170    fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
171        self.as_bytes().dep_encode(dest)
172    }
173
174    fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
175        &self,
176        dest: &mut O,
177        c: ExitCtx,
178        exit: fn(ExitCtx, EncodeError) -> !,
179    ) {
180        self.as_bytes().dep_encode_or_exit(dest, c, exit);
181    }
182}
183
184impl<T: NestedEncode> NestedEncode for Vec<T> {
185    #[inline]
186    fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
187        self.as_slice().dep_encode(dest)
188    }
189
190    #[inline]
191    fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
192        &self,
193        dest: &mut O,
194        c: ExitCtx,
195        exit: fn(ExitCtx, EncodeError) -> !,
196    ) {
197        self.as_slice().dep_encode_or_exit(dest, c, exit);
198    }
199}
200
201impl NestedEncode for String {
202    #[inline]
203    fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
204        self.as_bytes().dep_encode(dest)
205    }
206
207    #[inline]
208    fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
209        &self,
210        dest: &mut O,
211        c: ExitCtx,
212        exit: fn(ExitCtx, EncodeError) -> !,
213    ) {
214        self.as_bytes().dep_encode_or_exit(dest, c, exit);
215    }
216}
217
218impl NestedEncode for Box<str> {
219    #[inline]
220    fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
221        self.as_ref().as_bytes().dep_encode(dest)
222    }
223
224    #[inline]
225    fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
226        &self,
227        dest: &mut O,
228        c: ExitCtx,
229        exit: fn(ExitCtx, EncodeError) -> !,
230    ) {
231        self.as_ref().as_bytes().dep_encode_or_exit(dest, c, exit);
232    }
233}
234
235// The main unsigned types need to be reversed before serializing.
236macro_rules! encode_num_unsigned {
237    ($num_type:ty, $size_in_bits:expr, $type_info:expr) => {
238        impl NestedEncodeNoErr for $num_type {
239            #[inline(never)]
240            fn dep_encode_no_err<O: NestedEncodeOutput>(&self, dest: &mut O) {
241                dest.write(&self.to_be_bytes()[..]);
242            }
243        }
244
245        dep_encode_from_no_err! {$num_type, $type_info}
246    };
247}
248
249encode_num_unsigned! {u64, 64, TypeInfo::U64}
250encode_num_unsigned! {u32, 32, TypeInfo::U32}
251encode_num_unsigned! {u16, 16, TypeInfo::U16}
252
253// No reversing needed for u8, because it is a single byte.
254impl NestedEncodeNoErr for u8 {
255    fn dep_encode_no_err<O: NestedEncodeOutput>(&self, dest: &mut O) {
256        dest.push_byte(*self as u8);
257    }
258}
259
260dep_encode_from_no_err! {u8, TypeInfo::U8}
261
262// Derive the implementation of the other types by casting.
263macro_rules! encode_num_mimic {
264    ($num_type:ty, $mimic_type:ident, $type_info:expr) => {
265        impl NestedEncodeNoErr for $num_type {
266            #[inline]
267            fn dep_encode_no_err<O: NestedEncodeOutput>(&self, dest: &mut O) {
268                (*self as $mimic_type).dep_encode_no_err(dest)
269            }
270        }
271
272        dep_encode_from_no_err! {$num_type, $type_info}
273    };
274}
275
276encode_num_mimic! {usize, u32, TypeInfo::USIZE}
277encode_num_mimic! {i64, u64, TypeInfo::I64}
278encode_num_mimic! {i32, u32, TypeInfo::I32}
279encode_num_mimic! {isize, u32, TypeInfo::ISIZE}
280encode_num_mimic! {i16, u16, TypeInfo::I16}
281encode_num_mimic! {i8, u8, TypeInfo::I8}
282encode_num_mimic! {bool, u8, TypeInfo::Bool}
283
284impl<T: NestedEncode> NestedEncode for Option<T> {
285    fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
286        match self {
287            Some(v) => {
288                dest.push_byte(1u8);
289                v.dep_encode(dest)
290            },
291            None => {
292                dest.push_byte(0u8);
293                Ok(())
294            },
295        }
296    }
297
298    fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
299        &self,
300        dest: &mut O,
301        c: ExitCtx,
302        exit: fn(ExitCtx, EncodeError) -> !,
303    ) {
304        match self {
305            Some(v) => {
306                dest.push_byte(1u8);
307                v.dep_encode_or_exit(dest, c, exit);
308            },
309            None => {
310                dest.push_byte(0u8);
311            },
312        }
313    }
314}
315
316impl<T: NestedEncode> NestedEncode for Box<T> {
317    #[inline(never)]
318    fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
319        self.as_ref().dep_encode(dest)
320    }
321
322    fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
323        &self,
324        dest: &mut O,
325        c: ExitCtx,
326        exit: fn(ExitCtx, EncodeError) -> !,
327    ) {
328        self.as_ref().dep_encode_or_exit(dest, c, exit);
329    }
330}
331
332impl<T: NestedEncode> NestedEncode for Box<[T]> {
333    fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
334        self.as_ref().dep_encode(dest)
335    }
336
337    fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
338        &self,
339        dest: &mut O,
340        c: ExitCtx,
341        exit: fn(ExitCtx, EncodeError) -> !,
342    ) {
343        self.as_ref().dep_encode_or_exit(dest, c, exit);
344    }
345}
346
347macro_rules! tuple_impls {
348    ($(($($n:tt $name:ident)+))+) => {
349        $(
350            impl<$($name),+> NestedEncode for ($($name,)+)
351            where
352                $($name: NestedEncode,)+
353            {
354				fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
355					$(
356                        self.$n.dep_encode(dest)?;
357                    )+
358					Ok(())
359				}
360
361				fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(&self, dest: &mut O, c: ExitCtx, exit: fn(ExitCtx, EncodeError) -> !) {
362					$(
363                        self.$n.dep_encode_or_exit(dest, c.clone(), exit);
364                    )+
365				}
366            }
367        )+
368    }
369}
370
371tuple_impls! {
372    (0 T0)
373    (0 T0 1 T1)
374    (0 T0 1 T1 2 T2)
375    (0 T0 1 T1 2 T2 3 T3)
376    (0 T0 1 T1 2 T2 3 T3 4 T4)
377    (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5)
378    (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6)
379    (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7)
380    (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8)
381    (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9)
382    (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10)
383    (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11)
384    (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)
385    (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)
386    (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)
387    (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)
388}
389
390impl NestedEncode for NonZeroUsize {
391    #[inline]
392    fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
393        self.get().dep_encode(dest)
394    }
395
396    #[inline]
397    fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
398        &self,
399        dest: &mut O,
400        c: ExitCtx,
401        exit: fn(ExitCtx, EncodeError) -> !,
402    ) {
403        self.get().dep_encode_or_exit(dest, c, exit);
404    }
405}
406
407////////////////////////////////////////////////////////////////////////////////
408
409#[cfg(test)]
410mod tests {
411    use super::super::test_struct::*;
412    use super::*;
413    use crate::test_util::check_dep_encode;
414    use core::fmt::Debug;
415
416    fn ser_ok<V>(element: V, expected_bytes: &[u8])
417    where
418        V: NestedEncode + PartialEq + Debug + 'static,
419    {
420        let bytes = check_dep_encode(&element);
421        assert_eq!(bytes.as_slice(), expected_bytes);
422    }
423
424    #[test]
425    fn test_dep_encode_numbers() {
426        // unsigned positive
427        ser_ok(5u8, &[5]);
428        ser_ok(5u16, &[0, 5]);
429        ser_ok(5u32, &[0, 0, 0, 5]);
430        ser_ok(5usize, &[0, 0, 0, 5]);
431        ser_ok(5u64, &[0, 0, 0, 0, 0, 0, 0, 5]);
432        // signed positive
433        ser_ok(5i8, &[5]);
434        ser_ok(5i16, &[0, 5]);
435        ser_ok(5i32, &[0, 0, 0, 5]);
436        ser_ok(5isize, &[0, 0, 0, 5]);
437        ser_ok(5i64, &[0, 0, 0, 0, 0, 0, 0, 5]);
438        // signed negative
439        ser_ok(-5i8, &[251]);
440        ser_ok(-5i16, &[255, 251]);
441        ser_ok(-5i32, &[255, 255, 255, 251]);
442        ser_ok(-5isize, &[255, 255, 255, 251]);
443        ser_ok(-5i64, &[255, 255, 255, 255, 255, 255, 255, 251]);
444        // non zero usize
445        ser_ok(NonZeroUsize::new(5).unwrap(), &[0, 0, 0, 5]);
446    }
447
448    #[test]
449    fn test_dep_encode_bool() {
450        ser_ok(true, &[1]);
451        ser_ok(false, &[0]);
452    }
453
454    #[test]
455    fn test_dep_encode_empty_bytes() {
456        let empty_byte_slice: &[u8] = &[];
457        ser_ok(empty_byte_slice, &[0, 0, 0, 0]);
458    }
459
460    #[test]
461    fn test_dep_encode_bytes() {
462        ser_ok(&[1u8, 2u8, 3u8][..], &[0, 0, 0, 3, 1u8, 2u8, 3u8]);
463    }
464
465    #[test]
466    fn test_dep_encode_vec_u8() {
467        let some_vec = [1u8, 2u8, 3u8].to_vec();
468        ser_ok(some_vec, &[0, 0, 0, 3, 1u8, 2u8, 3u8]);
469    }
470
471    #[test]
472	#[rustfmt::skip]
473	fn test_dep_encode_str() {
474		let s = "abc";
475		ser_ok(s, &[0, 0, 0, 3, b'a', b'b', b'c']);
476		ser_ok(String::from(s), &[0, 0, 0, 3, b'a', b'b', b'c']);
477		ser_ok(String::from(s).into_boxed_str(), &[0, 0, 0, 3, b'a', b'b', b'c']);
478	}
479
480    #[test]
481    fn test_dep_encode_vec_i32() {
482        let some_vec = [1i32, 2i32, 3i32].to_vec();
483        let expected: &[u8] = &[0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3];
484        ser_ok(some_vec, expected);
485    }
486
487    #[test]
488    fn test_struct() {
489        let test = Test {
490            int: 1,
491            seq: [5, 6].to_vec(),
492            another_byte: 7,
493        };
494
495        ser_ok(test, &[0, 1, 0, 0, 0, 2, 5, 6, 7]);
496    }
497
498    #[test]
499    fn test_tuple() {
500        ser_ok((7u32, -2i16), &[0, 0, 0, 7, 255, 254]);
501    }
502
503    #[test]
504    fn test_unit() {
505        ser_ok((), &[]);
506    }
507
508    #[test]
509    fn test_enum() {
510        let u = E::Unit;
511        let expected: &[u8] = &[/*variant index*/ 0, 0, 0, 0];
512        ser_ok(u, expected);
513
514        let n = E::Newtype(1);
515        let expected: &[u8] = &[/*variant index*/ 0, 0, 0, 1, /*data*/ 0, 0, 0, 1];
516        ser_ok(n, expected);
517
518        let t = E::Tuple(1, 2);
519        let expected: &[u8] = &[
520            /*variant index*/ 0, 0, 0, 2, /*(*/ 0, 0, 0, 1, /*,*/ 0, 0, 0,
521            2, /*)*/
522        ];
523        ser_ok(t, expected);
524
525        let s = E::Struct { a: 1 };
526        let expected: &[u8] = &[/*variant index*/ 0, 0, 0, 3, /*data*/ 0, 0, 0, 1];
527        ser_ok(s, expected);
528    }
529}