pub const ID_EBU_TELETEXT_NON_SUBTITLE: u8 = 0x02;
pub const ID_EBU_TELETEXT_SUBTITLE: u8 = 0x03;
pub const ID_INVERTED_TELETEXT: u8 = 0xC0;
pub const ID_VPS: u8 = 0xC3;
pub const ID_WSS: u8 = 0xC4;
pub const ID_CLOSED_CAPTIONING: u8 = 0xC5;
pub const ID_MONOCHROME_422_SAMPLES: u8 = 0xC6;
pub const ID_STUFFING: u8 = 0xFF;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub enum DataUnitId {
EbuTeletextNonSubtitle,
EbuTeletextSubtitle,
InvertedTeletext,
Vps,
Wss,
ClosedCaptioning,
Monochrome422Samples,
Stuffing,
Reserved(u8),
UserDefined(u8),
}
impl DataUnitId {
pub fn from_u8(raw: u8) -> Self {
match raw {
ID_EBU_TELETEXT_NON_SUBTITLE => DataUnitId::EbuTeletextNonSubtitle,
ID_EBU_TELETEXT_SUBTITLE => DataUnitId::EbuTeletextSubtitle,
ID_INVERTED_TELETEXT => DataUnitId::InvertedTeletext,
ID_VPS => DataUnitId::Vps,
ID_WSS => DataUnitId::Wss,
ID_CLOSED_CAPTIONING => DataUnitId::ClosedCaptioning,
ID_MONOCHROME_422_SAMPLES => DataUnitId::Monochrome422Samples,
ID_STUFFING => DataUnitId::Stuffing,
0x80..=0xBF => DataUnitId::UserDefined(raw),
other => DataUnitId::Reserved(other),
}
}
pub fn to_u8(self) -> u8 {
match self {
DataUnitId::EbuTeletextNonSubtitle => ID_EBU_TELETEXT_NON_SUBTITLE,
DataUnitId::EbuTeletextSubtitle => ID_EBU_TELETEXT_SUBTITLE,
DataUnitId::InvertedTeletext => ID_INVERTED_TELETEXT,
DataUnitId::Vps => ID_VPS,
DataUnitId::Wss => ID_WSS,
DataUnitId::ClosedCaptioning => ID_CLOSED_CAPTIONING,
DataUnitId::Monochrome422Samples => ID_MONOCHROME_422_SAMPLES,
DataUnitId::Stuffing => ID_STUFFING,
DataUnitId::Reserved(v) => v,
DataUnitId::UserDefined(v) => v,
}
}
pub fn name(&self) -> &'static str {
match self {
DataUnitId::EbuTeletextNonSubtitle => "EBU Teletext non-subtitle data",
DataUnitId::EbuTeletextSubtitle => "EBU Teletext subtitle data",
DataUnitId::InvertedTeletext => "Inverted Teletext",
DataUnitId::Vps => "VPS",
DataUnitId::Wss => "WSS",
DataUnitId::ClosedCaptioning => "Closed Captioning",
DataUnitId::Monochrome422Samples => "monochrome 4:2:2 samples",
DataUnitId::Stuffing => "stuffing",
DataUnitId::Reserved(_) => "reserved",
DataUnitId::UserDefined(_) => "user defined",
}
}
}
broadcast_common::impl_spec_display!(DataUnitId, Reserved, UserDefined);
#[cfg(test)]
mod tests {
use super::*;
use alloc::string::ToString;
#[test]
fn all_u8_round_trip() {
for raw in 0u16..=0xFF {
let raw = raw as u8;
assert_eq!(DataUnitId::from_u8(raw).to_u8(), raw, "raw={raw:#04X}");
}
}
#[test]
fn c1_is_reserved_not_teletext() {
assert_eq!(DataUnitId::from_u8(0xC1), DataUnitId::Reserved(0xC1));
assert_eq!(DataUnitId::from_u8(0xC2), DataUnitId::Reserved(0xC2));
}
#[test]
fn ranges() {
assert_eq!(DataUnitId::from_u8(0x00), DataUnitId::Reserved(0x00));
assert_eq!(DataUnitId::from_u8(0x7F), DataUnitId::Reserved(0x7F));
assert_eq!(DataUnitId::from_u8(0x80), DataUnitId::UserDefined(0x80));
assert_eq!(DataUnitId::from_u8(0xBF), DataUnitId::UserDefined(0xBF));
assert_eq!(DataUnitId::from_u8(0xC7), DataUnitId::Reserved(0xC7));
assert_eq!(DataUnitId::from_u8(0xFE), DataUnitId::Reserved(0xFE));
}
#[test]
fn display_is_lossless_for_byte_bearing() {
assert_eq!(DataUnitId::Reserved(0xC1).to_string(), "reserved(0xC1)");
assert_eq!(
DataUnitId::UserDefined(0x90).to_string(),
"user defined(0x90)"
);
assert_eq!(DataUnitId::Vps.to_string(), "VPS");
}
}