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