numbat_codec/
nested_de.rs

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