numbat_codec/
nested_ser.rs

1use alloc::boxed::Box;
2use alloc::string::String;
3use alloc::vec::Vec;
4use core::num::NonZeroUsize;
5
6use crate::codec_err::EncodeError;
7use crate::nested_ser_output::NestedEncodeOutput;
8use crate::TypeInfo;
9
10/// Most types will be encoded without any possibility of error.
11/// The trait is used to provide these implementations.
12/// This is currently not a substitute for implementing a proper TopEncode.
13pub trait NestedEncodeNoErr: Sized {
14	fn dep_encode_no_err<O: NestedEncodeOutput>(&self, dest: &mut O);
15}
16
17/// Trait that allows zero-copy write of value-references to slices in LE format.
18///
19/// Implementations should override `using_top_encoded` for value types and `dep_encode` and `size_hint` for allocating types.
20/// Wrapper types should override all methods.
21pub trait NestedEncode: Sized {
22	// !INTERNAL USE ONLY!
23	// This const helps SCALE to optimize the encoding/decoding by doing fake specialization.
24	#[doc(hidden)]
25	const TYPE_INFO: TypeInfo = TypeInfo::Unknown;
26
27	/// NestedEncode to output, using the format of an object nested inside another structure.
28	/// Does not provide compact version.
29	fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError>;
30
31	/// Version of `top_decode` that exits quickly in case of error.
32	/// Its purpose is to create smaller implementations
33	/// in cases where the application is supposed to exit directly on decode error.
34	fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
35		&self,
36		dest: &mut O,
37		c: ExitCtx,
38		exit: fn(ExitCtx, EncodeError) -> !,
39	) {
40		match self.dep_encode(dest) {
41			Ok(v) => v,
42			Err(e) => exit(c, e),
43		}
44	}
45}
46
47macro_rules! dep_encode_from_no_err {
48	($type:ty, $type_info:expr) => {
49		impl NestedEncode for $type {
50			const TYPE_INFO: TypeInfo = $type_info;
51
52			#[inline]
53			fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
54				self.dep_encode_no_err(dest);
55				Ok(())
56			}
57
58			#[inline]
59			fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
60				&self,
61				dest: &mut O,
62				_: ExitCtx,
63				_: fn(ExitCtx, EncodeError) -> !,
64			) {
65				self.dep_encode_no_err(dest);
66			}
67		}
68	};
69}
70
71/// Convenience function for getting an object nested-encoded to a Vec<u8> directly.
72pub fn dep_encode_to_vec<T: NestedEncode>(obj: &T) -> Result<Vec<u8>, EncodeError> {
73	let mut bytes = Vec::<u8>::new();
74	obj.dep_encode(&mut bytes)?;
75	Ok(bytes)
76}
77
78/// Adds the concantenated encoded contents of a slice to an output buffer,
79/// without serializing the slice length.
80/// Byte slice is treated separately, via direct transmute.
81pub fn dep_encode_slice_contents<T: NestedEncode, O: NestedEncodeOutput>(
82	slice: &[T],
83	dest: &mut O,
84) -> Result<(), EncodeError> {
85	match T::TYPE_INFO {
86		TypeInfo::U8 => {
87			// cast &[T] to &[u8]
88			let slice: &[u8] =
89				unsafe { core::slice::from_raw_parts(slice.as_ptr() as *const u8, slice.len()) };
90			dest.write(slice);
91		},
92		_ => {
93			for x in slice {
94				x.dep_encode(dest)?;
95			}
96		},
97	}
98	Ok(())
99}
100
101pub fn dep_encode_slice_contents_or_exit<T, O, ExitCtx>(
102	slice: &[T],
103	dest: &mut O,
104	c: ExitCtx,
105	exit: fn(ExitCtx, EncodeError) -> !,
106) where
107	T: NestedEncode,
108	O: NestedEncodeOutput,
109	ExitCtx: Clone,
110{
111	match T::TYPE_INFO {
112		TypeInfo::U8 => {
113			// cast &[T] to &[u8]
114			let slice: &[u8] =
115				unsafe { core::slice::from_raw_parts(slice.as_ptr() as *const u8, slice.len()) };
116			dest.write(slice);
117		},
118		_ => {
119			for x in slice {
120				x.dep_encode_or_exit(dest, c.clone(), exit);
121			}
122		},
123	}
124}
125
126impl NestedEncodeNoErr for () {
127	fn dep_encode_no_err<O: NestedEncodeOutput>(&self, _: &mut O) {}
128}
129
130dep_encode_from_no_err! {(), TypeInfo::Unit}
131
132impl<T: NestedEncode> NestedEncode for &[T] {
133	fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
134		// push size
135		self.len().dep_encode(dest)?;
136		// actual data
137		dep_encode_slice_contents(self, dest)
138	}
139
140	fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
141		&self,
142		dest: &mut O,
143		c: ExitCtx,
144		exit: fn(ExitCtx, EncodeError) -> !,
145	) {
146		// push size
147		self.len().dep_encode_or_exit(dest, c.clone(), exit);
148		// actual data
149		dep_encode_slice_contents_or_exit(self, dest, c, exit);
150	}
151}
152
153impl<T: NestedEncode> NestedEncode for &T {
154	#[inline]
155	fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
156		(*self).dep_encode(dest)
157	}
158
159	fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
160		&self,
161		dest: &mut O,
162		c: ExitCtx,
163		exit: fn(ExitCtx, EncodeError) -> !,
164	) {
165		(*self).dep_encode_or_exit(dest, c, exit);
166	}
167}
168
169impl NestedEncode for &str {
170	fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
171		self.as_bytes().dep_encode(dest)
172	}
173
174	fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
175		&self,
176		dest: &mut O,
177		c: ExitCtx,
178		exit: fn(ExitCtx, EncodeError) -> !,
179	) {
180		self.as_bytes().dep_encode_or_exit(dest, c, exit);
181	}
182}
183
184impl<T: NestedEncode> NestedEncode for Vec<T> {
185	#[inline]
186	fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
187		self.as_slice().dep_encode(dest)
188	}
189
190	#[inline]
191	fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
192		&self,
193		dest: &mut O,
194		c: ExitCtx,
195		exit: fn(ExitCtx, EncodeError) -> !,
196	) {
197		self.as_slice().dep_encode_or_exit(dest, c, exit);
198	}
199}
200
201impl NestedEncode for String {
202	#[inline]
203	fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
204		self.as_bytes().dep_encode(dest)
205	}
206
207	#[inline]
208	fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
209		&self,
210		dest: &mut O,
211		c: ExitCtx,
212		exit: fn(ExitCtx, EncodeError) -> !,
213	) {
214		self.as_bytes().dep_encode_or_exit(dest, c, exit);
215	}
216}
217
218impl NestedEncode for Box<str> {
219	#[inline]
220	fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
221		self.as_ref().as_bytes().dep_encode(dest)
222	}
223
224	#[inline]
225	fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
226		&self,
227		dest: &mut O,
228		c: ExitCtx,
229		exit: fn(ExitCtx, EncodeError) -> !,
230	) {
231		self.as_ref().as_bytes().dep_encode_or_exit(dest, c, exit);
232	}
233}
234
235// The main unsigned types need to be reversed before serializing.
236macro_rules! encode_num_unsigned {
237	($num_type:ty, $size_in_bits:expr, $type_info:expr) => {
238		impl NestedEncodeNoErr for $num_type {
239			#[inline(never)]
240			fn dep_encode_no_err<O: NestedEncodeOutput>(&self, dest: &mut O) {
241				dest.write(&self.to_be_bytes()[..]);
242			}
243		}
244
245		dep_encode_from_no_err! {$num_type, $type_info}
246	};
247}
248
249encode_num_unsigned! {u64, 64, TypeInfo::U64}
250encode_num_unsigned! {u32, 32, TypeInfo::U32}
251encode_num_unsigned! {u16, 16, TypeInfo::U16}
252
253// No reversing needed for u8, because it is a single byte.
254impl NestedEncodeNoErr for u8 {
255	fn dep_encode_no_err<O: NestedEncodeOutput>(&self, dest: &mut O) {
256		dest.push_byte(*self as u8);
257	}
258}
259
260dep_encode_from_no_err! {u8, TypeInfo::U8}
261
262// Derive the implementation of the other types by casting.
263macro_rules! encode_num_mimic {
264	($num_type:ty, $mimic_type:ident, $type_info:expr) => {
265		impl NestedEncodeNoErr for $num_type {
266			#[inline]
267			fn dep_encode_no_err<O: NestedEncodeOutput>(&self, dest: &mut O) {
268				(*self as $mimic_type).dep_encode_no_err(dest)
269			}
270		}
271
272		dep_encode_from_no_err! {$num_type, $type_info}
273	};
274}
275
276encode_num_mimic! {usize, u32, TypeInfo::USIZE}
277encode_num_mimic! {i64, u64, TypeInfo::I64}
278encode_num_mimic! {i32, u32, TypeInfo::I32}
279encode_num_mimic! {isize, u32, TypeInfo::ISIZE}
280encode_num_mimic! {i16, u16, TypeInfo::I16}
281encode_num_mimic! {i8, u8, TypeInfo::I8}
282encode_num_mimic! {bool, u8, TypeInfo::Bool}
283
284impl<T: NestedEncode> NestedEncode for Option<T> {
285	fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
286		match self {
287			Some(v) => {
288				dest.push_byte(1u8);
289				v.dep_encode(dest)
290			},
291			None => {
292				dest.push_byte(0u8);
293				Ok(())
294			},
295		}
296	}
297
298	fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
299		&self,
300		dest: &mut O,
301		c: ExitCtx,
302		exit: fn(ExitCtx, EncodeError) -> !,
303	) {
304		match self {
305			Some(v) => {
306				dest.push_byte(1u8);
307				v.dep_encode_or_exit(dest, c, exit);
308			},
309			None => {
310				dest.push_byte(0u8);
311			},
312		}
313	}
314}
315
316impl<T: NestedEncode> NestedEncode for Box<T> {
317	#[inline(never)]
318	fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
319		self.as_ref().dep_encode(dest)
320	}
321
322	fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
323		&self,
324		dest: &mut O,
325		c: ExitCtx,
326		exit: fn(ExitCtx, EncodeError) -> !,
327	) {
328		self.as_ref().dep_encode_or_exit(dest, c, exit);
329	}
330}
331
332impl<T: NestedEncode> NestedEncode for Box<[T]> {
333	fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
334		self.as_ref().dep_encode(dest)
335	}
336
337	fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
338		&self,
339		dest: &mut O,
340		c: ExitCtx,
341		exit: fn(ExitCtx, EncodeError) -> !,
342	) {
343		self.as_ref().dep_encode_or_exit(dest, c, exit);
344	}
345}
346
347macro_rules! tuple_impls {
348    ($(($($n:tt $name:ident)+))+) => {
349        $(
350            impl<$($name),+> NestedEncode for ($($name,)+)
351            where
352                $($name: NestedEncode,)+
353            {
354				fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
355					$(
356                        self.$n.dep_encode(dest)?;
357                    )+
358					Ok(())
359				}
360
361				fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(&self, dest: &mut O, c: ExitCtx, exit: fn(ExitCtx, EncodeError) -> !) {
362					$(
363                        self.$n.dep_encode_or_exit(dest, c.clone(), exit);
364                    )+
365				}
366            }
367        )+
368    }
369}
370
371tuple_impls! {
372	(0 T0)
373	(0 T0 1 T1)
374	(0 T0 1 T1 2 T2)
375	(0 T0 1 T1 2 T2 3 T3)
376	(0 T0 1 T1 2 T2 3 T3 4 T4)
377	(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5)
378	(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6)
379	(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7)
380	(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8)
381	(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9)
382	(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10)
383	(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11)
384	(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)
385	(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)
386	(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)
387	(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)
388}
389
390impl NestedEncode for NonZeroUsize {
391	#[inline]
392	fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
393		self.get().dep_encode(dest)
394	}
395
396	#[inline]
397	fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
398		&self,
399		dest: &mut O,
400		c: ExitCtx,
401		exit: fn(ExitCtx, EncodeError) -> !,
402	) {
403		self.get().dep_encode_or_exit(dest, c, exit);
404	}
405}
406
407////////////////////////////////////////////////////////////////////////////////
408
409#[cfg(test)]
410mod tests {
411	use super::super::test_struct::*;
412	use super::*;
413	use crate::test_util::check_dep_encode;
414	use core::fmt::Debug;
415
416	fn ser_ok<V>(element: V, expected_bytes: &[u8])
417	where
418		V: NestedEncode + PartialEq + Debug + 'static,
419	{
420		let bytes = check_dep_encode(&element);
421		assert_eq!(bytes.as_slice(), expected_bytes);
422	}
423
424	#[test]
425	fn test_dep_encode_numbers() {
426		// unsigned positive
427		ser_ok(5u8, &[5]);
428		ser_ok(5u16, &[0, 5]);
429		ser_ok(5u32, &[0, 0, 0, 5]);
430		ser_ok(5usize, &[0, 0, 0, 5]);
431		ser_ok(5u64, &[0, 0, 0, 0, 0, 0, 0, 5]);
432		// signed positive
433		ser_ok(5i8, &[5]);
434		ser_ok(5i16, &[0, 5]);
435		ser_ok(5i32, &[0, 0, 0, 5]);
436		ser_ok(5isize, &[0, 0, 0, 5]);
437		ser_ok(5i64, &[0, 0, 0, 0, 0, 0, 0, 5]);
438		// signed negative
439		ser_ok(-5i8, &[251]);
440		ser_ok(-5i16, &[255, 251]);
441		ser_ok(-5i32, &[255, 255, 255, 251]);
442		ser_ok(-5isize, &[255, 255, 255, 251]);
443		ser_ok(-5i64, &[255, 255, 255, 255, 255, 255, 255, 251]);
444		// non zero usize
445		ser_ok(NonZeroUsize::new(5).unwrap(), &[0, 0, 0, 5]);
446	}
447
448	#[test]
449	fn test_dep_encode_bool() {
450		ser_ok(true, &[1]);
451		ser_ok(false, &[0]);
452	}
453
454	#[test]
455	fn test_dep_encode_empty_bytes() {
456		let empty_byte_slice: &[u8] = &[];
457		ser_ok(empty_byte_slice, &[0, 0, 0, 0]);
458	}
459
460	#[test]
461	fn test_dep_encode_bytes() {
462		ser_ok(&[1u8, 2u8, 3u8][..], &[0, 0, 0, 3, 1u8, 2u8, 3u8]);
463	}
464
465	#[test]
466	fn test_dep_encode_vec_u8() {
467		let some_vec = [1u8, 2u8, 3u8].to_vec();
468		ser_ok(some_vec, &[0, 0, 0, 3, 1u8, 2u8, 3u8]);
469	}
470
471	#[test]
472	#[rustfmt::skip]
473	fn test_dep_encode_str() {
474		let s = "abc";
475		ser_ok(s, &[0, 0, 0, 3, b'a', b'b', b'c']);
476		ser_ok(String::from(s), &[0, 0, 0, 3, b'a', b'b', b'c']);
477		ser_ok(String::from(s).into_boxed_str(), &[0, 0, 0, 3, b'a', b'b', b'c']);
478	}
479
480	#[test]
481	fn test_dep_encode_vec_i32() {
482		let some_vec = [1i32, 2i32, 3i32].to_vec();
483		let expected: &[u8] = &[0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3];
484		ser_ok(some_vec, expected);
485	}
486
487	#[test]
488	fn test_struct() {
489		let test = Test {
490			int: 1,
491			seq: [5, 6].to_vec(),
492			another_byte: 7,
493		};
494
495		ser_ok(test, &[0, 1, 0, 0, 0, 2, 5, 6, 7]);
496	}
497
498	#[test]
499	fn test_tuple() {
500		ser_ok((7u32, -2i16), &[0, 0, 0, 7, 255, 254]);
501	}
502
503	#[test]
504	fn test_unit() {
505		ser_ok((), &[]);
506	}
507
508	#[test]
509	fn test_enum() {
510		let u = E::Unit;
511		let expected: &[u8] = &[/*variant index*/ 0, 0, 0, 0];
512		ser_ok(u, expected);
513
514		let n = E::Newtype(1);
515		let expected: &[u8] = &[/*variant index*/ 0, 0, 0, 1, /*data*/ 0, 0, 0, 1];
516		ser_ok(n, expected);
517
518		let t = E::Tuple(1, 2);
519		let expected: &[u8] = &[
520			/*variant index*/ 0, 0, 0, 2, /*(*/ 0, 0, 0, 1, /*,*/ 0, 0, 0,
521			2, /*)*/
522		];
523		ser_ok(t, expected);
524
525		let s = E::Struct { a: 1 };
526		let expected: &[u8] = &[/*variant index*/ 0, 0, 0, 3, /*data*/ 0, 0, 0, 1];
527		ser_ok(s, expected);
528	}
529}