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
390macro_rules! array_impls {
391    ($($n: tt,)+) => {
392        $(
393            impl<T: NestedEncode> NestedEncode for [T; $n] {
394				#[inline]
395				fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
396					dep_encode_slice_contents(&self[..], dest)
397				}
398
399				#[inline]
400				fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(&self, dest: &mut O, c: ExitCtx, exit: fn(ExitCtx, EncodeError) -> !) {
401					dep_encode_slice_contents_or_exit(&self[..], dest, c, exit);
402				}
403			}
404        )+
405    }
406}
407
408#[rustfmt::skip]
409array_impls!(
410	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
411	17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
412	32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
413	52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
414	72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
415	92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
416	109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
417	125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140,
418	141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156,
419	157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172,
420	173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188,
421	189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204,
422	205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220,
423	221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236,
424	237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252,
425	253, 254, 255, 256, 384, 512, 768, 1024, 2048, 4096, 8192, 16384, 32768,
426);
427
428impl NestedEncode for NonZeroUsize {
429	#[inline]
430	fn dep_encode<O: NestedEncodeOutput>(&self, dest: &mut O) -> Result<(), EncodeError> {
431		self.get().dep_encode(dest)
432	}
433
434	#[inline]
435	fn dep_encode_or_exit<O: NestedEncodeOutput, ExitCtx: Clone>(
436		&self,
437		dest: &mut O,
438		c: ExitCtx,
439		exit: fn(ExitCtx, EncodeError) -> !,
440	) {
441		self.get().dep_encode_or_exit(dest, c, exit);
442	}
443}
444
445////////////////////////////////////////////////////////////////////////////////
446
447#[cfg(test)]
448mod tests {
449	use super::super::test_struct::*;
450	use super::*;
451	use crate::test_util::check_dep_encode;
452	use core::fmt::Debug;
453
454	fn ser_ok<V>(element: V, expected_bytes: &[u8])
455	where
456		V: NestedEncode + PartialEq + Debug + 'static,
457	{
458		let bytes = check_dep_encode(&element);
459		assert_eq!(bytes.as_slice(), expected_bytes);
460	}
461
462	#[test]
463	fn test_dep_encode_numbers() {
464		// unsigned positive
465		ser_ok(5u8, &[5]);
466		ser_ok(5u16, &[0, 5]);
467		ser_ok(5u32, &[0, 0, 0, 5]);
468		ser_ok(5usize, &[0, 0, 0, 5]);
469		ser_ok(5u64, &[0, 0, 0, 0, 0, 0, 0, 5]);
470		// signed positive
471		ser_ok(5i8, &[5]);
472		ser_ok(5i16, &[0, 5]);
473		ser_ok(5i32, &[0, 0, 0, 5]);
474		ser_ok(5isize, &[0, 0, 0, 5]);
475		ser_ok(5i64, &[0, 0, 0, 0, 0, 0, 0, 5]);
476		// signed negative
477		ser_ok(-5i8, &[251]);
478		ser_ok(-5i16, &[255, 251]);
479		ser_ok(-5i32, &[255, 255, 255, 251]);
480		ser_ok(-5isize, &[255, 255, 255, 251]);
481		ser_ok(-5i64, &[255, 255, 255, 255, 255, 255, 255, 251]);
482		// non zero usize
483		ser_ok(NonZeroUsize::new(5).unwrap(), &[0, 0, 0, 5]);
484	}
485
486	#[test]
487	fn test_dep_encode_bool() {
488		ser_ok(true, &[1]);
489		ser_ok(false, &[0]);
490	}
491
492	#[test]
493	fn test_dep_encode_empty_bytes() {
494		let empty_byte_slice: &[u8] = &[];
495		ser_ok(empty_byte_slice, &[0, 0, 0, 0]);
496	}
497
498	#[test]
499	fn test_dep_encode_bytes() {
500		ser_ok(&[1u8, 2u8, 3u8][..], &[0, 0, 0, 3, 1u8, 2u8, 3u8]);
501	}
502
503	#[test]
504	fn test_dep_encode_vec_u8() {
505		let some_vec = [1u8, 2u8, 3u8].to_vec();
506		ser_ok(some_vec, &[0, 0, 0, 3, 1u8, 2u8, 3u8]);
507	}
508
509	#[test]
510	#[rustfmt::skip]
511	fn test_dep_encode_str() {
512		let s = "abc";
513		ser_ok(s, &[0, 0, 0, 3, b'a', b'b', b'c']);
514		ser_ok(String::from(s), &[0, 0, 0, 3, b'a', b'b', b'c']);
515		ser_ok(String::from(s).into_boxed_str(), &[0, 0, 0, 3, b'a', b'b', b'c']);
516	}
517
518	#[test]
519	fn test_dep_encode_vec_i32() {
520		let some_vec = [1i32, 2i32, 3i32].to_vec();
521		let expected: &[u8] = &[0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3];
522		ser_ok(some_vec, expected);
523	}
524
525	#[test]
526	fn test_struct() {
527		let test = Test {
528			int: 1,
529			seq: [5, 6].to_vec(),
530			another_byte: 7,
531		};
532
533		ser_ok(test, &[0, 1, 0, 0, 0, 2, 5, 6, 7]);
534	}
535
536	#[test]
537	fn test_tuple() {
538		ser_ok((7u32, -2i16), &[0, 0, 0, 7, 255, 254]);
539	}
540
541	#[test]
542	fn test_unit() {
543		ser_ok((), &[]);
544	}
545
546	#[test]
547	fn test_enum() {
548		let u = E::Unit;
549		let expected: &[u8] = &[/*variant index*/ 0, 0, 0, 0];
550		ser_ok(u, expected);
551
552		let n = E::Newtype(1);
553		let expected: &[u8] = &[/*variant index*/ 0, 0, 0, 1, /*data*/ 0, 0, 0, 1];
554		ser_ok(n, expected);
555
556		let t = E::Tuple(1, 2);
557		let expected: &[u8] = &[
558			/*variant index*/ 0, 0, 0, 2, /*(*/ 0, 0, 0, 1, /*,*/ 0, 0, 0,
559			2, /*)*/
560		];
561		ser_ok(t, expected);
562
563		let s = E::Struct { a: 1 };
564		let expected: &[u8] = &[/*variant index*/ 0, 0, 0, 3, /*data*/ 0, 0, 0, 1];
565		ser_ok(s, expected);
566	}
567}