macro_rules! declare_tables {
(
$lt:lifetime;
$( $variant:ident = [ $( $lo:literal ..= $hi:literal ),+ ] => $($path:ident)::+ $(<$plt:lifetime>)? ),+ $(,)?
$( ; @no_dispatch $( $nd_variant:ident => $($nd_path:ident)::+ $(<$nd_plt:lifetime>)? ),+ $(,)? )?
) => {
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
#[non_exhaustive]
pub enum AnyTable<$lt> {
$(
#[allow(missing_docs)]
$variant($($path)::+ $(<$plt>)?),
)+
$($(
#[allow(missing_docs)]
$nd_variant($($nd_path)::+ $(<$nd_plt>)?),
)+)?
Unknown {
table_id: u8,
raw: &$lt [u8],
},
}
$(
impl<$lt> From<$($path)::+ $(<$plt>)?> for AnyTable<$lt> {
fn from(t: $($path)::+ $(<$plt>)?) -> Self {
Self::$variant(t)
}
}
)+
$($(
impl<$lt> From<$($nd_path)::+ $(<$nd_plt>)?> for AnyTable<$lt> {
fn from(t: $($nd_path)::+ $(<$nd_plt>)?) -> Self {
Self::$nd_variant(t)
}
}
)+)?
impl<$lt> AnyTable<$lt> {
pub const DISPATCHED_RANGES: &'static [(u8, u8)] =
&[$( $( ($lo, $hi) ),+ ),+];
#[must_use]
pub fn name(&self) -> &'static str {
match self {
$(
Self::$variant(_) =>
<$($path)::+ as crate::traits::TableDef>::NAME,
)+
$($(
Self::$nd_variant(_) =>
<$($nd_path)::+ as crate::traits::TableDef>::NAME,
)+)?
Self::Unknown { .. } => "UNKNOWN",
}
}
pub fn parse(bytes: &$lt [u8]) -> crate::Result<Self> {
let table_id = *bytes.first().ok_or(crate::Error::BufferTooShort {
need: 1,
have: 0,
what: "section table_id",
})?;
match table_id {
$(
$( $lo..=$hi )|+ => {
<$($path)::+ as dvb_common::Parse>::parse(bytes).map(Self::$variant)
}
)+
_ => Ok(Self::Unknown { table_id, raw: bytes }),
}
}
pub fn parse_as<T>(bytes: &$lt [u8]) -> crate::Result<T>
where
T: crate::traits::TableDef<$lt>,
{
<T as dvb_common::Parse>::parse(bytes)
}
}
#[cfg(test)]
mod macro_drift {
#[test]
fn ranges_match_tabledef() {
use crate::traits::TableDef;
$(
assert_eq!(
&[ $( ($lo, $hi) ),+ ][..],
<$($path)::+ as TableDef>::TABLE_ID_RANGES,
concat!("TABLE_ID_RANGES drift for ", stringify!($variant)),
);
assert!(
!<$($path)::+ as TableDef>::NAME.is_empty(),
concat!("empty NAME for ", stringify!($variant)),
);
)+
$($(
assert!(
!<$($nd_path)::+ as TableDef>::NAME.is_empty(),
concat!("empty NAME for no-dispatch ", stringify!($nd_variant)),
);
)+)?
}
#[test]
fn dispatched_ranges_are_disjoint() {
let mut ranges: Vec<(u8, u8)> = vec![
$( $( ($lo, $hi), )+ )+
];
ranges.sort_by_key(|r| r.0);
for w in ranges.windows(2) {
let (_, prev_hi) = w[0];
let (next_lo, _) = w[1];
assert!(
next_lo > prev_hi,
"overlapping dispatch ranges: {w:?}",
);
}
}
}
};
}
declare_tables! {'a;
Pat = [0x00..=0x00] => crate::tables::pat::Pat,
Cat = [0x01..=0x01] => crate::tables::cat::Cat<'a>,
Pmt = [0x02..=0x02] => crate::tables::pmt::Pmt<'a>,
Tsdt = [0x03..=0x03] => crate::tables::tsdt::Tsdt<'a>,
DsmccSection = [0x3A..=0x3F] => crate::tables::dsmcc::DsmccSection<'a>,
Nit = [0x40..=0x41] => crate::tables::nit::Nit<'a>,
Sdt = [0x42..=0x42, 0x46..=0x46] => crate::tables::sdt::Sdt<'a>,
Bat = [0x4A..=0x4A] => crate::tables::bat::Bat<'a>,
Unt = [0x4B..=0x4B] => crate::tables::unt::Unt<'a>,
Int = [0x4C..=0x4C] => crate::tables::int::Int<'a>,
Sat = [0x4D..=0x4D] => crate::tables::sat::Sat<'a>,
Eit = [0x4E..=0x6F] => crate::tables::eit::Eit<'a>,
Tdt = [0x70..=0x70] => crate::tables::tdt::Tdt,
Rst = [0x71..=0x71] => crate::tables::rst::Rst,
St = [0x72..=0x72] => crate::tables::st::St,
Tot = [0x73..=0x73] => crate::tables::tot::Tot<'a>,
Ait = [0x74..=0x74] => crate::tables::ait::Ait<'a>,
Container = [0x75..=0x75] => crate::tables::container::Container<'a>,
Rct = [0x76..=0x76] => crate::tables::rct::Rct<'a>,
Cit = [0x77..=0x77] => crate::tables::cit::Cit<'a>,
MpeFec = [0x78..=0x78] => crate::tables::mpe_fec::MpeFec<'a>,
Rnt = [0x79..=0x79] => crate::tables::rnt::Rnt<'a>,
MpeIfec = [0x7A..=0x7A] => crate::tables::mpe_ifec::MpeIfec<'a>,
ProtectionMessage = [0x7B..=0x7B] => crate::tables::protection_message::ProtectionMessageSection<'a>,
DownloadableFontInfo = [0x7C..=0x7C] => crate::tables::downloadable_font_info::DownloadableFontInfoSection<'a>,
Dit = [0x7E..=0x7E] => crate::tables::dit::Dit,
Sit = [0x7F..=0x7F] => crate::tables::sit::Sit<'a>;
@no_dispatch
MpeDatagram => crate::tables::mpe::MpeDatagramSection<'a>,
}