use crate::{
blocks::{
extended::ExtendedNavigationBlock, external::ExternalBlock, navigation::NavigationBlock,
},
header::{InputHeader, OutputHeader},
};
pub mod extended;
pub mod external;
pub mod navigation;
pub(crate) fn read_be<T: for<'a> binrw::BinRead<Args<'a> = ()>>(
cursor: &mut std::io::Cursor<&[u8]>,
) -> crate::error::Result<T> {
T::read_be(cursor).map_err(crate::error::Error::InvalidBlock)
}
pub(crate) fn parse_blocks<B>(
bitmask: u32,
num_bits: u32,
mut read_fn: impl FnMut(u32) -> crate::error::Result<Option<B>>,
) -> crate::error::Result<Vec<B>> {
(0..num_bits)
.filter(|&bit| bitmask & (1 << bit) != 0)
.filter_map(|bit| read_fn(bit).transpose())
.collect()
}
macro_rules! block_enum {
(
$(#[$meta:meta])*
pub enum $name:ident {
$(
$bit:literal $(if $guard:expr)? => $variant:ident($inner:ty, $size:literal)
),* $(,)?
}
read_fn($($rp:ident: $rpt:ty),*);
) => {
$(#[$meta])*
#[derive(Debug, Clone, serde::Serialize)]
pub enum $name {
$($variant($inner),)*
}
impl $name {
pub fn bit(&self) -> u32 {
match self {
$(Self::$variant(_) => $bit,)*
}
}
pub fn size(&self) -> usize {
match self {
$(Self::$variant(_) => $size,)*
}
}
pub fn read(bit: u32, $($rp: $rpt,)* cursor: &mut std::io::Cursor<&[u8]>) -> $crate::error::Result<Self> {
match bit {
$($bit $(if $guard)? => Ok(Self::$variant($crate::blocks::read_be(cursor)?)),)*
_ => Err($crate::error::Error::InvalidBlock(
binrw::Error::AssertFail {
pos: cursor.position(),
message: format!("unknown {} bit {bit}", stringify!($name)),
}
)),
}
}
pub fn bitmask(blocks: &[Self]) -> u32 {
blocks.iter().fold(0u32, |mask, b| mask | (1 << b.bit()))
}
}
};
}
pub(crate) use block_enum;
#[derive(Debug, Clone)]
pub struct NavigationDataFrame {
pub header: OutputHeader,
pub navigation: Vec<NavigationBlock>,
pub extended_navigation: Vec<ExtendedNavigationBlock>,
pub external: Vec<ExternalBlock>,
}
#[derive(Debug, Clone)]
pub struct InputDataFrame {
pub header: InputHeader,
pub external: Vec<ExternalBlock>,
}
#[derive(Debug, Clone)]
pub enum Message {
NavigationData(NavigationDataFrame),
InputData(InputDataFrame),
Command(Vec<u8>),
Answer(Vec<u8>),
}