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