use core::{
fmt::{self, Debug},
ops::Deref,
};
use tlf::TypeLengthField;
pub mod common;
#[cfg(feature = "alloc")]
pub mod complete;
mod num;
mod octet_string;
pub mod streaming;
mod tlf;
pub use tlf::TlfParseError;
pub use octet_string::OctetStr;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ParseError {
LeftoverInput,
UnexpectedEOF,
InvalidTlf(TlfParseError),
TlfMismatch(&'static str),
CrcMismatch,
MsgEndMismatch,
UnexpectedVariant,
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<Self as Debug>::fmt(self, f)
}
}
#[cfg(feature = "std")]
impl std::error::Error for ParseError {}
type ResTy<'i, O> = Result<(&'i [u8], O), ParseError>;
#[allow(dead_code)]
type ResTyComplete<'i, O> = Result<O, ParseError>;
pub(crate) trait SmlParse<'i>
where
Self: Sized,
{
fn parse(input: &'i [u8]) -> ResTy<Self>;
fn parse_complete(input: &'i [u8]) -> ResTyComplete<Self> {
let (input, x) = Self::parse(input)?;
if !input.is_empty() {
return Err(ParseError::LeftoverInput);
}
Ok(x)
}
}
pub(crate) trait SmlParseTlf<'i>
where
Self: Sized,
{
fn check_tlf(tlf: &TypeLengthField) -> bool;
fn parse_with_tlf(input: &'i [u8], tlf: &TypeLengthField) -> ResTy<'i, Self>;
}
impl<'i, T: SmlParseTlf<'i>> SmlParse<'i> for T {
fn parse(input: &'i [u8]) -> ResTy<Self> {
let (input, tlf) = TypeLengthField::parse(input)?;
if !Self::check_tlf(&tlf) {
return Err(ParseError::TlfMismatch(core::any::type_name::<Self>()));
}
Self::parse_with_tlf(input, &tlf)
}
}
impl<'i, T: SmlParse<'i>> SmlParse<'i> for Option<T> {
fn parse(input: &'i [u8]) -> ResTy<Self> {
if let Some(0x01u8) = input.first() {
Ok((&input[1..], None))
} else {
let (input, x) = T::parse(input)?;
Ok((input, Some(x)))
}
}
}
fn take_byte(input: &[u8]) -> ResTy<u8> {
if input.is_empty() {
return Err(ParseError::UnexpectedEOF);
}
Ok((&input[1..], input[0]))
}
fn take<const N: usize>(input: &[u8]) -> ResTy<&[u8; N]> {
if input.len() < N {
return Err(ParseError::UnexpectedEOF);
}
Ok((&input[N..], input[..N].try_into().unwrap()))
}
fn take_n(input: &[u8], n: usize) -> ResTy<&[u8]> {
if input.len() < n {
return Err(ParseError::UnexpectedEOF);
}
Ok((&input[n..], &input[..n]))
}
fn map<O1, O2>(val: ResTy<O1>, mut f: impl FnMut(O1) -> O2) -> ResTy<O2> {
val.map(|(input, x)| (input, f(x)))
}
struct OctetStrFormatter<'i>(&'i [u8]);
impl<'i> Debug for OctetStrFormatter<'i> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self.0)
}
}
struct NumberFormatter<T: Debug, U: Deref<Target = T>>(U);
impl<T: Debug, U: Deref<Target = T>> Debug for NumberFormatter<T, U> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}{}", self.0.deref(), core::any::type_name::<T>())
}
}