array_fusion/bytes/
encoding.rs

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