use broadcast_common::{Parse, Serialize};
macro_rules! declare_segments {
(
$lt:lifetime;
$( $variant:ident = $seg_type:literal => $($path:ident)::+ $(<$plt:lifetime>)? ),+ $(,)?
) => {
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
#[non_exhaustive]
pub enum AnySegment<$lt> {
$(
#[allow(missing_docs)]
$variant($($path)::+ $(<$plt>)?),
)+
Unknown {
segment_type: u8,
page_id: u16,
data: &$lt [u8],
},
}
$(
impl<$lt> From<$($path)::+ $(<$plt>)?> for AnySegment<$lt> {
fn from(s: $($path)::+ $(<$plt>)?) -> Self {
Self::$variant(s)
}
}
)+
impl<$lt> AnySegment<$lt> {
pub const DISPATCHED_SEGMENT_TYPES: &'static [u8] = &[$($seg_type),+];
#[must_use]
pub fn name(&self) -> &'static str {
match self {
$(
Self::$variant(_) =>
<$($path)::+ as crate::traits::SegmentDef>::NAME,
)+
Self::Unknown { .. } => "UNKNOWN",
}
}
pub(crate) fn dispatch(segment_type: u8, full: &$lt [u8]) -> Option<crate::Result<Self>> {
match segment_type {
$(
$seg_type => Some(<$($path)::+>::parse(full).map(Self::$variant)),
)+
_ => None,
}
}
pub(crate) fn serialized_len(&self) -> usize {
match self {
$(
Self::$variant(s) => s.serialized_len(),
)+
Self::Unknown { data, .. } => (6 + data.len()),
}
}
pub(crate) fn serialize_into(&self, buf: &mut [u8]) -> crate::Result<usize> {
match self {
$(
Self::$variant(s) => s.serialize_into(buf),
)+
Self::Unknown { segment_type, page_id, data } => {
let len = 6 + data.len();
if buf.len() < len {
return Err(crate::error::Error::BufferTooShort {
need: len,
have: buf.len(),
what: "Unknown segment serialize",
});
}
buf[0] = 0x0F;
buf[1] = *segment_type;
buf[2..4].copy_from_slice(&page_id.to_be_bytes());
let seg_len = data.len() as u16;
buf[4..6].copy_from_slice(&seg_len.to_be_bytes());
buf[6..len].copy_from_slice(data);
Ok(len)
}
}
}
}
#[cfg(test)]
mod macro_drift {
#[test]
fn segment_type_literals_match_segment_def() {
use crate::traits::SegmentDef;
$(
assert_eq!(
$seg_type,
<$($path)::+ as SegmentDef>::SEGMENT_TYPE,
concat!("segment_type literal drift for ", stringify!($variant)),
);
assert!(
!<$($path)::+ as SegmentDef>::NAME.is_empty(),
concat!("empty NAME for ", stringify!($variant)),
);
)+
}
}
};
}
declare_segments! {'a;
PageComposition = 0x10 => crate::segments::page_composition::PageCompositionSegment,
RegionComposition = 0x11 => crate::segments::region_composition::RegionCompositionSegment,
ClutDefinition = 0x12 => crate::segments::clut_definition::ClutDefinitionSegment,
ObjectData = 0x13 => crate::segments::object_data::ObjectDataSegment<'a>,
DisplayDefinition = 0x14 => crate::segments::display_definition::DisplayDefinitionSegment,
DisparitySignalling = 0x15 => crate::segments::disparity_signalling::DisparitySignallingSegment,
AlternativeClut = 0x16 => crate::segments::alternative_clut::AlternativeClutSegment,
EndOfDisplaySet = 0x80 => crate::segments::end_of_display_set::EndOfDisplaySetSegment,
Stuffing = 0xFF => crate::segments::stuffing::StuffingSegment<'a>,
}