1#![allow(incomplete_features)]
2#![feature(
3 more_qualified_paths,
4 iter_next_chunk,
5 generic_const_exprs,
6 iter_array_chunks
7)]
8#![no_std]
9
10#[cfg(feature = "non_fixed")]
11extern crate alloc;
12
13use core::fmt::Debug;
14
15#[cfg(feature = "non_fixed")]
16use alloc::vec::Vec;
17
18#[derive(Debug)]
19pub enum ParserError {
21 TooLittleData(usize),
23 HeaderIncomplete(usize),
25 InvalidMagic,
27 ValueNotUnderstood,
29 ArrayTooShort,
31}
32
33#[derive(Debug, Copy, Clone)]
35pub enum Endian {
36 Little,
37 Big,
38}
39pub trait StaticallySized {
41 const SIZE: usize;
42}
43pub trait Read
45where
46 Self: Sized,
47{
48 fn from_bytes(data: &mut impl ExactSizeIterator<Item = u8>) -> Result<Self, ParserError>;
49}
50pub trait ReadCtx<Ctx>
52where
53 Self: Sized,
54{
55 fn from_bytes(
56 data: &mut impl ExactSizeIterator<Item = u8>,
57 ctx: Ctx,
58 ) -> Result<Self, ParserError>;
59}
60#[cfg(feature = "non_fixed")]
61pub trait Write {
63 fn to_bytes(&self) -> Vec<u8>;
64}
65#[cfg(feature = "capped")]
66pub trait WriteCapped<const CAP: usize> {
68 fn to_bytes(&self) -> heapless::Vec<u8, CAP>;
69}
70#[cfg(feature = "non_fixed")]
71pub trait WriteCtx<Ctx> {
73 fn to_bytes(&self, ctx: Ctx) -> Vec<u8>;
74}#[cfg(feature = "capped")]
75pub trait WriteCappedCtx<const CAP: usize, Ctx> {
77 fn to_bytes(&self, ctx: Ctx) -> heapless::Vec<u8, CAP>;
78}
79
80pub trait ReadFixed<const N: usize>
82where
83 Self: Sized,
84{
85 fn from_bytes(data: &[u8; N]) -> Result<Self, ParserError>;
86}
87pub trait ReadFixedCtx<const N: usize, Ctx>
89where
90 Self: Sized,
91{
92 fn from_bytes(data: &[u8; N], ctx: Ctx) -> Result<Self, ParserError>;
93}
94pub trait WriteFixed<const N: usize>
96where
97 Self: Sized,
98{
99 fn to_bytes(&self) -> [u8; N];
100}
101pub trait WriteFixedCtx<const N: usize, Ctx>
103where
104 Self: Sized,
105{
106 fn to_bytes(&self, ctx: Ctx) -> [u8; N];
107}
108#[cfg(feature = "non_fixed")]
109impl<T> Read for Vec<T>
110where
111 T: Read,
112{
113 fn from_bytes(data: &mut impl ExactSizeIterator<Item = u8>) -> Result<Self, ParserError> {
114 Ok((0..).map_while(|_| T::from_bytes(data).ok()).collect()) }
116}
117
118#[cfg(feature = "non_fixed")]
119impl<T, Ctx> ReadCtx<Ctx> for Vec<T>
120where
121 T: ReadCtx<Ctx>,
122 Ctx: Clone,
123{
124 fn from_bytes(
125 data: &mut impl ExactSizeIterator<Item = u8>,
126 ctx: Ctx,
127 ) -> Result<Self, ParserError> {
128 Ok((0..)
129 .map_while(|_| T::from_bytes(data, ctx.clone()).ok())
130 .collect()) }
132}
133#[cfg(feature = "non_fixed")]
134impl<T> Write for Vec<T>
135where
136 T: Write,
137{
138 fn to_bytes(&self) -> Vec<u8> {
139 self.iter().flat_map(T::to_bytes).collect()
140 }
141}
142#[cfg(feature = "non_fixed")]
143impl<T, Ctx> WriteCtx<Ctx> for Vec<T>
144where
145 T: WriteCtx<Ctx>,
146 Ctx: Clone,
147{
148 fn to_bytes(&self, ctx: Ctx) -> Vec<u8> {
149 self.iter().flat_map(|x| x.to_bytes(ctx.clone())).collect()
150 }
151}
152impl<const N: usize, T> ReadFixed<{ T::SIZE * N }> for [T; N]
153where
154 T: StaticallySized + ReadFixed<{ T::SIZE }> + Default + Copy,
155 [(); T::SIZE * N]:,
156{
157 fn from_bytes(data: &[u8; T::SIZE * N]) -> Result<Self, ParserError> {
158 let mut output = [T::default(); N];
159 for (i, x) in data
160 .iter()
161 .copied()
162 .array_chunks::<{ T::SIZE }>()
163 .map(|x| T::from_bytes(&x))
164 .enumerate()
165 {
166 output[i] = x?;
167 }
168 Ok(output)
169 }
170}
171impl<const N: usize, T> WriteFixed<{ T::SIZE * N }> for [T; N]
172where
173 T: StaticallySized + WriteFixed<{ T::SIZE }> + Default + Copy,
174 [(); T::SIZE * N]:,
175{
176 fn to_bytes(&self) -> [u8; T::SIZE * N] {
177 self.iter().flat_map(T::to_bytes).next_chunk().unwrap()
178 }
179}
180#[cfg(feature = "non_fixed")]
181impl<const N: usize, T: Read + Default + Copy> Read for [T; N] {
182 fn from_bytes(data: &mut impl ExactSizeIterator<Item = u8>) -> Result<Self, ParserError> {
183 (0..N)
184 .map_while(|_| T::from_bytes(data).ok())
185 .next_chunk()
186 .map_err(|_| ParserError::ArrayTooShort)
187 }
188}
189#[cfg(feature = "non_fixed")]
190impl<const N: usize, T: Write> Write for [T; N] {
191 fn to_bytes(&self) -> Vec<u8> {
192 self.iter().flat_map(T::to_bytes).collect()
193 }
194}
195#[macro_export]
196macro_rules! enum_to_int {
227 ($a:ty, $b:ty, $($x:expr, $y:path), +) => {
228 impl From<$a> for $b {
229 fn from(value: $a) -> Self {
230 match value {
231 $($x => $y,)+
232 _ => Self::Unknown(value),
233 }
234 }
235 }
236 impl From<$b> for $a {
237 fn from(value: $b) -> Self {
238 match value {
239 $($y => $x,)+
240 <$b>::Unknown(value) => value
241 }
242 }
243 }
244 }
245}
246
247#[cfg(feature = "numeric_rw")]
248mod numeric_rw {
249 use super::*;
250 macro_rules! impl_rw_numeric {
251 ($number_type:ty) => {
252 impl StaticallySized for $number_type {
253 const SIZE: usize = { ::core::mem::size_of::<$number_type>() };
254 }
255 impl ReadFixedCtx<{ ::core::mem::size_of::<$number_type>() }, &Endian> for $number_type {
256 fn from_bytes(
257 data: &[u8; { ::core::mem::size_of::<$number_type>() }],
258 ctx: &Endian,
259 ) -> Result<Self, ParserError> {
260 let function = match *ctx {
261 Endian::Little => <$number_type>::from_le_bytes,
262 Endian::Big => <$number_type>::from_be_bytes,
263 };
264 Ok(function(*data))
265 }
266 }
267 #[cfg(feature = "non_fixed")]
268 impl ReadCtx<&Endian> for $number_type {
269 fn from_bytes(
270 data: &mut impl ExactSizeIterator<Item = u8>,
271 ctx: &Endian,
272 ) -> Result<Self, ParserError> {
273 let mut iter =
274 ::try_take::try_take(data, { ::core::mem::size_of::<$number_type>() })
275 .map_err(ParserError::TooLittleData)?;
276 <$number_type as ReadFixedCtx<
277 { ::core::mem::size_of::<$number_type>() },
278 &Endian,
279 >>::from_bytes(&iter.next_chunk().unwrap(), ctx)
280 }
281 }
282 impl WriteFixedCtx<{ ::core::mem::size_of::<$number_type>() }, &Endian>
283 for $number_type
284 {
285 fn to_bytes(
286 &self,
287 ctx: &Endian,
288 ) -> [u8; { ::core::mem::size_of::<$number_type>() }] {
289 let function = match *ctx {
290 Endian::Little => <$number_type>::to_le_bytes,
291 Endian::Big => <$number_type>::to_be_bytes,
292 };
293 function(*self)
294 }
295 }
296 #[cfg(feature = "non_fixed")]
297 impl<'a> WriteCtx<&Endian> for $number_type {
298 fn to_bytes(&self, ctx: &Endian) -> ::alloc::vec::Vec<u8> {
299 <Self as WriteFixedCtx<{ ::core::mem::size_of::<$number_type>() }, &Endian>>::to_bytes(self, ctx).to_vec()
300 }
301 }
302 };
303 }
304 impl_rw_numeric!(u8);
305 impl_rw_numeric!(i8);
306 impl_rw_numeric!(u16);
307 impl_rw_numeric!(i16);
308 impl_rw_numeric!(u32);
309 impl_rw_numeric!(i32);
310 impl_rw_numeric!(u64);
311 impl_rw_numeric!(i64);
312 impl_rw_numeric!(u128);
313 impl_rw_numeric!(i128);
314}
315#[cfg(feature = "numeric_rw")]
316pub use numeric_rw::*;