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}