#![no_std]
extern crate alloc;
use alloc::vec::Vec;
use core::fmt::{self, Debug, Formatter};
pub type Step<'a, Output, Error> = (&'a [u8], Result<Output, Error>);
pub struct ByteError;
pub fn byte<'a, Error: From<ByteError>>(input: &'a [u8]) -> Step<'a, u8, Error> {
match input.split_first() {
Some((&byte, rest)) => (rest, Ok(byte)),
None => (input, Err(ByteError.into())),
}
}
pub struct TakeError<'a>(
pub &'a [u8],
);
pub fn take<'a, Error: From<TakeError<'a>>>(
count: usize,
) -> impl Fn(&'a [u8]) -> Step<'a, &'a [u8], Error> {
move |input| {
let (out, input) = input.split_at(count);
match out.len() {
0 if count != 0 => (input, Err(TakeError(input).into())),
_ => (input, Ok(out)),
}
}
}
pub struct SeqError<'a, ChildError> {
pub at: &'a [u8],
pub step: usize,
pub child_error: ChildError,
}
impl<'a, ChildError: Debug> Debug for SeqError<'a, ChildError> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
fmt.debug_struct("SeqError")
.field("step", &self.step)
.field("child_error", &self.child_error)
.finish()
}
}
pub fn seq<'a, Output, Error: From<SeqError<'a, ChildError>>, ChildError>(
count: usize,
child: impl Fn(&'a [u8]) -> Step<'a, Output, ChildError>,
) -> impl Fn(&'a [u8]) -> Step<'a, Vec<Output>, Error> {
move |mut input| {
let before = input;
let mut out = Vec::with_capacity(count);
for step in 0..count {
let (rest, result) = (child)(input);
match result {
Ok(x) => out.push(x),
Err(child_error) => {
return (
before,
Err(SeqError {
at: input,
step,
child_error,
}
.into()),
)
}
}
input = rest;
}
(input, Ok(out))
}
}
pub enum OptError {}
pub fn opt<'a, Output, Error, Parser>(
child: impl Fn(&'a [u8]) -> Step<'a, Output, Error>,
) -> impl Fn(&'a [u8]) -> Step<'a, Option<Output>, OptError> {
move |input| {
let (rest, result) = (child)(input);
match result {
Ok(x) => (rest, Ok(Some(x))),
Err(_) => (input, Ok(None)),
}
}
}
pub struct FinishError<'a>(
pub &'a [u8],
);
pub fn finish<'a, Output, Error: From<ChildError> + From<FinishError<'a>>, ChildError>(
child: impl Fn(&'a [u8]) -> Step<'a, Output, ChildError>,
) -> impl Fn(&'a [u8]) -> Step<'a, Output, Error> {
move |input| {
let (rest, result) = (child)(input);
match result {
Ok(x) => match input.len() {
0 => (rest, Ok(x)),
_ => (input, Err(FinishError(input).into())),
},
Err(e) => (input, Err(e.into())),
}
}
}
pub struct TagError<'a>(
pub &'a [u8],
);
impl<'a> From<TakeError<'a>> for TagError<'a> {
fn from(x: TakeError<'a>) -> Self {
Self(x.0)
}
}
pub fn tag<'a, 'b, Error: From<TagError<'a>>>(
key: &'b [u8],
) -> impl Fn(&'a [u8]) -> Step<'a, &'a [u8], Error> + 'b {
move |input| match take::<TagError>(key.len())(input) {
(rest, Ok(result)) if result == key => (rest, Ok(result)),
(_, Err(x)) => (input, Err(x.into())),
_ => (input, Err(TagError(input).into())),
}
}
pub fn or<'a, Output1, Output2, Error: From<Error2>, Error1, Error2>(
one: impl Fn(&'a [u8]) -> Step<'a, Output1, Error1>,
two: impl Fn(&'a [u8]) -> Step<'a, Output2, Error2>,
) -> impl Fn(&'a [u8]) -> Step<'a, (Option<Output1>, Option<Output2>), Error> {
move |input| {
let (rest, result1) = (one)(input);
let input = if result1.is_ok() { rest } else { input };
let (rest, result2) = (two)(input);
(rest, Ok((result1.ok(), result2.ok())))
}
}
pub fn and<'a, Output1, Output2, Error: From<Error1> + From<Error2>, Error1, Error2>(
one: impl Fn(&'a [u8]) -> Step<'a, Output1, Error1>,
two: impl Fn(&'a [u8]) -> Step<'a, Output2, Error2>,
) -> impl Fn(&'a [u8]) -> Step<'a, (Output1, Output2), Error> {
move |input| {
let before = input;
match (one)(input) {
(rest, Ok(x)) => match (two)(rest) {
(rest, Ok(y)) => (rest, Ok((x, y))),
(_, Err(e)) => (before, Err(e.into())),
},
(_, Err(e)) => (before, Err(e.into())),
}
}
}
#[cfg(feature = "bytemuck")]
use bytemuck::{Pod, PodCastError};
#[cfg(feature = "bytemuck")]
pub struct PodError<'a> {
pub at: &'a [u8],
pub pod_error: PodCastError,
}
#[cfg(feature = "bytemuck")]
pub fn pod<'a, Output: Pod, Error: From<PodError<'a>>>(
input: &'a [u8],
) -> Step<'a, &'a Output, Error> {
let (rest, bytes) = input.split_at(core::mem::size_of::<Output>());
match bytemuck::try_from_bytes(bytes) {
Ok(x) => (rest, Ok(x)),
Err(pod_error) => (
input,
Err(PodError {
at: input,
pod_error,
}
.into()),
),
}
}
macro_rules! num_impl {
(
$(#[$m:meta])*
$num_ty:ty, $endian_fn:ident, $fn_name:ident, $err_name:ident;
$($rest:tt)*
) => {
pub struct $err_name<'a>(&'a [u8]);
$(#[$m])*
pub fn $fn_name<'a, Error: From<$err_name<'a>>>(
input: &'a [u8]
) -> Step<'a, $num_ty, $err_name> {
let (out, rest) = input.split_at(core::mem::size_of::<$num_ty>());
let out = match out.try_into() {
Ok(x) => x,
Err(_) => return (input, Err($err_name(input).into())),
};
(rest, Ok(<$num_ty>::$endian_fn(out)))
}
num_impl! { $($rest)* }
};
() => {}
}
num_impl! {
u16, from_le_bytes, u16l, U16LError;
i16, from_le_bytes, i16l, I16LError;
u16, from_be_bytes, u16b, U16BError;
i16, from_be_bytes, i16b, I16BError;
u32, from_le_bytes, u32l, U32LError;
i32, from_le_bytes, i32l, I32LError;
u32, from_be_bytes, u32b, U32BError;
i32, from_be_bytes, i32b, I32BError;
u64, from_le_bytes, u64l, U64LError;
i64, from_le_bytes, i64l, I64LError;
u64, from_be_bytes, u64b, U64BError;
i64, from_be_bytes, i64b, I64BError;
u128, from_le_bytes, u128l, U128LError;
i128, from_le_bytes, i128l, I128LError;
u128, from_be_bytes, u128b, U128BError;
i128, from_be_bytes, i128b, I128BError;
f32, from_le_bytes, f32l, F32LError;
f32, from_be_bytes, f32b, F32BError;
f64, from_le_bytes, f64l, F64LError;
f64, from_be_bytes, f64b, F64BError;
}