numbat_codec/
top_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::{dep_encode_slice_contents, NestedEncode};
8use crate::nested_ser_output::NestedEncodeOutput;
9use crate::top_ser_output::TopEncodeOutput;
10use crate::TypeInfo;
11
12/// Most types will be encoded without any possibility of error.
13/// The trait is used to provide these implementations.
14/// This is currently not a substitute for implementing a proper TopEncode.
15pub trait TopEncodeNoErr: Sized {
16	fn top_encode_no_err<O: TopEncodeOutput>(&self, output: O);
17}
18
19pub trait TopEncode: Sized {
20	// !INTERNAL USE ONLY!
21	#[doc(hidden)]
22	const TYPE_INFO: TypeInfo = TypeInfo::Unknown;
23
24	/// Attempt to serialize the value to ouput.
25	fn top_encode<O: TopEncodeOutput>(&self, output: O) -> Result<(), EncodeError>;
26
27	/// Version of `top_decode` that exits quickly in case of error.
28	/// Its purpose is to create smaller bytecode implementations
29	/// in cases where the application is supposed to exit directly on decode error.
30	fn top_encode_or_exit<O: TopEncodeOutput, ExitCtx: Clone>(
31		&self,
32		output: O,
33		c: ExitCtx,
34		exit: fn(ExitCtx, EncodeError) -> !,
35	) {
36		match self.top_encode(output) {
37			Ok(v) => v,
38			Err(e) => exit(c, e),
39		}
40	}
41}
42
43pub fn top_encode_from_nested<T, O>(obj: &T, output: O) -> Result<(), EncodeError>
44where
45	O: TopEncodeOutput,
46	T: NestedEncode,
47{
48	let mut bytes = Vec::<u8>::new();
49	obj.dep_encode(&mut bytes)?;
50	output.set_slice_u8(&bytes[..]);
51	Ok(())
52}
53
54pub fn top_encode_from_nested_or_exit<T, O, ExitCtx>(
55	obj: &T,
56	output: O,
57	c: ExitCtx,
58	exit: fn(ExitCtx, EncodeError) -> !,
59) where
60	O: TopEncodeOutput,
61	T: NestedEncode,
62	ExitCtx: Clone,
63{
64	let mut bytes = Vec::<u8>::new();
65	obj.dep_encode_or_exit(&mut bytes, c, exit);
66	output.set_slice_u8(&bytes[..]);
67}
68
69macro_rules! top_encode_from_no_err {
70	($type:ty, $type_info:expr) => {
71		impl TopEncode for $type {
72			const TYPE_INFO: TypeInfo = $type_info;
73
74			#[inline]
75			fn top_encode<O: TopEncodeOutput>(&self, output: O) -> Result<(), EncodeError> {
76				self.top_encode_no_err(output);
77				Ok(())
78			}
79
80			#[inline]
81			fn top_encode_or_exit<O: TopEncodeOutput, ExitCtx: Clone>(
82				&self,
83				output: O,
84				_: ExitCtx,
85				_: fn(ExitCtx, EncodeError) -> !,
86			) {
87				self.top_encode_no_err(output);
88			}
89		}
90	};
91}
92
93pub fn top_encode_to_vec<T: TopEncode>(obj: &T) -> Result<Vec<u8>, EncodeError> {
94	let mut bytes = Vec::<u8>::new();
95	obj.top_encode(&mut bytes)?;
96	Ok(bytes)
97}
98
99impl TopEncodeNoErr for () {
100	#[inline]
101	fn top_encode_no_err<O: TopEncodeOutput>(&self, output: O) {
102		output.set_unit();
103	}
104}
105
106top_encode_from_no_err! {(), TypeInfo::Unit}
107
108impl<T: NestedEncode> TopEncode for &[T] {
109	fn top_encode<O: TopEncodeOutput>(&self, output: O) -> Result<(), EncodeError> {
110		match T::TYPE_INFO {
111			TypeInfo::U8 => {
112				// transmute to &[u8]
113				// save directly, without passing through the buffer
114				let slice: &[u8] =
115					unsafe { core::slice::from_raw_parts(self.as_ptr() as *const u8, self.len()) };
116				output.set_slice_u8(slice);
117			},
118			_ => {
119				// only using `dep_encode_slice_contents` for non-u8,
120				// because it always appends to the buffer,
121				// which is not necessary above
122				let mut buffer = Vec::<u8>::new();
123				dep_encode_slice_contents(self, &mut buffer)?;
124				output.set_slice_u8(&buffer[..]);
125			},
126		}
127		Ok(())
128	}
129
130	fn top_encode_or_exit<O: TopEncodeOutput, ExitCtx: Clone>(
131		&self,
132		output: O,
133		c: ExitCtx,
134		exit: fn(ExitCtx, EncodeError) -> !,
135	) {
136		match T::TYPE_INFO {
137			TypeInfo::U8 => {
138				// transmute to &[u8]
139				// save directly, without passing through the buffer
140				let slice: &[u8] =
141					unsafe { core::slice::from_raw_parts(self.as_ptr() as *const u8, self.len()) };
142				output.set_slice_u8(slice);
143			},
144			_ => {
145				// only using `dep_encode_slice_contents` for non-u8,
146				// because it always appends to the buffer,
147				// which is not necessary above
148				let mut buffer = Vec::<u8>::new();
149				for x in *self {
150					x.dep_encode_or_exit(&mut buffer, c.clone(), exit);
151				}
152				output.set_slice_u8(&buffer[..]);
153			},
154		}
155	}
156}
157
158impl<T: TopEncode> TopEncode for &T {
159	#[inline]
160	fn top_encode<O: TopEncodeOutput>(&self, output: O) -> Result<(), EncodeError> {
161		(*self).top_encode(output)
162	}
163
164	#[inline]
165	fn top_encode_or_exit<O: TopEncodeOutput, ExitCtx: Clone>(
166		&self,
167		output: O,
168		c: ExitCtx,
169		exit: fn(ExitCtx, EncodeError) -> !,
170	) {
171		(*self).top_encode_or_exit(output, c, exit);
172	}
173}
174
175impl TopEncode for &str {
176	fn top_encode<O: TopEncodeOutput>(&self, output: O) -> Result<(), EncodeError> {
177		output.set_slice_u8(self.as_bytes());
178		Ok(())
179	}
180
181	fn top_encode_or_exit<O: TopEncodeOutput, ExitCtx: Clone>(
182		&self,
183		output: O,
184		_: ExitCtx,
185		_: fn(ExitCtx, EncodeError) -> !,
186	) {
187		output.set_slice_u8(self.as_bytes());
188	}
189}
190
191impl<T: NestedEncode> TopEncode for Vec<T> {
192	#[inline]
193	fn top_encode<O: TopEncodeOutput>(&self, output: O) -> Result<(), EncodeError> {
194		self.as_slice().top_encode(output)
195	}
196
197	#[inline]
198	fn top_encode_or_exit<O: TopEncodeOutput, ExitCtx: Clone>(
199		&self,
200		output: O,
201		c: ExitCtx,
202		exit: fn(ExitCtx, EncodeError) -> !,
203	) {
204		self.as_slice().top_encode_or_exit(output, c, exit);
205	}
206}
207
208impl TopEncode for String {
209	#[inline]
210	fn top_encode<O: TopEncodeOutput>(&self, output: O) -> Result<(), EncodeError> {
211		self.as_bytes().top_encode(output)
212	}
213
214	#[inline]
215	fn top_encode_or_exit<O: TopEncodeOutput, ExitCtx: Clone>(
216		&self,
217		output: O,
218		c: ExitCtx,
219		exit: fn(ExitCtx, EncodeError) -> !,
220	) {
221		self.as_bytes().top_encode_or_exit(output, c, exit);
222	}
223}
224
225impl TopEncode for Box<str> {
226	#[inline]
227	fn top_encode<O: TopEncodeOutput>(&self, output: O) -> Result<(), EncodeError> {
228		self.as_ref().as_bytes().top_encode(output)
229	}
230
231	#[inline]
232	fn top_encode_or_exit<O: TopEncodeOutput, ExitCtx: Clone>(
233		&self,
234		output: O,
235		c: ExitCtx,
236		exit: fn(ExitCtx, EncodeError) -> !,
237	) {
238		self.as_ref().as_bytes().top_encode_or_exit(output, c, exit);
239	}
240}
241
242macro_rules! encode_num_unsigned {
243	($num_type:ty, $size_in_bits:expr, $type_info:expr) => {
244		impl TopEncodeNoErr for $num_type {
245			#[inline]
246			fn top_encode_no_err<O: TopEncodeOutput>(&self, output: O) {
247				output.set_u64(*self as u64);
248			}
249		}
250
251		top_encode_from_no_err! {$num_type, $type_info}
252	};
253}
254
255encode_num_unsigned! {u64, 64, TypeInfo::U64}
256encode_num_unsigned! {u32, 32, TypeInfo::U32}
257encode_num_unsigned! {usize, 32, TypeInfo::USIZE}
258encode_num_unsigned! {u16, 16, TypeInfo::U16}
259encode_num_unsigned! {u8, 8, TypeInfo::U8}
260
261macro_rules! encode_num_signed {
262	($num_type:ty, $size_in_bits:expr, $type_info:expr) => {
263		impl TopEncodeNoErr for $num_type {
264			#[inline]
265			fn top_encode_no_err<O: TopEncodeOutput>(&self, output: O) {
266				output.set_i64(*self as i64);
267			}
268		}
269
270		top_encode_from_no_err! {$num_type, $type_info}
271	};
272}
273
274encode_num_signed! {i64, 64, TypeInfo::I64}
275encode_num_signed! {i32, 32, TypeInfo::I32}
276encode_num_signed! {isize, 32, TypeInfo::ISIZE}
277encode_num_signed! {i16, 16, TypeInfo::I16}
278encode_num_signed! {i8, 8, TypeInfo::I8}
279
280impl TopEncodeNoErr for bool {
281	fn top_encode_no_err<O: TopEncodeOutput>(&self, output: O) {
282		// only using signed because this one is implemented in Andes, unsigned is not
283		// TODO: change to set_u64
284		output.set_i64(if *self { 1i64 } else { 0i64 });
285	}
286}
287
288top_encode_from_no_err! {bool, TypeInfo::Bool}
289
290impl<T: NestedEncode> TopEncode for Option<T> {
291	/// Allow None to be serialized to empty bytes, but leave the leading "1" for Some,
292	/// to allow disambiguation between e.g. Some(0) and None.
293	fn top_encode<O: TopEncodeOutput>(&self, output: O) -> Result<(), EncodeError> {
294		match self {
295			Some(v) => {
296				let mut buffer = Vec::<u8>::new();
297				buffer.push_byte(1u8);
298				v.dep_encode(&mut buffer)?;
299				output.set_slice_u8(&buffer[..]);
300			},
301			None => {
302				output.set_slice_u8(&[]);
303			},
304		}
305		Ok(())
306	}
307
308	/// Allow None to be serialized to empty bytes, but leave the leading "1" for Some,
309	/// to allow disambiguation between e.g. Some(0) and None.
310	fn top_encode_or_exit<O: TopEncodeOutput, ExitCtx: Clone>(
311		&self,
312		output: O,
313		c: ExitCtx,
314		exit: fn(ExitCtx, EncodeError) -> !,
315	) {
316		match self {
317			Some(v) => {
318				let mut buffer = Vec::<u8>::new();
319				buffer.push_byte(1u8);
320				v.dep_encode_or_exit(&mut buffer, c, exit);
321				output.set_slice_u8(&buffer[..]);
322			},
323			None => {
324				output.set_slice_u8(&[]);
325			},
326		}
327	}
328}
329
330impl<T: TopEncode> TopEncode for Box<T> {
331	#[inline]
332	fn top_encode<O: TopEncodeOutput>(&self, output: O) -> Result<(), EncodeError> {
333		self.as_ref().top_encode(output)
334	}
335
336	#[inline]
337	fn top_encode_or_exit<O: TopEncodeOutput, ExitCtx: Clone>(
338		&self,
339		output: O,
340		c: ExitCtx,
341		exit: fn(ExitCtx, EncodeError) -> !,
342	) {
343		self.as_ref().top_encode_or_exit(output, c, exit);
344	}
345}
346
347impl<T: NestedEncode> TopEncode for Box<[T]> {
348	#[inline]
349	fn top_encode<O: TopEncodeOutput>(&self, output: O) -> Result<(), EncodeError> {
350		self.as_ref().top_encode(output)
351	}
352
353	#[inline]
354	fn top_encode_or_exit<O: TopEncodeOutput, ExitCtx: Clone>(
355		&self,
356		output: O,
357		c: ExitCtx,
358		exit: fn(ExitCtx, EncodeError) -> !,
359	) {
360		self.as_ref().top_encode_or_exit(output, c, exit);
361	}
362}
363
364macro_rules! tuple_impls {
365    ($(($($n:tt $name:ident)+))+) => {
366        $(
367            impl<$($name),+> TopEncode for ($($name,)+)
368            where
369                $($name: NestedEncode,)+
370            {
371				fn top_encode<O: TopEncodeOutput>(&self, output: O) -> Result<(), EncodeError> {
372					let mut buffer = Vec::<u8>::new();
373					$(
374                        self.$n.dep_encode(&mut buffer)?;
375                    )+
376					output.set_slice_u8(&buffer[..]);
377					Ok(())
378				}
379
380				fn top_encode_or_exit<O: TopEncodeOutput, ExitCtx: Clone>(&self, output: O, c: ExitCtx, exit: fn(ExitCtx, EncodeError) -> !) {
381					let mut buffer = Vec::<u8>::new();
382					$(
383                        self.$n.dep_encode_or_exit(&mut buffer, c.clone(), exit);
384                    )+
385					output.set_slice_u8(&buffer[..]);
386				}
387            }
388        )+
389    }
390}
391
392tuple_impls! {
393	(0 T0)
394	(0 T0 1 T1)
395	(0 T0 1 T1 2 T2)
396	(0 T0 1 T1 2 T2 3 T3)
397	(0 T0 1 T1 2 T2 3 T3 4 T4)
398	(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5)
399	(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6)
400	(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7)
401	(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8)
402	(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9)
403	(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10)
404	(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11)
405	(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)
406	(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)
407	(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)
408	(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)
409}
410
411macro_rules! array_impls {
412    ($($n: tt,)+) => {
413        $(
414            impl<T: NestedEncode> TopEncode for [T; $n] {
415				#[inline]
416				fn top_encode<O: TopEncodeOutput>(&self, output: O) -> Result<(), EncodeError> {
417					// the top encoded slice does not serialize its length, so just like the array
418					(&self[..]).top_encode(output)
419				}
420
421				#[inline]
422				fn top_encode_or_exit<O: TopEncodeOutput, ExitCtx: Clone>(&self, output: O, c: ExitCtx, exit: fn(ExitCtx, EncodeError) -> !) {
423					(&self[..]).top_encode_or_exit(output, c, exit);
424				}
425            }
426        )+
427    }
428}
429
430#[rustfmt::skip]
431array_impls!(
432	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
433	17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
434	32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
435	52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
436	72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
437	92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
438	109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
439	125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140,
440	141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156,
441	157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172,
442	173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188,
443	189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204,
444	205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220,
445	221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236,
446	237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252,
447	253, 254, 255, 256, 384, 512, 768, 1024, 2048, 4096, 8192, 16384, 32768,
448);
449
450impl TopEncode for NonZeroUsize {
451	fn top_encode<O: TopEncodeOutput>(&self, output: O) -> Result<(), EncodeError> {
452		self.get().top_encode(output)
453	}
454
455	fn top_encode_or_exit<O: TopEncodeOutput, ExitCtx: Clone>(
456		&self,
457		output: O,
458		c: ExitCtx,
459		exit: fn(ExitCtx, EncodeError) -> !,
460	) {
461		self.get().top_encode_or_exit(output, c, exit);
462	}
463}
464
465////////////////////////////////////////////////////////////////////////////////
466
467#[cfg(test)]
468mod tests {
469	use super::super::test_struct::*;
470	use super::*;
471	use crate::test_util::check_top_encode;
472	use core::fmt::Debug;
473
474	fn ser_ok<V>(element: V, expected_bytes: &[u8])
475	where
476		V: TopEncode + PartialEq + Debug + 'static,
477	{
478		let bytes = check_top_encode(&element);
479		assert_eq!(bytes.as_slice(), expected_bytes);
480	}
481
482	#[test]
483	fn test_serialize_top_compacted_numbers() {
484		// unsigned positive
485		ser_ok(5u8, &[5]);
486		ser_ok(5u16, &[5]);
487		ser_ok(5u32, &[5]);
488		ser_ok(5u64, &[5]);
489		ser_ok(5usize, &[5]);
490		// signed positive
491		ser_ok(5i8, &[5]);
492		ser_ok(5i16, &[5]);
493		ser_ok(5i32, &[5]);
494		ser_ok(5i64, &[5]);
495		ser_ok(5isize, &[5]);
496		// signed negative
497		ser_ok(-5i8, &[251]);
498		ser_ok(-5i16, &[251]);
499		ser_ok(-5i32, &[251]);
500		ser_ok(-5i64, &[251]);
501		ser_ok(-5isize, &[251]);
502		// non zero usize
503		ser_ok(NonZeroUsize::new(5).unwrap(), &[5]);
504	}
505
506	#[test]
507	fn test_serialize_top_compacted_numbers_msb_ok() {
508		ser_ok(127i32, &[127]);
509		ser_ok(128i32, &[0, 128]);
510		ser_ok(255i32, &[0, 255]);
511
512		ser_ok(-1i32, &[255]);
513		ser_ok(-128i32, &[128]);
514		ser_ok(-129i32, &[255, 127]);
515		ser_ok(-256i32, &[255, 0]);
516		ser_ok(-257i32, &[254, 255]);
517	}
518
519	#[test]
520	fn test_top_compacted_bool() {
521		ser_ok(true, &[1]);
522		ser_ok(false, &[]);
523	}
524
525	#[test]
526	fn test_top_compacted_empty_bytes() {
527		let empty_byte_slice: &[u8] = &[];
528		ser_ok(empty_byte_slice, empty_byte_slice);
529	}
530
531	#[test]
532	fn test_top_compacted_bytes() {
533		ser_ok(&[1u8, 2u8, 3u8][..], &[1u8, 2u8, 3u8]);
534	}
535
536	#[test]
537	fn test_top_compacted_vec_u8() {
538		let some_vec = [1u8, 2u8, 3u8].to_vec();
539		ser_ok(some_vec, &[1u8, 2u8, 3u8]);
540	}
541
542	#[test]
543	fn test_top_encode_str() {
544		let s = "abc";
545		ser_ok(s, &[b'a', b'b', b'c']);
546		ser_ok(String::from(s), &[b'a', b'b', b'c']);
547		ser_ok(String::from(s).into_boxed_str(), &[b'a', b'b', b'c']);
548	}
549
550	#[test]
551	fn test_top_compacted_vec_i32() {
552		let some_vec = [1i32, 2i32, 3i32].to_vec();
553		let expected: &[u8] = &[0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3];
554		ser_ok(some_vec, expected);
555	}
556
557	#[test]
558	fn test_struct() {
559		let test = Test {
560			int: 1,
561			seq: [5, 6].to_vec(),
562			another_byte: 7,
563		};
564
565		ser_ok(test, &[0, 1, 0, 0, 0, 2, 5, 6, 7]);
566	}
567
568	#[test]
569	fn test_tuple() {
570		ser_ok((7u32, -2i16), &[0, 0, 0, 7, 255, 254]);
571	}
572
573	#[test]
574	fn test_unit() {
575		ser_ok((), &[]);
576	}
577
578	#[test]
579	fn test_enum() {
580		let u = E::Unit;
581		let expected: &[u8] = &[/*variant index*/ 0, 0, 0, 0];
582		ser_ok(u, expected);
583
584		let n = E::Newtype(1);
585		let expected: &[u8] = &[/*variant index*/ 0, 0, 0, 1, /*data*/ 0, 0, 0, 1];
586		ser_ok(n, expected);
587
588		let t = E::Tuple(1, 2);
589		let expected: &[u8] = &[
590			/*variant index*/ 0, 0, 0, 2, /*(*/ 0, 0, 0, 1, /*,*/ 0, 0, 0,
591			2, /*)*/
592		];
593		ser_ok(t, expected);
594
595		let s = E::Struct { a: 1 };
596		let expected: &[u8] = &[/*variant index*/ 0, 0, 0, 3, /*data*/ 0, 0, 0, 1];
597		ser_ok(s, expected);
598	}
599}