#![feature(more_qualified_paths)]
#![feature(iter_next_chunk)]
#![no_std]
#[cfg(feature = "non_fixed")]
extern crate alloc;
use core::fmt::Debug;
#[cfg(feature = "non_fixed")]
use alloc::borrow::Cow;
#[derive(Debug)]
pub enum ParserError {
TooLittleData(usize),
HeaderIncomplete(usize),
InvalidMagic,
ValueNotUnderstood,
}
pub enum Endian {
Little,
Big,
}
#[cfg(feature = "non_fixed")]
pub trait Read
where
Self: Sized,
{
fn from_bytes(data: &mut impl ExactSizeIterator<Item = u8>) -> Result<Self, ParserError>;
}
#[cfg(feature = "non_fixed")]
pub trait ReadCtx<Ctx>
where
Self: Sized,
{
fn from_bytes(
data: &mut impl ExactSizeIterator<Item = u8>,
ctx: Ctx,
) -> Result<Self, ParserError>;
}
#[cfg(feature = "non_fixed")]
pub trait Write<'a> {
fn to_bytes(&self) -> Cow<'a, [u8]>;
}
#[cfg(feature = "non_fixed")]
pub trait WriteCtx<'a, Ctx> {
fn to_bytes(&self, ctx: Ctx) -> Cow<'a, [u8]>;
}
pub trait ReadFixed<const N: usize>
where
Self: Sized,
{
fn from_bytes(data: &[u8; N]) -> Result<Self, ParserError>;
}
pub trait ReadFixedCtx<const N: usize, Ctx>
where
Self: Sized,
{
fn from_bytes(data: &[u8; N], ctx: Ctx) -> Result<Self, ParserError>;
}
pub trait WriteFixed<const N: usize>
where
Self: Sized,
{
fn to_bytes(&self) -> [u8; N];
}
pub trait WriteFixedCtx<const N: usize, Ctx>
where
Self: Sized,
{
fn to_bytes(&self, ctx: Ctx) -> [u8; N];
}
#[cfg(feature = "non_fixed")]
impl<T> Read for Vec<T>
where
T: Read,
{
fn from_bytes(data: &mut impl ExactSizeIterator<Item = u8>) -> Result<Self, ParserError> {
Ok((0..).map_while(|_| T::from_bytes(data).ok()).collect()) }
}
#[cfg(feature = "non_fixed")]
impl<T, Ctx> ReadCtx<Ctx> for Vec<T>
where
T: ReadCtx<Ctx>,
Ctx: Clone,
{
fn from_bytes(
data: &mut impl ExactSizeIterator<Item = u8>,
ctx: Ctx,
) -> Result<Self, ParserError> {
Ok((0..)
.map_while(|_| T::from_bytes(data, ctx.clone()).ok())
.collect()) }
}
#[cfg(feature = "non_fixed")]
impl<'a, T> Write<'a> for Vec<T>
where
T: Write<'a>,
{
fn to_bytes(&self) -> Cow<'a, [u8]> {
self.iter()
.map(T::to_bytes)
.collect::<Vec<Cow<[u8]>>>()
.concat()
.into()
}
}
#[cfg(feature = "non_fixed")]
impl<'a, T, Ctx> WriteCtx<'a, Ctx> for Vec<T>
where
T: WriteCtx<'a, Ctx>,
Ctx: Clone,
{
fn to_bytes(&self, ctx: Ctx) -> Cow<'a, [u8]> {
self.iter()
.map(|x| T::to_bytes(x, ctx.clone()))
.collect::<Vec<Cow<[u8]>>>()
.concat()
.into()
}
}
#[macro_export]
macro_rules! enum_to_int {
($a:ty, $b:ty, $($x:expr, $y:path), +) => {
impl From<$a> for $b {
fn from(value: $a) -> Self {
match value {
$($x => $y,)+
_ => Self::Unknown(value),
}
}
}
impl From<$b> for $a {
fn from(value: $b) -> Self {
match value {
$($y => $x,)+
<$b>::Unknown(value) => value
}
}
}
}
}
#[cfg(feature = "numeric_rw")]
mod numeric_rw {
use super::*;
use alloc::borrow::ToOwned;
impl Read for u8 {
fn from_bytes(data: &mut impl ExactSizeIterator<Item = u8>) -> Result<Self, ParserError> {
data.next().ok_or(ParserError::TooLittleData(1))
}
}
impl Read for i8 {
fn from_bytes(data: &mut impl ExactSizeIterator<Item = u8>) -> Result<Self, ParserError> {
data.next()
.ok_or(ParserError::TooLittleData(1))
.map(|x| x as i8)
}
}
impl<'a> Write<'a> for u8 {
fn to_bytes(&self) -> Cow<'a, [u8]> {
Cow::Owned([*self].as_slice().to_owned())
}
}
impl<'a> Write<'a> for i8 {
fn to_bytes(&self) -> Cow<'a, [u8]> {
Cow::Owned([*self as u8].as_slice().to_owned())
}
}
macro_rules! impl_rw_numeric {
($number_type:ty) => {
impl ReadCtx<Endian> for $number_type {
fn from_bytes(
data: &mut impl ExactSizeIterator<Item = u8>,
ctx: Endian,
) -> Result<Self, ParserError> {
Ok(match ctx {
Endian::Little => {
<$number_type>::from_le_bytes(data.next_chunk().map_err(|x| {
ParserError::TooLittleData(
core::mem::size_of::<$number_type>() - x.len(),
)
})?)
}
Endian::Big => {
<$number_type>::from_be_bytes(data.next_chunk().map_err(|x| {
ParserError::TooLittleData(
core::mem::size_of::<$number_type>() - x.len(),
)
})?)
}
})
}
}
impl<'a> WriteCtx<'a, Endian> for $number_type {
fn to_bytes(&self, ctx: Endian) -> Cow<'a, [u8]> {
match ctx {
Endian::Little => self.to_le_bytes(),
Endian::Big => self.to_be_bytes(),
}
.as_slice()
.to_owned()
.into()
}
}
};
}
impl_rw_numeric!(u16);
impl_rw_numeric!(i16);
impl_rw_numeric!(u32);
impl_rw_numeric!(i32);
impl_rw_numeric!(u64);
impl_rw_numeric!(i64);
impl_rw_numeric!(u128);
impl_rw_numeric!(i128);
}
use alloc::vec::Vec;
pub use numeric_rw::*;