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