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