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, 0x0, 0x0, 0x12, 0x34, 0, b'a', b'b', b'c', ])
237 );
238 }
239}