1use crate::{
4 EtherCrabWireRead, EtherCrabWireReadSized, EtherCrabWireSized, EtherCrabWireWrite,
5 EtherCrabWireWriteSized, WireError,
6};
7
8macro_rules! impl_primitive_wire_field {
9 ($ty:ty, $size:expr) => {
10 impl EtherCrabWireWrite for $ty {
11 fn pack_to_slice_unchecked<'buf>(&self, buf: &'buf mut [u8]) -> &'buf [u8] {
12 let Some(chunk) = buf.first_chunk_mut::<$size>() else {
13 unreachable!()
14 };
15
16 *chunk = self.to_le_bytes();
17
18 chunk
19 }
20
21 fn pack_to_slice<'buf>(&self, buf: &'buf mut [u8]) -> Result<&'buf [u8], WireError> {
22 let Some(chunk) = buf.first_chunk_mut::<$size>() else {
23 return Err(WireError::WriteBufferTooShort);
24 };
25
26 *chunk = self.to_le_bytes();
27
28 Ok(chunk)
29 }
30
31 fn packed_len(&self) -> usize {
32 $size
33 }
34 }
35
36 impl EtherCrabWireRead for $ty {
37 fn unpack_from_slice(buf: &[u8]) -> Result<Self, WireError> {
38 buf.first_chunk::<$size>()
39 .ok_or(WireError::ReadBufferTooShort)
40 .map(|chunk| Self::from_le_bytes(*chunk))
41 }
42 }
43
44 impl EtherCrabWireSized for $ty {
45 const PACKED_LEN: usize = $size;
46
47 type Buffer = [u8; $size];
48
49 fn buffer() -> Self::Buffer {
50 [0u8; $size]
51 }
52 }
53
54 impl EtherCrabWireWriteSized for $ty {
55 fn pack(&self) -> Self::Buffer {
56 self.to_le_bytes()
57 }
58 }
59
60 impl<const N: usize> EtherCrabWireSized for [$ty; N] {
63 const PACKED_LEN: usize = N * $size;
64
65 type Buffer = [u8; N];
66
67 fn buffer() -> Self::Buffer {
68 [0u8; N]
69 }
70 }
71 };
72}
73
74macro_rules! impl_tuples {
76 ($($len:tt => ($($n:tt $name:ident)+))+) => {
77 $(
78 #[allow(non_snake_case)]
79 impl<$($name: EtherCrabWireReadSized),+> EtherCrabWireRead for ($($name,)+) {
80 #[allow(unused_assignments)]
81 fn unpack_from_slice(mut buf: &[u8]) -> Result<Self, WireError> {
82 $(
83 let $name = $name::unpack_from_slice(buf)?;
84
85 if buf.len() > 0 {
86 buf = &buf[$name::PACKED_LEN..];
87 }
88 )+
89
90 Ok(($($name,)+))
91 }
92 }
93
94 #[allow(non_snake_case)]
95 impl<$($name: EtherCrabWireWrite),+> EtherCrabWireWrite for ($($name,)+) {
96 #[allow(unused_assignments)]
97 fn pack_to_slice_unchecked<'buf>(&self, orig: &'buf mut [u8]) -> &'buf [u8] {
98 {
99 let mut buf = &mut orig[..];
100
101 $(
102 let (chunk, rest) = buf.split_at_mut(self.$n.packed_len());
103 let _packed = self.$n.pack_to_slice_unchecked(chunk);
104 buf = rest;
105 )+
106 }
107
108 &orig[0..self.packed_len()]
109 }
110
111 fn packed_len(&self) -> usize {
112 0
113 $(
114 + self.$n.packed_len()
115 )+
116 }
117 }
118 )+
119 }
120}
121
122impl_tuples! {
123 1 => (0 T0)
124 2 => (0 T0 1 T1)
125 3 => (0 T0 1 T1 2 T2)
126 4 => (0 T0 1 T1 2 T2 3 T3)
127 5 => (0 T0 1 T1 2 T2 3 T3 4 T4)
128 6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5)
129 7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6)
130 8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7)
131 9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8)
132 10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9)
133 11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10)
134 12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11)
135 13 => (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)
136 14 => (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)
137 15 => (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)
138 16 => (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)
139}
140
141impl_primitive_wire_field!(u8, 1);
142impl_primitive_wire_field!(u16, 2);
143impl_primitive_wire_field!(u32, 4);
144impl_primitive_wire_field!(u64, 8);
145impl_primitive_wire_field!(i8, 1);
146impl_primitive_wire_field!(i16, 2);
147impl_primitive_wire_field!(i32, 4);
148impl_primitive_wire_field!(i64, 8);
149
150impl_primitive_wire_field!(f32, 4);
151impl_primitive_wire_field!(f64, 8);
152
153impl EtherCrabWireWrite for bool {
154 fn pack_to_slice_unchecked<'buf>(&self, buf: &'buf mut [u8]) -> &'buf [u8] {
155 buf[0] = if *self { 0xff } else { 0x00 };
156
157 &buf[0..1]
158 }
159
160 fn packed_len(&self) -> usize {
161 1
162 }
163}
164
165impl EtherCrabWireRead for bool {
166 fn unpack_from_slice(buf: &[u8]) -> Result<Self, WireError> {
167 Ok(*buf.first().ok_or(WireError::ReadBufferTooShort)? > 0)
170 }
171}
172
173impl EtherCrabWireSized for bool {
174 const PACKED_LEN: usize = 1;
175
176 type Buffer = [u8; Self::PACKED_LEN];
177
178 fn buffer() -> Self::Buffer {
179 [0u8; 1]
180 }
181}
182
183impl EtherCrabWireWriteSized for bool {
184 fn pack(&self) -> Self::Buffer {
185 [if *self { 0xff } else { 0x00 }; 1]
187 }
188}
189
190impl EtherCrabWireWrite for () {
191 fn pack_to_slice_unchecked<'buf>(&self, _buf: &'buf mut [u8]) -> &'buf [u8] {
192 &[]
193 }
194
195 fn packed_len(&self) -> usize {
196 0
197 }
198}
199
200impl EtherCrabWireRead for () {
201 fn unpack_from_slice(_buf: &[u8]) -> Result<Self, WireError> {
202 Ok(())
203 }
204}
205
206impl EtherCrabWireSized for () {
207 const PACKED_LEN: usize = 0;
208
209 type Buffer = [u8; 0];
210
211 fn buffer() -> Self::Buffer {
212 [0u8; 0]
213 }
214}
215
216impl EtherCrabWireWriteSized for () {
217 fn pack(&self) -> Self::Buffer {
218 [0u8; 0]
219 }
220}
221
222impl<const N: usize> EtherCrabWireWrite for [u8; N] {
223 fn pack_to_slice_unchecked<'buf>(&self, buf: &'buf mut [u8]) -> &'buf [u8] {
224 let Some(chunk) = buf.first_chunk_mut::<N>() else {
225 unreachable!()
226 };
227
228 *chunk = *self;
229
230 chunk
231 }
232
233 fn packed_len(&self) -> usize {
234 N
235 }
236}
237
238impl EtherCrabWireWrite for &[u8] {
239 fn pack_to_slice_unchecked<'buf>(&self, buf: &'buf mut [u8]) -> &'buf [u8] {
240 let buf = &mut buf[0..self.len()];
241
242 buf.copy_from_slice(self);
243
244 buf
245 }
246
247 fn packed_len(&self) -> usize {
248 self.len()
249 }
250}
251
252impl<T> EtherCrabWireWrite for &T
254where
255 T: EtherCrabWireWrite,
256{
257 fn pack_to_slice_unchecked<'buf>(&self, buf: &'buf mut [u8]) -> &'buf [u8] {
258 EtherCrabWireWrite::pack_to_slice_unchecked(*self, buf)
259 }
260
261 fn packed_len(&self) -> usize {
262 EtherCrabWireWrite::packed_len(*self)
263 }
264}
265
266impl<const N: usize, T> EtherCrabWireRead for [T; N]
268where
269 T: EtherCrabWireReadSized,
270{
271 fn unpack_from_slice(buf: &[u8]) -> Result<Self, WireError> {
272 buf.get(0..(T::PACKED_LEN * N))
273 .ok_or(WireError::ReadBufferTooShort)?
274 .chunks_exact(T::PACKED_LEN)
275 .take(N)
276 .map(T::unpack_from_slice)
277 .collect::<Result<heapless::Vec<_, N>, WireError>>()
278 .and_then(|res| res.into_array().map_err(|_e| WireError::ArrayLength))
279 }
280}
281
282impl<const N: usize, T> EtherCrabWireRead for heapless::Vec<T, N>
285where
286 T: EtherCrabWireReadSized,
287{
288 fn unpack_from_slice(buf: &[u8]) -> Result<Self, WireError> {
289 buf.chunks_exact(T::PACKED_LEN)
290 .take(N)
291 .map(T::unpack_from_slice)
292 .collect::<Result<heapless::Vec<_, N>, WireError>>()
293 }
294}
295
296impl<const N: usize, T> EtherCrabWireSized for heapless::Vec<T, N>
299where
300 T: Into<u8>,
301{
302 const PACKED_LEN: usize = N;
303
304 type Buffer = [u8; N];
305
306 fn buffer() -> Self::Buffer {
307 [0u8; N]
308 }
309}
310
311impl<const N: usize> EtherCrabWireRead for heapless::String<N> {
314 fn unpack_from_slice(buf: &[u8]) -> Result<Self, WireError> {
315 core::str::from_utf8(buf)
316 .map_err(|_| WireError::InvalidUtf8)
317 .and_then(|s| Self::try_from(s).map_err(|_| WireError::ArrayLength))
318 }
319}
320
321impl<const N: usize> EtherCrabWireSized for heapless::String<N> {
322 const PACKED_LEN: usize = N;
323
324 type Buffer = [u8; N];
325
326 fn buffer() -> Self::Buffer {
327 [0u8; N]
328 }
329}
330
331#[cfg(feature = "std")]
334impl EtherCrabWireRead for String {
335 fn unpack_from_slice(buf: &[u8]) -> Result<Self, WireError> {
336 core::str::from_utf8(buf)
337 .map_err(|_| WireError::InvalidUtf8)
338 .map(String::from)
339 }
340}
341
342#[cfg(test)]
343mod tests {
344 use super::*;
345
346 #[test]
347 fn bool_pack() {
348 assert_eq!(true.pack(), [0xff]);
349 assert_eq!(false.pack(), [0x00]);
350
351 let mut sl1 = [0u8; 8];
352 let mut sl2 = [0u8; 8];
353
354 assert_eq!(true.pack_to_slice_unchecked(&mut sl1), &[0xffu8]);
355 assert_eq!(false.pack_to_slice_unchecked(&mut sl2), &[0x00u8]);
356 }
357
358 #[test]
359 fn bool_unpack() {
360 assert_eq!(bool::unpack_from_slice(&[0xff]), Ok(true));
361 assert_eq!(bool::unpack_from_slice(&[0x00]), Ok(false));
362
363 assert_eq!(bool::unpack_from_slice(&[0x01]), Ok(true));
365 }
366
367 #[test]
368 fn tuple_decode() {
369 let res = <(u32, u8)>::unpack_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd, 0x99]);
370
371 assert_eq!(
372 res,
373 Ok((u32::from_le_bytes([0xaa, 0xbb, 0xcc, 0xdd]), 0x99))
374 )
375 }
376
377 #[test]
378 fn tuple_encode() {
379 let mut buf = [0u8; 32];
380
381 let written = (0xaabbccddu32, 0x99u8, 0x1234u16).pack_to_slice_unchecked(&mut buf);
382
383 assert_eq!(written, &[0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x34, 0x12]);
384 }
385}