numbat_codec/
nested_de.rs

1use alloc::boxed::Box;
2use alloc::string::String;
3use alloc::vec::Vec;
4use arrayvec::ArrayVec;
5use core::num::NonZeroUsize;
6
7use crate::codec_err::DecodeError;
8use crate::nested_de_input::NestedDecodeInput;
9use crate::num_conv::bytes_to_number;
10use crate::TypeInfo;
11
12/// Trait that allows zero-copy read of value-references from slices in LE format.
13pub trait NestedDecode: Sized {
14	// !INTERNAL USE ONLY!
15	// This const helps numbat-wasm to optimize the encoding/decoding by doing fake specialization.
16	#[doc(hidden)]
17	const TYPE_INFO: TypeInfo = TypeInfo::Unknown;
18
19	/// Attempt to deserialise the value from input,
20	/// using the format of an object nested inside another structure.
21	/// In case of success returns the deserialized value and the number of bytes consumed during the operation.
22	fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError>;
23
24	/// Version of `top_decode` that exits quickly in case of error.
25	/// Its purpose is to create smaller implementations
26	/// in cases where the application is supposed to exit directly on decode error.
27	fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
28		input: &mut I,
29		c: ExitCtx,
30		exit: fn(ExitCtx, DecodeError) -> !,
31	) -> Self {
32		match Self::dep_decode(input) {
33			Ok(v) => v,
34			Err(e) => exit(c, e),
35		}
36	}
37}
38
39/// Convenience method, to avoid having to specify type when calling `dep_decode`.
40/// Especially useful in the macros.
41/// Also checks that the entire slice was used.
42/// The input doesn't need to be mutable because we are not changing the underlying data.
43pub fn dep_decode_from_byte_slice<D: NestedDecode>(input: &[u8]) -> Result<D, DecodeError> {
44	let mut_slice = &mut &*input;
45	let result = D::dep_decode(mut_slice);
46	if !mut_slice.is_empty() {
47		return Err(DecodeError::INPUT_TOO_LONG);
48	}
49	result
50}
51
52pub fn dep_decode_from_byte_slice_or_exit<D: NestedDecode, ExitCtx: Clone>(
53	input: &[u8],
54	c: ExitCtx,
55	exit: fn(ExitCtx, DecodeError) -> !,
56) -> D {
57	let mut_slice = &mut &*input;
58	let result = D::dep_decode_or_exit(mut_slice, c.clone(), exit);
59	if !mut_slice.is_empty() {
60		exit(c, DecodeError::INPUT_TOO_LONG);
61	}
62	result
63}
64
65impl NestedDecode for () {
66	const TYPE_INFO: TypeInfo = TypeInfo::Unit;
67
68	fn dep_decode<I: NestedDecodeInput>(_: &mut I) -> Result<(), DecodeError> {
69		Ok(())
70	}
71
72	fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
73		_: &mut I,
74		_: ExitCtx,
75		_: fn(ExitCtx, DecodeError) -> !,
76	) -> Self {
77	}
78}
79
80impl NestedDecode for u8 {
81	const TYPE_INFO: TypeInfo = TypeInfo::U8;
82
83	fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
84		input.read_byte()
85	}
86
87	fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
88		input: &mut I,
89		c: ExitCtx,
90		exit: fn(ExitCtx, DecodeError) -> !,
91	) -> Self {
92		input.read_byte_or_exit(c, exit)
93	}
94}
95
96impl<T: NestedDecode> NestedDecode for Vec<T> {
97	fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
98		let size = usize::dep_decode(input)?;
99		match T::TYPE_INFO {
100			TypeInfo::U8 => {
101				let bytes = input.read_slice(size)?;
102				let bytes_copy = bytes.to_vec(); // copy is needed because result might outlive input
103				let cast_vec: Vec<T> = unsafe { core::mem::transmute(bytes_copy) };
104				Ok(cast_vec)
105			},
106			_ => {
107				let mut result: Vec<T> = Vec::with_capacity(size);
108				for _ in 0..size {
109					result.push(T::dep_decode(input)?);
110				}
111				Ok(result)
112			},
113		}
114	}
115
116	fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
117		input: &mut I,
118		c: ExitCtx,
119		exit: fn(ExitCtx, DecodeError) -> !,
120	) -> Self {
121		let size = usize::dep_decode_or_exit(input, c.clone(), exit);
122		match T::TYPE_INFO {
123			TypeInfo::U8 => {
124				let bytes = input.read_slice_or_exit(size, c, exit);
125				let bytes_copy = bytes.to_vec(); // copy is needed because result might outlive input
126				let cast_vec: Vec<T> = unsafe { core::mem::transmute(bytes_copy) };
127				cast_vec
128			},
129			_ => {
130				let mut result: Vec<T> = Vec::with_capacity(size);
131				for _ in 0..size {
132					result.push(T::dep_decode_or_exit(input, c.clone(), exit));
133				}
134				result
135			},
136		}
137	}
138}
139
140impl NestedDecode for String {
141	fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
142		let raw = Vec::<u8>::dep_decode(input)?;
143		match String::from_utf8(raw) {
144			Ok(s) => Ok(s),
145			Err(_) => Err(DecodeError::UTF8_DECODE_ERROR),
146		}
147	}
148
149	fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
150		input: &mut I,
151		c: ExitCtx,
152		exit: fn(ExitCtx, DecodeError) -> !,
153	) -> Self {
154		let raw = Vec::<u8>::dep_decode_or_exit(input, c.clone(), exit);
155		match String::from_utf8(raw) {
156			Ok(s) => s,
157			Err(_) => exit(c, DecodeError::UTF8_DECODE_ERROR),
158		}
159	}
160}
161
162impl NestedDecode for Box<str> {
163	#[inline]
164	fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
165		Ok(String::dep_decode(input)?.into_boxed_str())
166	}
167
168	#[inline]
169	fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
170		input: &mut I,
171		c: ExitCtx,
172		exit: fn(ExitCtx, DecodeError) -> !,
173	) -> Self {
174		String::dep_decode_or_exit(input, c, exit).into_boxed_str()
175	}
176}
177
178macro_rules! decode_num_unsigned {
179	($ty:ty, $num_bytes:expr, $type_info:expr) => {
180		impl NestedDecode for $ty {
181			const TYPE_INFO: TypeInfo = $type_info;
182
183			fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
184				let bytes = input.read_slice($num_bytes)?;
185				let num = bytes_to_number(bytes, false) as $ty;
186				Ok(num)
187			}
188
189			fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
190				input: &mut I,
191				c: ExitCtx,
192				exit: fn(ExitCtx, DecodeError) -> !,
193			) -> Self {
194				let bytes = input.read_slice_or_exit($num_bytes, c, exit);
195				let num = bytes_to_number(bytes, false) as $ty;
196				num
197			}
198		}
199	};
200}
201
202decode_num_unsigned!(u16, 2, TypeInfo::U16);
203decode_num_unsigned!(u32, 4, TypeInfo::U32);
204decode_num_unsigned!(usize, 4, TypeInfo::USIZE);
205decode_num_unsigned!(u64, 8, TypeInfo::U64);
206
207macro_rules! decode_num_signed {
208	($ty:ty, $num_bytes:expr, $type_info:expr) => {
209		impl NestedDecode for $ty {
210			const TYPE_INFO: TypeInfo = $type_info;
211
212			fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
213				let bytes = input.read_slice($num_bytes)?;
214				let num = bytes_to_number(bytes, true) as $ty;
215				Ok(num)
216			}
217
218			fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
219				input: &mut I,
220				c: ExitCtx,
221				exit: fn(ExitCtx, DecodeError) -> !,
222			) -> Self {
223				let bytes = input.read_slice_or_exit($num_bytes, c, exit);
224				let num = bytes_to_number(bytes, true) as $ty;
225				num
226			}
227		}
228	};
229}
230
231decode_num_signed!(i8, 1, TypeInfo::I8);
232decode_num_signed!(i16, 2, TypeInfo::I16);
233decode_num_signed!(i32, 4, TypeInfo::I32);
234decode_num_signed!(isize, 4, TypeInfo::ISIZE);
235decode_num_signed!(i64, 8, TypeInfo::I64);
236
237impl NestedDecode for bool {
238	const TYPE_INFO: TypeInfo = TypeInfo::Bool;
239
240	fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
241		match input.read_byte()? {
242			0 => Ok(false),
243			1 => Ok(true),
244			_ => Err(DecodeError::INVALID_VALUE),
245		}
246	}
247
248	fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
249		input: &mut I,
250		c: ExitCtx,
251		exit: fn(ExitCtx, DecodeError) -> !,
252	) -> Self {
253		match input.read_byte_or_exit(c.clone(), exit) {
254			0 => false,
255			1 => true,
256			_ => exit(c, DecodeError::INVALID_VALUE),
257		}
258	}
259}
260
261impl<T: NestedDecode> NestedDecode for Option<T> {
262	fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
263		match input.read_byte()? {
264			0 => Ok(None),
265			1 => Ok(Some(T::dep_decode(input)?)),
266			_ => Err(DecodeError::INVALID_VALUE),
267		}
268	}
269
270	fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
271		input: &mut I,
272		c: ExitCtx,
273		exit: fn(ExitCtx, DecodeError) -> !,
274	) -> Self {
275		match input.read_byte_or_exit(c.clone(), exit) {
276			0 => None,
277			1 => Some(T::dep_decode_or_exit(input, c, exit)),
278			_ => exit(c, DecodeError::INVALID_VALUE),
279		}
280	}
281}
282
283impl<T: NestedDecode> NestedDecode for Box<T> {
284	fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
285		Ok(Box::new(T::dep_decode(input)?))
286	}
287
288	fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
289		input: &mut I,
290		c: ExitCtx,
291		exit: fn(ExitCtx, DecodeError) -> !,
292	) -> Self {
293		Box::new(T::dep_decode_or_exit(input, c, exit))
294	}
295}
296
297macro_rules! tuple_impls {
298    ($($len:expr => ($($n:tt $name:ident)+))+) => {
299        $(
300            impl<$($name),+> NestedDecode for ($($name,)+)
301            where
302                $($name: NestedDecode,)+
303            {
304                fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
305                    Ok((
306                        $(
307                            $name::dep_decode(input)?,
308                        )+
309                    ))
310                }
311
312                fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(input: &mut I, c: ExitCtx, exit: fn(ExitCtx, DecodeError) -> !) -> Self {
313                    (
314                        $(
315                            $name::dep_decode_or_exit(input, c.clone(), exit),
316                        )+
317                    )
318                }
319            }
320        )+
321    }
322}
323
324tuple_impls! {
325	1 => (0 T0)
326	2 => (0 T0 1 T1)
327	3 => (0 T0 1 T1 2 T2)
328	4 => (0 T0 1 T1 2 T2 3 T3)
329	5 => (0 T0 1 T1 2 T2 3 T3 4 T4)
330	6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5)
331	7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6)
332	8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7)
333	9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8)
334	10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9)
335	11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10)
336	12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11)
337	13 => (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)
338	14 => (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)
339	15 => (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)
340	16 => (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)
341}
342
343macro_rules! array_impls {
344    ($($n: tt,)+) => {
345        $(
346            impl<T: NestedDecode> NestedDecode for [T; $n] {
347                fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
348					let mut r = ArrayVec::new();
349					for _ in 0..$n {
350						r.push(T::dep_decode(input)?);
351					}
352					let i = r.into_inner();
353
354					match i {
355						Ok(a) => Ok(a),
356						Err(_) => Err(DecodeError::ARRAY_DECODE_ERROR),
357					}
358                }
359
360                fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(input: &mut I, c: ExitCtx, exit: fn(ExitCtx, DecodeError) -> !) -> Self {
361                    let mut r = ArrayVec::new();
362					for _ in 0..$n {
363						r.push(T::dep_decode_or_exit(input, c.clone(), exit));
364					}
365					let i = r.into_inner();
366
367					match i {
368						Ok(a) => a,
369						Err(_) => exit(c, DecodeError::ARRAY_DECODE_ERROR),
370					}
371                }
372            }
373        )+
374    }
375}
376
377#[rustfmt::skip]
378array_impls!(
379	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
380	17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
381	32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
382	52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
383	72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
384	92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
385	109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
386	125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140,
387	141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156,
388	157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172,
389	173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188,
390	189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204,
391	205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220,
392	221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236,
393	237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252,
394	253, 254, 255, 256, 384, 512, 768, 1024, 2048, 4096, 8192, 16384, 32768,
395);
396
397impl NestedDecode for NonZeroUsize {
398	fn dep_decode<I: NestedDecodeInput>(input: &mut I) -> Result<Self, DecodeError> {
399		if let Some(nz) = NonZeroUsize::new(usize::dep_decode(input)?) {
400			Ok(nz)
401		} else {
402			Err(DecodeError::INVALID_VALUE)
403		}
404	}
405
406	fn dep_decode_or_exit<I: NestedDecodeInput, ExitCtx: Clone>(
407		input: &mut I,
408		c: ExitCtx,
409		exit: fn(ExitCtx, DecodeError) -> !,
410	) -> Self {
411		if let Some(nz) = NonZeroUsize::new(usize::dep_decode_or_exit(input, c.clone(), exit)) {
412			nz
413		} else {
414			exit(c, DecodeError::INVALID_VALUE)
415		}
416	}
417}
418
419////////////////////////////////////////////////////////////////////////////////
420
421#[cfg(test)]
422mod tests {
423	use super::super::test_struct::*;
424	use super::*;
425	use crate::test_util::check_dep_decode;
426	use core::fmt::Debug;
427
428	fn deser_ok<V>(element: V, bytes: &[u8])
429	where
430		V: NestedDecode + PartialEq + Debug + 'static,
431	{
432		let input = bytes.to_vec();
433		let deserialized: V = check_dep_decode::<V>(&input[..]);
434		assert_eq!(deserialized, element);
435	}
436
437	#[test]
438	fn test_dep_decode_numbers() {
439		// unsigned positive
440		deser_ok(5u8, &[5]);
441		deser_ok(5u16, &[0, 5]);
442		deser_ok(5u32, &[0, 0, 0, 5]);
443		deser_ok(5usize, &[0, 0, 0, 5]);
444		deser_ok(5u64, &[0, 0, 0, 0, 0, 0, 0, 5]);
445		// signed positive
446		deser_ok(5i8, &[5]);
447		deser_ok(5i16, &[0, 5]);
448		deser_ok(5i32, &[0, 0, 0, 5]);
449		deser_ok(5isize, &[0, 0, 0, 5]);
450		deser_ok(5i64, &[0, 0, 0, 0, 0, 0, 0, 5]);
451		// signed negative
452		deser_ok(-5i8, &[251]);
453		deser_ok(-5i16, &[255, 251]);
454		deser_ok(-5i32, &[255, 255, 255, 251]);
455		deser_ok(-5isize, &[255, 255, 255, 251]);
456		deser_ok(-5i64, &[255, 255, 255, 255, 255, 255, 255, 251]);
457		// non zero usize
458		deser_ok(NonZeroUsize::new(5).unwrap(), &[0, 0, 0, 5]);
459	}
460
461	#[test]
462	#[rustfmt::skip]
463	fn test_dep_decode_str() {
464		deser_ok(String::from("abc"), &[0, 0, 0, 3, b'a', b'b', b'c']);
465		deser_ok(String::from("abc").into_boxed_str(), &[0, 0, 0, 3, b'a', b'b', b'c']);
466	}
467
468	#[test]
469	fn test_struct() {
470		let test = Test {
471			int: 1,
472			seq: [5, 6].to_vec(),
473			another_byte: 7,
474		};
475		deser_ok(test, &[0, 1, 0, 0, 0, 2, 5, 6, 7]);
476	}
477
478	#[test]
479	fn test_enum() {
480		let u = E::Unit;
481		let expected: &[u8] = &[/*variant index*/ 0, 0, 0, 0];
482		deser_ok(u, expected);
483
484		let n = E::Newtype(1);
485		let expected: &[u8] = &[/*variant index*/ 0, 0, 0, 1, /*data*/ 0, 0, 0, 1];
486		deser_ok(n, expected);
487
488		let t = E::Tuple(1, 2);
489		let expected: &[u8] = &[
490			/*variant index*/ 0, 0, 0, 2, /*(*/ 0, 0, 0, 1, /*,*/ 0, 0, 0,
491			2, /*)*/
492		];
493		deser_ok(t, expected);
494
495		let s = E::Struct { a: 1 };
496		let expected: &[u8] = &[/*variant index*/ 0, 0, 0, 3, /*data*/ 0, 0, 0, 1];
497		deser_ok(s, expected);
498	}
499}