numbat_codec/
lib.rs

1#![no_std]
2
3extern crate alloc;
4
5#[cfg(feature = "numbat-codec-derive")]
6pub use numbat_codec_derive;
7
8/// Reexport needed by derive.
9pub use alloc::vec::Vec;
10
11mod codec_err;
12mod default_traits;
13mod impl_array;
14mod nested_de;
15mod nested_de_input;
16mod nested_ser;
17mod nested_ser_output;
18mod num_conv;
19pub mod test_util;
20mod top_de;
21mod top_de_input;
22mod top_ser;
23mod top_ser_output;
24mod transmute;
25
26pub use crate::nested_de_input::NestedDecodeInput;
27pub use crate::nested_ser_output::NestedEncodeOutput;
28pub use crate::num_conv::{bytes_to_number, top_encode_number_to_output, using_encoded_number};
29pub use codec_err::{DecodeError, EncodeError};
30pub use default_traits::{DecodeDefault, EncodeDefault};
31pub use nested_de::{dep_decode_from_byte_slice, dep_decode_from_byte_slice_or_exit, NestedDecode};
32pub use nested_ser::{dep_encode_to_vec, NestedEncode, NestedEncodeNoErr};
33pub use top_de::{top_decode_from_nested, top_decode_from_nested_or_exit, TopDecode};
34pub use top_de_input::TopDecodeInput;
35pub use top_ser::{
36    top_encode_from_nested, top_encode_from_nested_or_exit, top_encode_no_err, top_encode_to_vec,
37    TopEncode,
38};
39pub use top_ser_output::TopEncodeOutput;
40pub use transmute::{boxed_slice_into_vec, vec_into_boxed_slice};
41
42/// !INTERNAL USE ONLY!
43///
44/// This enum provides type information to optimize encoding/decoding by doing fake specialization.
45#[doc(hidden)]
46#[allow(clippy::upper_case_acronyms)]
47pub enum TypeInfo {
48    /// Default value of [`NestedEncode::TYPE_INFO`] to not require implementors to set this value in the trait.
49    Unknown,
50    U8,
51    I8,
52    U16,
53    I16,
54    U32,
55    I32,
56    USIZE,
57    ISIZE,
58    U64,
59    I64,
60    Bool,
61    BigUint,
62    BigInt,
63    Unit,
64}
65
66/// Until we have derive capabilities, here are some structures with explicit encode/decode, for testing.
67#[cfg(test)]
68pub mod test_struct {
69    use super::*;
70    use alloc::vec::Vec;
71    use core::fmt::Debug;
72
73    #[derive(PartialEq, Debug)]
74    pub struct Test {
75        pub int: u16,
76        pub seq: Vec<u8>,
77        pub another_byte: u8,
78    }
79
80    impl NestedEncode for Test {
81        fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
82            self.int.dep_encode(dest)?;
83            self.seq.dep_encode(dest)?;
84            self.another_byte.dep_encode(dest)?;
85            Ok(())
86        }
87
88        fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
89            &self,
90            dest: &mut O,
91            c: ExitCtx,
92            exit: fn(ExitCtx, EncodeError) -> !,
93        ) {
94            self.int.dep_encode_or_exit(dest, c.clone(), exit);
95            self.seq.dep_encode_or_exit(dest, c.clone(), exit);
96            self.another_byte.dep_encode_or_exit(dest, c.clone(), exit);
97        }
98    }
99
100    impl TopEncode for Test {
101        #[inline]
102        fn top_encode<O: TopEncodeOutput>(&self, output: O) -> Result<(), EncodeError> {
103            top_encode_from_nested(self, output)
104        }
105
106        #[inline]
107        fn top_encode_or_exit<O: TopEncodeOutput, ExitCtx: Clone>(
108            &self,
109            output: O,
110            c: ExitCtx,
111            exit: fn(ExitCtx, EncodeError) -> !,
112        ) {
113            top_encode_from_nested_or_exit(self, output, c, exit);
114        }
115    }
116
117    impl NestedDecode for Test {
118        fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
119            Ok(Test {
120                int: u16::dep_decode(input)?,
121                seq: Vec::<u8>::dep_decode(input)?,
122                another_byte: u8::dep_decode(input)?,
123            })
124        }
125
126        fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
127            input: &mut I,
128            c: ExitCtx,
129            exit: fn(ExitCtx, DecodeError) -> !,
130        ) -> Self {
131            Test {
132                int: u16::dep_decode_or_exit(input, c.clone(), exit),
133                seq: Vec::<u8>::dep_decode_or_exit(input, c.clone(), exit),
134                another_byte: u8::dep_decode_or_exit(input, c.clone(), exit),
135            }
136        }
137    }
138
139    impl TopDecode for Test {
140        fn top_decode<I: TopDecodeInput>(input: I) -> Result<Self, DecodeError> {
141            top_decode_from_nested(input)
142        }
143
144        fn top_decode_or_exit<I: TopDecodeInput, ExitCtx: Clone>(
145            input: I,
146            c: ExitCtx,
147            exit: fn(ExitCtx, DecodeError) -> !,
148        ) -> Self {
149            top_decode_from_nested_or_exit(input, c, exit)
150        }
151    }
152
153    #[derive(PartialEq, Clone, Debug)]
154    pub enum E {
155        Unit,
156        Newtype(u32),
157        Tuple(u32, u32),
158        Struct { a: u32 },
159    }
160
161    impl NestedEncodeNoErr for E {
162        fn dep_encode_no_err<O: NestedEncodeOutput>(&self, dest: &mut O) {
163            match self {
164                E::Unit => {
165                    0u32.dep_encode_no_err(dest);
166                },
167                E::Newtype(arg1) => {
168                    1u32.dep_encode_no_err(dest);
169                    arg1.dep_encode_no_err(dest);
170                },
171                E::Tuple(arg1, arg2) => {
172                    2u32.dep_encode_no_err(dest);
173                    arg1.dep_encode_no_err(dest);
174                    arg2.dep_encode_no_err(dest);
175                },
176                E::Struct { a } => {
177                    3u32.dep_encode_no_err(dest);
178                    a.dep_encode_no_err(dest);
179                },
180            }
181        }
182    }
183
184    impl NestedEncode for E {
185        #[inline]
186        fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
187            self.dep_encode_no_err(dest);
188            Ok(())
189        }
190
191        #[inline]
192        fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
193            &self,
194            dest: &mut O,
195            _: ExitCtx,
196            _: fn(ExitCtx, EncodeError) -> !,
197        ) {
198            self.dep_encode_no_err(dest);
199        }
200    }
201
202    impl TopEncode for E {
203        #[inline]
204        fn top_encode<O: TopEncodeOutput>(&self, output: O) -> Result<(), EncodeError> {
205            top_encode_from_nested(self, output)
206        }
207
208        #[inline]
209        fn top_encode_or_exit<O: TopEncodeOutput, ExitCtx: Clone>(
210            &self,
211            output: O,
212            c: ExitCtx,
213            exit: fn(ExitCtx, EncodeError) -> !,
214        ) {
215            top_encode_from_nested_or_exit(self, output, c, exit);
216        }
217    }
218
219    impl NestedDecode for E {
220        fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
221            match u32::dep_decode(input)? {
222                0 => Ok(E::Unit),
223                1 => Ok(E::Newtype(u32::dep_decode(input)?)),
224                2 => Ok(E::Tuple(u32::dep_decode(input)?, u32::dep_decode(input)?)),
225                3 => Ok(E::Struct {
226                    a: u32::dep_decode(input)?,
227                }),
228                _ => Err(DecodeError::INVALID_VALUE),
229            }
230        }
231
232        fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
233            input: &mut I,
234            c: ExitCtx,
235            exit: fn(ExitCtx, DecodeError) -> !,
236        ) -> Self {
237            match u32::dep_decode_or_exit(input, c.clone(), exit) {
238                0 => E::Unit,
239                1 => E::Newtype(u32::dep_decode_or_exit(input, c.clone(), exit)),
240                2 => E::Tuple(
241                    u32::dep_decode_or_exit(input, c.clone(), exit),
242                    u32::dep_decode_or_exit(input, c.clone(), exit),
243                ),
244                3 => E::Struct {
245                    a: u32::dep_decode_or_exit(input, c.clone(), exit),
246                },
247                _ => exit(c.clone(), DecodeError::INVALID_VALUE),
248            }
249        }
250    }
251
252    impl TopDecode for E {
253        fn top_decode<I: TopDecodeInput>(input: I) -> Result<Self, DecodeError> {
254            top_decode_from_nested(input)
255        }
256
257        fn top_decode_or_exit<I: TopDecodeInput, ExitCtx: Clone>(
258            input: I,
259            c: ExitCtx,
260            exit: fn(ExitCtx, DecodeError) -> !,
261        ) -> Self {
262            top_decode_from_nested_or_exit(input, c, exit)
263        }
264    }
265
266    #[derive(PartialEq, Debug, Clone, Copy)]
267    pub struct WrappedArray(pub [u8; 5]);
268
269    impl NestedEncode for WrappedArray {
270        fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
271            dest.write(&self.0[..]);
272            Ok(())
273        }
274
275        fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
276            &self,
277            dest: &mut O,
278            _: ExitCtx,
279            _: fn(ExitCtx, EncodeError) -> !,
280        ) {
281            dest.write(&self.0[..]);
282        }
283    }
284
285    impl TopEncode for WrappedArray {
286        fn top_encode<O: TopEncodeOutput>(&self, output: O) -> Result<(), EncodeError> {
287            output.set_slice_u8(&self.0[..]);
288            Ok(())
289        }
290
291        fn top_encode_or_exit<O: TopEncodeOutput, ExitCtx: Clone>(
292            &self,
293            output: O,
294            _: ExitCtx,
295            _: fn(ExitCtx, EncodeError) -> !,
296        ) {
297            output.set_slice_u8(&self.0[..]);
298        }
299    }
300
301    impl NestedDecode for WrappedArray {
302        fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
303            let mut arr = [0u8; 5];
304            input.read_into(&mut arr)?;
305            Ok(WrappedArray(arr))
306        }
307
308        fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
309            input: &mut I,
310            c: ExitCtx,
311            exit: fn(ExitCtx, DecodeError) -> !,
312        ) -> Self {
313            let mut arr = [0u8; 5];
314            input.read_into_or_exit(&mut arr, c, exit);
315            WrappedArray(arr)
316        }
317    }
318
319    impl TopDecode for WrappedArray {
320        fn top_decode<I: TopDecodeInput>(input: I) -> Result<Self, DecodeError> {
321            top_decode_from_nested(input)
322        }
323
324        fn top_decode_or_exit<I: TopDecodeInput, ExitCtx: Clone>(
325            input: I,
326            c: ExitCtx,
327            exit: fn(ExitCtx, DecodeError) -> !,
328        ) -> Self {
329            top_decode_from_nested_or_exit(input, c, exit)
330        }
331    }
332}
333
334#[cfg(test)]
335pub mod tests {
336    use super::test_struct::*;
337    use super::*;
338    use crate::test_util::{check_top_decode, check_top_encode, ser_deser_ok};
339    use alloc::vec::Vec;
340    use core::fmt::Debug;
341    use core::num::NonZeroUsize;
342
343    pub fn the_same<V>(element: V)
344    where
345        V: TopEncode + TopDecode + PartialEq + Debug + 'static,
346    {
347        let serialized_bytes = check_top_encode(&element);
348        let deserialized: V = check_top_decode::<V>(&serialized_bytes[..]);
349        assert_eq!(deserialized, element);
350    }
351
352    #[test]
353    fn test_top_compacted_numbers() {
354        // zero
355        ser_deser_ok(0u8, &[]);
356        ser_deser_ok(0u16, &[]);
357        ser_deser_ok(0u32, &[]);
358        ser_deser_ok(0u64, &[]);
359        ser_deser_ok(0usize, &[]);
360        // unsigned positive
361        ser_deser_ok(5u8, &[5]);
362        ser_deser_ok(5u16, &[5]);
363        ser_deser_ok(5u32, &[5]);
364        ser_deser_ok(5u64, &[5]);
365        ser_deser_ok(5usize, &[5]);
366        // signed positive
367        ser_deser_ok(5i8, &[5]);
368        ser_deser_ok(5i16, &[5]);
369        ser_deser_ok(5i32, &[5]);
370        ser_deser_ok(5i64, &[5]);
371        ser_deser_ok(5isize, &[5]);
372        // signed negative
373        ser_deser_ok(-5i8, &[251]);
374        ser_deser_ok(-5i16, &[251]);
375        ser_deser_ok(-5i32, &[251]);
376        ser_deser_ok(-5i64, &[251]);
377        ser_deser_ok(-5isize, &[251]);
378        // non zero usize
379        ser_deser_ok(NonZeroUsize::new(5).unwrap(), &[5]);
380    }
381
382    #[test]
383    fn test_top_compacted_bool() {
384        ser_deser_ok(true, &[1]);
385        ser_deser_ok(false, &[]);
386    }
387
388    #[test]
389    fn test_top_bytes_compacted() {
390        ser_deser_ok(Vec::<u8>::new(), &[]);
391        ser_deser_ok([1u8, 2u8, 3u8].to_vec(), &[1u8, 2u8, 3u8]);
392    }
393
394    #[test]
395    fn test_vec_i32_compacted() {
396        let v = [1i32, 2i32, 3i32].to_vec();
397        let expected: &[u8] = &[0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3];
398        ser_deser_ok(v, expected);
399    }
400
401    #[test]
402    fn test_array_16384() {
403        let arr = [7i32; 16384];
404        let mut expected_bytes = Vec::<u8>::with_capacity(16384 * 4);
405        for _ in 0..16384 {
406            expected_bytes.push(0);
407            expected_bytes.push(0);
408            expected_bytes.push(0);
409            expected_bytes.push(7);
410        }
411
412        // serialize
413        let serialized_bytes = check_top_encode(&arr);
414        assert_eq!(serialized_bytes, expected_bytes);
415
416        // deserialize
417        let deserialized = <[i32; 16384]>::top_decode(&serialized_bytes[..]).unwrap();
418        for i in 0..16384 {
419            assert_eq!(deserialized[i], 7i32);
420        }
421    }
422
423    #[test]
424    fn test_option_vec_i32() {
425        let some_v = Some([1i32, 2i32, 3i32].to_vec());
426        let expected: &[u8] = &[
427            /*opt*/ 1, /*size*/ 0, 0, 0, 3, /*data*/ 0, 0, 0, 1, 0, 0, 0, 2, 0, 0,
428            0, 3,
429        ];
430        ser_deser_ok(some_v, expected);
431
432        let none_v: Option<Vec<i32>> = None;
433        ser_deser_ok(none_v, &[]);
434    }
435
436    #[test]
437    fn test_struct() {
438        let test = Test {
439            int: 1,
440            seq: [5, 6].to_vec(),
441            another_byte: 7,
442        };
443        the_same(test);
444    }
445
446    #[test]
447    fn test_wrapped_array() {
448        let wa = WrappedArray([1, 2, 3, 4, 5]);
449        ser_deser_ok(wa, &[1, 2, 3, 4, 5]);
450
451        let mut v: Vec<WrappedArray> = Vec::new();
452        v.push(wa);
453        v.push(WrappedArray([6, 7, 8, 9, 0]));
454        ser_deser_ok(v, &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]);
455    }
456
457    #[test]
458    fn test_tuple() {
459        let t = (1i8, 2u32, 3i16);
460        let expected: &[u8] = &[1, 0, 0, 0, 2, 0, 3];
461        ser_deser_ok(t, expected);
462    }
463}