#[cfg(feature = "bus-impl")]
mod body;
mod byte_order;
mod error;
mod fields;
mod primary_header;
mod quick_fields;
#[cfg(test)]
mod tests;
#[cfg(feature = "bus-impl")]
pub(crate) use body::validate as validate_body;
pub(crate) use quick_fields::QuickFields;
use winnow::{LocatingSlice, Parser, binary::length_and_then};
use crate::{
Error, Result,
message::{PrimaryHeader, header::MIN_MESSAGE_SIZE},
};
use byte_order::{BigEndian, ByteOrder, LittleEndian};
use error::ParseError;
use fields::fields;
use primary_header::primary_header;
pub(crate) fn parse(bytes: &[u8]) -> Result<(PrimaryHeader, usize, QuickFields)> {
let input = &mut Input::new(bytes);
let header = match bytes.first() {
Some(b'l') => header::<LittleEndian>(input),
Some(b'B') => header::<BigEndian>(input),
Some(_) => Err(ParseError::Endian),
None => Err(ParseError::Truncated),
};
if let Ok((_, _, fields)) = &header
&& fields.repeated()
{
return Err(ParseError::Field.into());
}
header.map_err(Error::from)
}
pub(super) fn parse_primary_header(bytes: &[u8]) -> Result<(PrimaryHeader, u32)> {
let input = &mut Input::new(bytes);
match bytes.first() {
Some(b'l') => (primary_header::<LittleEndian>, LittleEndian::u32).parse_next(input),
Some(b'B') => (primary_header::<BigEndian>, BigEndian::u32).parse_next(input),
Some(_) => Err(ParseError::Endian),
None => Err(ParseError::Truncated),
}
.map_err(Error::from)
}
fn header<O: ByteOrder>(input: &mut Input<'_>) -> PResult<(PrimaryHeader, usize, QuickFields)> {
(
primary_header::<O>,
length_and_then(fields_len::<O>, fields::<O>),
)
.with_span()
.map(|((primary_header, fields), span)| (primary_header, span.end, fields))
.parse_next(input)
}
fn fields_len<O: ByteOrder>(input: &mut Input<'_>) -> PResult<u32> {
O::u32
.try_map(|len| match len.checked_add(MIN_MESSAGE_SIZE as u32) {
Some(_) => Ok(len),
None => Err(ParseError::TooLarge),
})
.parse_next(input)
}
type Input<'i> = LocatingSlice<&'i [u8]>;
type PResult<T> = std::result::Result<T, ParseError>;