array_fusion/bytes/
decoding.rs

1use core::ops::Add;
2use core::ops::Mul;
3use core::ops::Sub;
4
5pub use hybrid_array;
6#[doc(hidden)]
7pub use hybrid_array::Array;
8use hybrid_array::ArraySize;
9use hybrid_array::AssocArraySize;
10#[doc(hidden)]
11pub use hybrid_array::sizes;
12use hybrid_array::sizes::U0;
13use hybrid_array::sizes::U1;
14use hybrid_array::typenum::Prod;
15use hybrid_array::typenum::Sum;
16
17use super::SizeOf;
18use crate::array_to_core;
19use crate::chunks::chunks;
20
21
22
23#[macro_export]
24macro_rules! split_bytes {
25	(
26		let bytes [
27			$($name:ident $(: $ty:ty)? ),* $(,)?
28		] = $data:expr $(;)?
29	) => {
30		$crate::split_array!{
31			let split [
32				$($name),*
33			] = $data;
34		}
35
36		$(
37			let $name $( : $ty )? = $crate::bytes::decoding::FromByteArray::from_bytes($name) ;
38		)*
39	};
40}
41
42
43
44pub trait FromByteArray {
45	type Size: ArraySize;
46
47	fn from_bytes(array: Array<u8, Self::Size>) -> Self;
48}
49
50
51impl<Size, T> FromByteArray for Array<T, Size>
52where
53	Size: ArraySize,
54	T: FromByteArray,
55	Prod<T::Size, Size>: ArraySize,
56	T::Size: Mul<Size>,
57{
58	type Size = Prod<T::Size, Size>;
59
60	fn from_bytes(array: Array<u8, Self::Size>) -> Self {
61		chunks(array).map(|sub| FromByteArray::from_bytes(sub))
62	}
63}
64
65impl<const N: usize, T> FromByteArray for [T; N]
66where
67	T: FromByteArray,
68	[T; N]: AssocArraySize,
69	<[T; N] as AssocArraySize>::Size: ArraySize<ArrayType<T> = [T; N]>,
70	Prod<T::Size, SizeOf<T, N>>: ArraySize,
71	T::Size: Mul<SizeOf<T, N>>,
72{
73	type Size = Prod<T::Size, SizeOf<T, N>>;
74
75	fn from_bytes(array: Array<u8, Self::Size>) -> Self {
76		array_to_core(Array::from_bytes(array))
77	}
78}
79
80impl FromByteArray for u8 {
81	type Size = U1;
82
83	fn from_bytes(array: Array<u8, Self::Size>) -> Self {
84		let [n] = array.0;
85		n
86	}
87}
88impl FromByteArray for i8 {
89	type Size = U1;
90
91	fn from_bytes(array: Array<u8, Self::Size>) -> Self {
92		let [n] = array.0;
93		n as i8
94	}
95}
96
97impl FromByteArray for () {
98	type Size = U0;
99
100	fn from_bytes(array: Array<u8, Self::Size>) -> Self {
101		let [] = array.0;
102	}
103}
104impl<T1> FromByteArray for (T1,)
105where
106	T1: FromByteArray,
107{
108	type Size = T1::Size;
109
110	fn from_bytes(array: Array<u8, Self::Size>) -> Self {
111		(T1::from_bytes(array),)
112	}
113}
114impl<T1, T2> FromByteArray for (T1, T2)
115where
116	T1: FromByteArray,
117	T2: FromByteArray,
118	T1::Size: Add<T2::Size>,
119	Sum<T1::Size, T2::Size>: ArraySize + Sub<T1::Size, Output = T2::Size>,
120{
121	type Size = Sum<T1::Size, T2::Size>;
122
123	fn from_bytes(array: Array<u8, Self::Size>) -> Self {
124		let (sub1, sub2) = array.split();
125		(T1::from_bytes(sub1), T2::from_bytes(sub2))
126	}
127}
128
129pub fn parse_from_array<T>(array: Array<u8, T::Size>) -> T
130where
131	T: FromByteArray,
132{
133	T::from_bytes(array)
134}
135
136
137
138#[cfg(test)]
139mod test {
140	use hybrid_array::sizes::U2;
141	use hybrid_array::sizes::U4;
142
143	use super::*;
144	use crate::array_from_core;
145	use crate::bytes::BigEndian;
146	use crate::chunks::chunks_from_core;
147	use crate::chunks::flatten;
148
149	struct Foo(u16);
150	impl FromByteArray for Foo {
151		type Size = U2;
152
153		fn from_bytes(array: Array<u8, Self::Size>) -> Self {
154			Foo(u16::from_be_bytes(array.0))
155		}
156	}
157	struct Bar(u32);
158	impl FromByteArray for Bar {
159		type Size = U4;
160
161		fn from_bytes(array: Array<u8, Self::Size>) -> Self {
162			Bar(u32::from_be_bytes(array.0))
163		}
164	}
165
166
167	#[test]
168	fn test_parse_from_array_u8() {
169		let input = 42_u8;
170		let data = array_from_core([input]);
171		let parsed: u8 = parse_from_array(data);
172		assert_eq!(parsed, input);
173	}
174
175	#[test]
176	fn test_parse_from_array_id() {
177		let input = [1, 2, 3, 4];
178		let data = array_from_core(input);
179		let parsed: Array<u8, U4> = parse_from_array(data);
180		assert_eq!(parsed, Array(input));
181	}
182
183	#[test]
184	fn test_parse_from_array_array() {
185		let input = [1, 2, 3, 4];
186		let data = array_from_core(input);
187		let parsed: [u8; 4] = parse_from_array(data);
188		assert_eq!(parsed, input);
189	}
190
191	#[test]
192	fn test_parse_from_array_array_of_arrays() {
193		let input = [[1, 2], [3, 4]];
194		let data = flatten(chunks_from_core(input));
195		let parsed: [[u8; 2]; 2] = parse_from_array(data);
196		assert_eq!(parsed, input);
197	}
198
199	#[test]
200	fn test_parse_from_array_tuple() {
201		let input = [1, 2];
202		let data = array_from_core(input);
203		let parsed: (u8, u8) = parse_from_array(data);
204		assert_eq!(parsed, (1, 2));
205	}
206
207	#[test]
208	fn test_parse_from_array_custom_type() {
209		let input = [0, 42];
210		let data = array_from_core(input);
211		let parsed: Foo = parse_from_array(data);
212		assert_eq!(parsed.0, 42);
213	}
214
215	#[test]
216	fn test_parse_from_array_custom_tuple() {
217		let input = [0, 42, 0, 0, 0x12, 0x34];
218		let data = array_from_core(input);
219		let parsed: (Foo, Bar) = parse_from_array(data);
220		assert_eq!(parsed.0.0, 42);
221		assert_eq!(parsed.1.0, 0x1234);
222	}
223
224	#[test]
225	fn test_split_bytes() {
226		let data = [
227			0, 42, // foo
228			0x0, 0x0, 0x12, 0x34, // bar
229			0,    // padding
230			b'a', b'b', b'c', // alpha
231		];
232		split_bytes! {
233			let bytes [
234				foo,
235				bar: BigEndian<u32>,
236				_pad: u8,
237				alpha: [u8; 3],
238			] = array_from_core(data);
239		}
240		let foo: Foo = foo;
241		assert_eq!(foo.0, 42);
242		assert_eq!(bar.0, 0x1234);
243		assert_eq!(alpha, *b"abc");
244	}
245}