use alloc::boxed::Box;
use alloc::collections::BTreeMap;
use core::any::Any;
use crate::descriptors::any::AnyDescriptor;
use crate::descriptors::private_data_specifier::PDS_NORDIG;
#[cfg(not(feature = "serde"))]
pub trait DescriptorObject: core::fmt::Debug + Any + Send + Sync {
fn as_any(&self) -> &dyn Any;
}
#[cfg(feature = "serde")]
pub trait DescriptorObject: core::fmt::Debug + Any + Send + Sync + erased_serde::Serialize {
fn as_any(&self) -> &dyn Any;
}
#[cfg(not(feature = "serde"))]
impl<T> DescriptorObject for T
where
T: core::fmt::Debug + Any + Send + Sync,
{
fn as_any(&self) -> &dyn Any {
self
}
}
#[cfg(feature = "serde")]
impl<T> DescriptorObject for T
where
T: core::fmt::Debug + Any + Send + Sync + serde::Serialize,
{
fn as_any(&self) -> &dyn Any {
self
}
}
impl dyn DescriptorObject {
#[must_use]
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
self.as_any().downcast_ref::<T>()
}
#[must_use]
pub fn is<T: Any>(&self) -> bool {
self.as_any().is::<T>()
}
}
#[cfg(feature = "serde")]
#[allow(clippy::borrowed_box)]
pub(crate) fn serialize_erased<S: serde::Serializer>(
v: &Box<dyn DescriptorObject>,
s: S,
) -> Result<S::Ok, S::Error> {
erased_serde::serialize(&**v, s)
}
pub(crate) type CustomParse =
Box<dyn for<'a> Fn(&'a [u8]) -> crate::Result<Box<dyn DescriptorObject>> + Send + Sync>;
#[derive(Default)]
pub struct DescriptorRegistry {
custom: BTreeMap<(Option<u32>, u8), CustomParse>,
logical_channel: bool,
logical_channel_pds: alloc::collections::BTreeSet<u32>,
}
impl DescriptorRegistry {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn register<T>(&mut self) -> &mut Self
where
T: for<'a> crate::traits::DescriptorDef<'a> + DescriptorObject + 'static,
{
let tag = <T as crate::traits::DescriptorDef<'static>>::TAG;
self.custom.insert(
(None, tag),
Box::new(|b| {
Ok(Box::new(<T as broadcast_common::Parse>::parse(b)?)
as Box<dyn DescriptorObject>)
}),
);
self
}
pub fn register_for_pds<T>(&mut self, pds: u32) -> &mut Self
where
T: for<'a> crate::traits::DescriptorDef<'a> + DescriptorObject + 'static,
{
let tag = <T as crate::traits::DescriptorDef<'static>>::TAG;
self.custom.insert(
(Some(pds), tag),
Box::new(|b| {
Ok(Box::new(<T as broadcast_common::Parse>::parse(b)?)
as Box<dyn DescriptorObject>)
}),
);
self
}
pub fn with_logical_channel(&mut self) -> &mut Self {
self.logical_channel = true;
self
}
pub fn with_logical_channel_for_pds(&mut self, pds: u32) -> &mut Self {
self.logical_channel_pds.insert(pds);
self
}
pub fn with_nordig_lcn(&mut self) -> &mut Self {
self.register_for_pds::<crate::descriptors::nordig::NordigLogicalChannelV1>(PDS_NORDIG);
self.register_for_pds::<crate::descriptors::nordig::NordigLogicalChannelV2>(PDS_NORDIG);
self
}
pub fn with_avs3_audio(&mut self) -> &mut Self {
self.register_for_pds::<crate::descriptors::avs3_audio::Avs3AudioDescriptor>(
crate::descriptors::PDS_AVSA,
);
self
}
pub fn with_avs3_video(&mut self) -> &mut Self {
self.register_for_pds::<crate::descriptors::avs3_video::Avs3VideoDescriptor>(
crate::descriptors::PDS_AVSV,
);
self
}
pub fn with_avs2_video(&mut self) -> &mut Self {
self.register_for_pds::<crate::descriptors::avs2_video::Avs2VideoDescriptor>(
crate::descriptors::PDS_AVSV,
);
self
}
pub fn with_avs2_audio(&mut self) -> &mut Self {
self.register_for_pds::<crate::descriptors::avs2_audio::Avs2AudioDescriptor>(
crate::descriptors::PDS_AVSA,
);
self
}
pub fn with_tuwa_avs3_video(&mut self) -> &mut Self {
self.register::<crate::descriptors::tuwa_avs3_video::TuwaAvs3VideoDescriptor>()
}
pub fn with_china_caption_service(&mut self) -> &mut Self {
self.register::<crate::descriptors::china_caption_service::ChinaCaptionServiceDescriptor>()
}
pub fn with_atsc_caption_service(&mut self) -> &mut Self {
self.register::<crate::descriptors::atsc_caption_service::AtscCaptionServiceDescriptor>()
}
#[must_use]
pub fn parse_loop<'r, 'a>(&'r self, bytes: &'a [u8]) -> RegistryIter<'r, 'a> {
RegistryIter {
registry: self,
bytes,
pos: 0,
fused: false,
current_pds: None,
}
}
#[must_use]
pub fn parse_loop_in_scope<'r, 'a>(
&'r self,
bytes: &'a [u8],
inherited: Option<u32>,
) -> RegistryIter<'r, 'a> {
RegistryIter {
registry: self,
bytes,
pos: 0,
fused: false,
current_pds: inherited,
}
}
}
pub struct RegistryIter<'r, 'a> {
registry: &'r DescriptorRegistry,
bytes: &'a [u8],
pos: usize,
fused: bool,
current_pds: Option<u32>,
}
pub(crate) fn dispatch_entry<'a>(
registry: &DescriptorRegistry,
current_pds: Option<u32>,
tag: u8,
full: &'a [u8],
) -> crate::Result<AnyDescriptor<'a>> {
if let Some(pds) = current_pds
&& let Some(parse_fn) = registry.custom.get(&(Some(pds), tag))
{
return parse_fn(full).map(|value| AnyDescriptor::Other { tag, value });
}
if let Some(parse_fn) = registry.custom.get(&(None, tag)) {
return parse_fn(full).map(|value| AnyDescriptor::Other { tag, value });
}
if let Some(pds) = current_pds
&& tag == crate::descriptors::logical_channel::TAG
&& registry.logical_channel_pds.contains(&pds)
{
use broadcast_common::Parse;
return crate::descriptors::logical_channel::LogicalChannelDescriptor::parse(full)
.map(AnyDescriptor::LogicalChannel);
}
if registry.logical_channel && tag == crate::descriptors::logical_channel::TAG {
use broadcast_common::Parse;
return crate::descriptors::logical_channel::LogicalChannelDescriptor::parse(full)
.map(AnyDescriptor::LogicalChannel);
}
if let Some(res) = AnyDescriptor::dispatch(tag, full) {
return res;
}
Ok(AnyDescriptor::Unknown {
tag,
body: &full[2..],
})
}
fn update_pds(current: &mut Option<u32>, tag: u8, full: &[u8]) {
if tag == crate::descriptors::registration::TAG {
use broadcast_common::Parse;
if let Ok(reg) = crate::descriptors::registration::RegistrationDescriptor::parse(full) {
let id = u32::from_be_bytes(reg.format_identifier);
if id == crate::descriptors::PDS_AVSA || id == crate::descriptors::PDS_AVSV {
*current = Some(id);
}
}
}
if tag == crate::descriptors::private_data_specifier::TAG {
use broadcast_common::Parse;
if let Ok(pds) =
crate::descriptors::private_data_specifier::PrivateDataSpecifierDescriptor::parse(full)
{
*current = Some(pds.private_data_specifier);
}
}
}
impl RegistryIter<'_, '_> {
#[must_use]
pub fn avs_scope(&self) -> Option<u32> {
self.current_pds
.filter(|p| *p == crate::descriptors::PDS_AVSA || *p == crate::descriptors::PDS_AVSV)
}
}
impl<'a> Iterator for RegistryIter<'_, 'a> {
type Item = crate::Result<AnyDescriptor<'a>>;
fn next(&mut self) -> Option<Self::Item> {
let (tag, full) = match crate::descriptors::any::next_loop_entry(
self.bytes,
&mut self.pos,
&mut self.fused,
)? {
Ok(v) => v,
Err(e) => return Some(Err(e)),
};
update_pds(&mut self.current_pds, tag, full);
Some(dispatch_entry(self.registry, self.current_pds, tag, full))
}
}
impl core::iter::FusedIterator for RegistryIter<'_, '_> {}
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
#[non_exhaustive]
pub enum ExtIterItem<'a> {
Descriptor(AnyDescriptor<'a>),
CustomExtension {
tag_extension: u8,
#[cfg_attr(
feature = "serde",
serde(serialize_with = "super::extension::registry::serialize_erased")
)]
value: Box<dyn super::extension::registry::ExtensionObject>,
},
}
pub struct ExtRegistryIter<'r, 'a> {
desc_reg: &'r DescriptorRegistry,
ext_reg: &'r super::extension::registry::ExtensionRegistry,
bytes: &'a [u8],
pos: usize,
fused: bool,
current_pds: Option<u32>,
}
impl<'r, 'a> ExtRegistryIter<'r, 'a> {
pub(crate) fn new(
desc_reg: &'r DescriptorRegistry,
ext_reg: &'r super::extension::registry::ExtensionRegistry,
bytes: &'a [u8],
inherited: Option<u32>,
) -> Self {
Self {
desc_reg,
ext_reg,
bytes,
pos: 0,
fused: false,
current_pds: inherited,
}
}
#[must_use]
pub fn avs_scope(&self) -> Option<u32> {
self.current_pds
.filter(|p| *p == crate::descriptors::PDS_AVSA || *p == crate::descriptors::PDS_AVSV)
}
}
impl<'a> Iterator for ExtRegistryIter<'_, 'a> {
type Item = crate::Result<ExtIterItem<'a>>;
fn next(&mut self) -> Option<Self::Item> {
let (tag, full) = match crate::descriptors::any::next_loop_entry(
self.bytes,
&mut self.pos,
&mut self.fused,
)? {
Ok(v) => v,
Err(e) => return Some(Err(e)),
};
update_pds(&mut self.current_pds, tag, full);
let len = full.len() - 2;
if tag == crate::descriptors::extension::TAG && len >= 1 {
let tag_extension = full[2];
if self.ext_reg.has_custom(tag_extension) {
return Some(match self.ext_reg.parse_body(tag_extension, &full[3..]) {
Ok(super::extension::registry::RegisteredExtension::Custom {
tag_extension,
value,
}) => Ok(ExtIterItem::CustomExtension {
tag_extension,
value,
}),
Ok(super::extension::registry::RegisteredExtension::Builtin(d)) => {
Ok(ExtIterItem::Descriptor(AnyDescriptor::Extension(d)))
}
Err(e) => Err(e),
});
}
}
Some(
dispatch_entry(self.desc_reg, self.current_pds, tag, full).map(ExtIterItem::Descriptor),
)
}
}
impl core::iter::FusedIterator for ExtRegistryIter<'_, '_> {}
#[cfg(test)]
mod tests {
use super::*;
use crate::descriptors::private_data_specifier;
use crate::descriptors::private_data_specifier::{PDS_EACEM, PDS_NORDIG};
use crate::traits::DescriptorDef;
#[test]
fn pds_constants_match_the_register() {
assert_eq!(
private_data_specifier::private_data_specifier_name(PDS_EACEM),
Some("EACEM/EICTA")
);
assert_eq!(
private_data_specifier::private_data_specifier_name(PDS_NORDIG),
Some("NorDig")
);
}
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
struct PdsEacem {
v: u8,
}
impl<'a> broadcast_common::Parse<'a> for PdsEacem {
type Error = crate::error::Error;
fn parse(bytes: &'a [u8]) -> crate::Result<Self> {
if bytes.len() < 3 {
return Err(crate::error::Error::BufferTooShort {
need: 3,
have: bytes.len(),
what: "PdsEacem",
});
}
Ok(Self { v: bytes[2] })
}
}
impl DescriptorDef<'_> for PdsEacem {
const TAG: u8 = 0x83;
const NAME: &'static str = "PDS_EACEM";
}
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
struct PdsNordig {
w: u8,
}
impl<'a> broadcast_common::Parse<'a> for PdsNordig {
type Error = crate::error::Error;
fn parse(bytes: &'a [u8]) -> crate::Result<Self> {
if bytes.len() < 3 {
return Err(crate::error::Error::BufferTooShort {
need: 3,
have: bytes.len(),
what: "PdsNordig",
});
}
Ok(Self { w: bytes[2] })
}
}
impl DescriptorDef<'_> for PdsNordig {
const TAG: u8 = 0x83;
const NAME: &'static str = "PDS_NORDIG";
}
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
struct PdsAgnostic {
z: u8,
}
impl<'a> broadcast_common::Parse<'a> for PdsAgnostic {
type Error = crate::error::Error;
fn parse(bytes: &'a [u8]) -> crate::Result<Self> {
if bytes.len() < 3 {
return Err(crate::error::Error::BufferTooShort {
need: 3,
have: bytes.len(),
what: "PdsAgnostic",
});
}
Ok(Self { z: bytes[2] })
}
}
impl DescriptorDef<'_> for PdsAgnostic {
const TAG: u8 = 0x84;
const NAME: &'static str = "PDS_AGNOSTIC";
}
fn pds_descriptor(pds: u32) -> Vec<u8> {
let mut v = vec![private_data_specifier::TAG, 4];
v.extend_from_slice(&pds.to_be_bytes());
v
}
#[test]
fn pds_scoped_same_tag_resolves_by_pds() {
let mut reg = DescriptorRegistry::new();
reg.register_for_pds::<PdsEacem>(PDS_EACEM);
reg.register_for_pds::<PdsNordig>(PDS_NORDIG);
let mut bytes = Vec::new();
bytes.extend_from_slice(&pds_descriptor(PDS_EACEM));
bytes.extend_from_slice(&[0x83, 0x01, 0xAA]);
let items: Vec<_> = reg.parse_loop(&bytes).collect::<Result<_, _>>().unwrap();
assert_eq!(items.len(), 2);
assert!(matches!(items[0], AnyDescriptor::PrivateDataSpecifier(_)));
match &items[1] {
AnyDescriptor::Other { tag, value } => {
assert_eq!(*tag, 0x83);
let c = value.downcast_ref::<PdsEacem>().unwrap();
assert_eq!(c.v, 0xAA);
}
other => panic!("expected Other (PdsEacem), got {other:?}"),
}
let mut bytes2 = Vec::new();
bytes2.extend_from_slice(&pds_descriptor(PDS_NORDIG));
bytes2.extend_from_slice(&[0x83, 0x01, 0xBB]);
let items2: Vec<_> = reg.parse_loop(&bytes2).collect::<Result<_, _>>().unwrap();
match &items2[1] {
AnyDescriptor::Other { tag, value } => {
assert_eq!(*tag, 0x83);
let c = value.downcast_ref::<PdsNordig>().unwrap();
assert_eq!(c.w, 0xBB);
}
other => panic!("expected Other (PdsNordig), got {other:?}"),
}
}
#[test]
fn pds_scoped_does_not_match_wrong_pds() {
let mut reg = DescriptorRegistry::new();
reg.register_for_pds::<PdsEacem>(PDS_EACEM);
let mut bytes = Vec::new();
bytes.extend_from_slice(&pds_descriptor(PDS_NORDIG));
bytes.extend_from_slice(&[0x83, 0x01, 0xCC]);
let items: Vec<_> = reg.parse_loop(&bytes).collect::<Result<_, _>>().unwrap();
assert_eq!(items.len(), 2);
assert!(matches!(items[0], AnyDescriptor::PrivateDataSpecifier(_)));
match &items[1] {
AnyDescriptor::Unknown { tag, .. } => assert_eq!(*tag, 0x83),
other => panic!("expected Unknown (wrong PDS), got {other:?}"),
}
}
#[test]
fn avs2_and_tuwa_descriptors_are_scoped() {
use crate::descriptors::avs2_audio::Avs2AudioDescriptor;
use crate::descriptors::avs2_video::Avs2VideoDescriptor;
use crate::descriptors::private_data_specifier::{PDS_AVSA, PDS_AVSV};
use crate::descriptors::tuwa_avs3_video::TuwaAvs3VideoDescriptor;
let mut reg = DescriptorRegistry::new();
reg.with_avs2_video()
.with_avs2_audio()
.with_tuwa_avs3_video();
let v = [0x40, 5, 0x20, 0x42, 0x00, 0xA9, 0x5F];
let items: Vec<_> = reg.parse_loop(&v).collect::<Result<_, _>>().unwrap();
assert!(matches!(items[0], AnyDescriptor::NetworkName(_)));
let mut b = vec![0x05, 4, b'A', b'V', b'S', b'V'];
b.extend_from_slice(&v);
let items: Vec<_> = reg.parse_loop(&b).collect::<Result<_, _>>().unwrap();
match &items[1] {
AnyDescriptor::Other { tag: 0x40, value } => {
assert!(value.downcast_ref::<Avs2VideoDescriptor>().is_some());
}
other => panic!("expected Avs2Video, got {other:?}"),
}
let mut b = pds_descriptor(PDS_AVSV);
b.extend_from_slice(&v);
let items: Vec<_> = reg.parse_loop(&b).collect::<Result<_, _>>().unwrap();
assert!(matches!(items[1], AnyDescriptor::Other { tag: 0x40, .. }));
let a = [0xD3, 2, 6, 0x20];
let mut b = vec![0x05, 4, b'A', b'V', b'S', b'A'];
b.extend_from_slice(&a);
let items: Vec<_> = reg.parse_loop(&b).collect::<Result<_, _>>().unwrap();
match &items[1] {
AnyDescriptor::Other { tag: 0xD3, value } => {
assert!(value.downcast_ref::<Avs2AudioDescriptor>().is_some());
}
other => panic!("expected Avs2Audio, got {other:?}"),
}
let mut b = pds_descriptor(PDS_AVSA);
b.extend_from_slice(&a);
assert!(matches!(
reg.parse_loop(&b).collect::<Result<Vec<_>, _>>().unwrap()[1],
AnyDescriptor::Other { tag: 0xD3, .. }
));
let items: Vec<_> = reg.parse_loop(&a).collect::<Result<_, _>>().unwrap();
assert!(matches!(items[0], AnyDescriptor::Unknown { tag: 0xD3, .. }));
let t = [62, 7, 0x22, 0x42, 0xAA, 0x4F, 9, 14, 9];
let items: Vec<_> = reg.parse_loop(&t).collect::<Result<_, _>>().unwrap();
match &items[0] {
AnyDescriptor::Other { tag: 62, value } => {
assert!(value.downcast_ref::<TuwaAvs3VideoDescriptor>().is_some());
}
other => panic!("expected TuwaAvs3Video, got {other:?}"),
}
let plain = DescriptorRegistry::new();
let items: Vec<_> = plain.parse_loop(&t).collect::<Result<_, _>>().unwrap();
assert!(matches!(items[0], AnyDescriptor::Unknown { tag: 62, .. }));
}
#[test]
fn program_info_registration_scopes_es_info_descriptors() {
use crate::descriptors::avs3_video::Avs3VideoDescriptor;
use crate::descriptors::private_data_specifier::PDS_AVSV;
let program_info = [0x05, 4, b'A', b'V', b'S', b'V'];
let es_info = [0xD1, 8, 0x22, 0x42, 0xAA, 0x4B, 9, 14, 9, 0xFF];
let mut reg = DescriptorRegistry::new();
reg.with_avs3_video();
let items: Vec<_> = reg.parse_loop(&es_info).collect::<Result<_, _>>().unwrap();
assert!(matches!(items[0], AnyDescriptor::Unknown { tag: 0xD1, .. }));
let mut pi = reg.parse_loop(&program_info);
assert_eq!(pi.avs_scope(), None, "no entry consumed yet");
for item in pi.by_ref() {
item.unwrap();
}
let scope = pi.avs_scope();
assert_eq!(scope, Some(PDS_AVSV));
let items: Vec<_> = reg
.parse_loop_in_scope(&es_info, scope)
.collect::<Result<_, _>>()
.unwrap();
match &items[0] {
AnyDescriptor::Other { tag: 0xD1, value } => {
assert!(value.downcast_ref::<Avs3VideoDescriptor>().is_some());
}
other => panic!("expected Avs3Video via inherited scope, got {other:?}"),
}
let hevc = [0x05, 4, b'H', b'E', b'V', b'C'];
let mut pi = reg.parse_loop(&hevc);
for item in pi.by_ref() {
item.unwrap();
}
assert_eq!(pi.avs_scope(), None);
}
#[test]
fn avs3_video_descriptor_scopes() {
use crate::descriptors::avs3_video::Avs3VideoDescriptor;
use crate::descriptors::private_data_specifier::PDS_AVSV;
let desc = [0xD1, 8, 0x22, 0x42, 0xAA, 0x4B, 9, 14, 9, 0xFF];
let mut reg = DescriptorRegistry::new();
reg.with_avs3_video();
let check = |bytes: &[u8], idx: usize| {
let items: Vec<_> = reg.parse_loop(bytes).collect::<Result<_, _>>().unwrap();
match &items[idx] {
AnyDescriptor::Other { tag, value } => {
assert_eq!(*tag, 0xD1);
assert_eq!(
value
.downcast_ref::<Avs3VideoDescriptor>()
.unwrap()
.profile_id,
0x22
);
}
other => panic!("expected Other, got {other:?}"),
}
};
let mut pds = pds_descriptor(PDS_AVSV);
pds.extend_from_slice(&desc);
check(&pds, 1);
let mut registration = vec![0x05, 4, b'A', b'V', b'S', b'V'];
registration.extend_from_slice(&desc);
check(®istration, 1);
let items: Vec<_> = reg.parse_loop(&desc).collect::<Result<_, _>>().unwrap();
assert!(matches!(items[0], AnyDescriptor::Unknown { tag: 0xD1, .. }));
let mut other = vec![0x05, 4, b'A', b'C', b'-', b'3'];
other.extend_from_slice(&desc);
let items: Vec<_> = reg.parse_loop(&other).collect::<Result<_, _>>().unwrap();
assert!(matches!(items[1], AnyDescriptor::Unknown { tag: 0xD1, .. }));
let adesc = [0xD2, 2, 0x72, 0x45];
let mut areg = DescriptorRegistry::new();
areg.with_avs3_audio();
let mut b = vec![0x05, 4, b'A', b'V', b'S', b'A'];
b.extend_from_slice(&adesc);
let items: Vec<_> = areg.parse_loop(&b).collect::<Result<_, _>>().unwrap();
assert!(matches!(items[1], AnyDescriptor::Other { tag: 0xD2, .. }));
}
#[test]
fn avs3_audio_descriptor_is_pds_scoped() {
use crate::descriptors::avs3_audio::Avs3AudioDescriptor;
use crate::descriptors::private_data_specifier::PDS_AVSA;
let desc = [0xD2, 6, 0x03, 0xAA, 0x95, 0x04, 0x00, 0x6A];
let mut reg = DescriptorRegistry::new();
reg.with_avs3_audio();
let mut bytes = Vec::new();
bytes.extend_from_slice(&pds_descriptor(PDS_AVSA));
bytes.extend_from_slice(&desc);
let items: Vec<_> = reg.parse_loop(&bytes).collect::<Result<_, _>>().unwrap();
match &items[1] {
AnyDescriptor::Other { tag, value } => {
assert_eq!(*tag, 0xD2);
let d = value.downcast_ref::<Avs3AudioDescriptor>().unwrap();
assert_eq!(d.sampling_frequency_index, 3);
}
other => panic!("expected Other (Avs3AudioDescriptor), got {other:?}"),
}
let items: Vec<_> = reg.parse_loop(&desc).collect::<Result<_, _>>().unwrap();
assert!(matches!(items[0], AnyDescriptor::Unknown { tag: 0xD2, .. }));
let mut other = Vec::new();
other.extend_from_slice(&pds_descriptor(PDS_NORDIG));
other.extend_from_slice(&desc);
let items: Vec<_> = reg.parse_loop(&other).collect::<Result<_, _>>().unwrap();
assert!(matches!(items[1], AnyDescriptor::Unknown { tag: 0xD2, .. }));
}
#[test]
fn china_caption_service_is_opt_in() {
use crate::descriptors::china_caption_service::ChinaCaptionServiceDescriptor;
let desc = [
0x86, 9, 0xE1, b'c', b'h', b'i', 0xC1, 0xC2, 0xFF, 0xE1, 0x00,
];
let plain = DescriptorRegistry::new();
let items: Vec<_> = plain.parse_loop(&desc).collect::<Result<_, _>>().unwrap();
assert!(matches!(items[0], AnyDescriptor::Unknown { tag: 0x86, .. }));
let mut reg = DescriptorRegistry::new();
reg.with_china_caption_service();
let items: Vec<_> = reg.parse_loop(&desc).collect::<Result<_, _>>().unwrap();
match &items[0] {
AnyDescriptor::Other { tag, value } => {
assert_eq!(*tag, 0x86);
let d = value
.downcast_ref::<ChinaCaptionServiceDescriptor>()
.unwrap();
assert_eq!(d.services.len(), 1);
}
other => panic!("expected Other, got {other:?}"),
}
}
#[test]
fn atsc_caption_service_is_opt_in() {
use crate::descriptors::atsc_caption_service::AtscCaptionServiceDescriptor;
let desc = [0x86, 7, 0xE1, b'e', b'n', b'g', 0xC1, 0x7F, 0xFF];
let plain = DescriptorRegistry::new();
let items: Vec<_> = plain.parse_loop(&desc).collect::<Result<_, _>>().unwrap();
assert!(matches!(items[0], AnyDescriptor::Unknown { tag: 0x86, .. }));
let mut reg = DescriptorRegistry::new();
reg.with_atsc_caption_service();
let items: Vec<_> = reg.parse_loop(&desc).collect::<Result<_, _>>().unwrap();
match &items[0] {
AnyDescriptor::Other { value, .. } => {
let d = value
.downcast_ref::<AtscCaptionServiceDescriptor>()
.unwrap();
assert_eq!(d.services.len(), 1);
}
other => panic!("expected Other, got {other:?}"),
}
}
#[test]
fn pds_agnostic_matches_without_pds() {
let mut reg = DescriptorRegistry::new();
reg.register::<PdsAgnostic>();
let bytes = [0x84, 0x01, 0xDD];
let items: Vec<_> = reg.parse_loop(&bytes).collect::<Result<_, _>>().unwrap();
assert_eq!(items.len(), 1);
match &items[0] {
AnyDescriptor::Other { tag, value } => {
assert_eq!(*tag, 0x84);
let c = value.downcast_ref::<PdsAgnostic>().unwrap();
assert_eq!(c.z, 0xDD);
}
other => panic!("expected Other, got {other:?}"),
}
}
#[test]
fn pds_scoped_takes_precedence_over_agnostic() {
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
struct Agnostic83 {
a: u8,
}
impl<'a> broadcast_common::Parse<'a> for Agnostic83 {
type Error = crate::error::Error;
fn parse(bytes: &'a [u8]) -> crate::Result<Self> {
if bytes.len() < 3 {
return Err(crate::error::Error::BufferTooShort {
need: 3,
have: bytes.len(),
what: "Agnostic83",
});
}
Ok(Self { a: bytes[2] })
}
}
impl DescriptorDef<'_> for Agnostic83 {
const TAG: u8 = 0x83;
const NAME: &'static str = "AGNOSTIC_83";
}
let mut reg = DescriptorRegistry::new();
reg.register::<Agnostic83>();
reg.register_for_pds::<PdsEacem>(PDS_EACEM);
let items: Vec<_> = reg
.parse_loop(&[0x83, 0x01, 0xEE])
.collect::<Result<_, _>>()
.unwrap();
match &items[0] {
AnyDescriptor::Other { value, .. } => {
assert!(value.downcast_ref::<Agnostic83>().is_some());
assert!(value.downcast_ref::<PdsEacem>().is_none());
}
other => panic!("expected Other, got {other:?}"),
}
let mut bytes = Vec::new();
bytes.extend_from_slice(&pds_descriptor(PDS_EACEM));
bytes.extend_from_slice(&[0x83, 0x01, 0xFF]);
let items: Vec<_> = reg.parse_loop(&bytes).collect::<Result<_, _>>().unwrap();
match &items[1] {
AnyDescriptor::Other { value, .. } => {
assert!(value.downcast_ref::<PdsEacem>().is_some());
assert!(value.downcast_ref::<Agnostic83>().is_none());
}
other => panic!("expected Other, got {other:?}"),
}
}
fn logical_channel_descriptor(service_id: u16, visible: bool, lcn: u16) -> Vec<u8> {
let mut v = vec![crate::descriptors::logical_channel::TAG, 4];
v.extend_from_slice(&service_id.to_be_bytes());
let flags = (u8::from(visible) << 7) | ((lcn >> 8) as u8 & 0x03);
v.push(flags);
v.push((lcn & 0xFF) as u8);
v
}
#[test]
fn logical_channel_pds_scoped_matches_correct_pds() {
let mut reg = DescriptorRegistry::new();
reg.with_logical_channel_for_pds(PDS_EACEM);
let mut bytes = Vec::new();
bytes.extend_from_slice(&pds_descriptor(PDS_EACEM));
bytes.extend_from_slice(&logical_channel_descriptor(0x1234, true, 101));
let items: Vec<_> = reg.parse_loop(&bytes).collect::<Result<_, _>>().unwrap();
assert_eq!(items.len(), 2);
assert!(matches!(items[0], AnyDescriptor::PrivateDataSpecifier(_)));
match &items[1] {
AnyDescriptor::LogicalChannel(lc) => {
assert_eq!(lc.entries.len(), 1);
assert_eq!(lc.entries[0].service_id, 0x1234);
assert!(lc.entries[0].visible_service);
assert_eq!(lc.entries[0].logical_channel_number, 101);
}
other => panic!("expected LogicalChannel, got {other:?}"),
}
}
#[test]
fn logical_channel_pds_scoped_rejects_no_pds() {
let mut reg = DescriptorRegistry::new();
reg.with_logical_channel_for_pds(PDS_EACEM);
let bytes = logical_channel_descriptor(0x1234, true, 101);
let items: Vec<_> = reg.parse_loop(&bytes).collect::<Result<_, _>>().unwrap();
assert_eq!(items.len(), 1);
assert!(matches!(
&items[0],
AnyDescriptor::Unknown { tag: 0x83, .. }
));
}
#[test]
fn logical_channel_pds_scoped_rejects_wrong_pds() {
let mut reg = DescriptorRegistry::new();
reg.with_logical_channel_for_pds(PDS_EACEM);
let mut bytes = Vec::new();
bytes.extend_from_slice(&pds_descriptor(PDS_NORDIG));
bytes.extend_from_slice(&logical_channel_descriptor(0x1234, true, 101));
let items: Vec<_> = reg.parse_loop(&bytes).collect::<Result<_, _>>().unwrap();
assert_eq!(items.len(), 2);
assert!(matches!(items[0], AnyDescriptor::PrivateDataSpecifier(_)));
assert!(matches!(
&items[1],
AnyDescriptor::Unknown { tag: 0x83, .. }
));
}
#[test]
fn logical_channel_pds_scoped_multiple_pds() {
let mut reg = DescriptorRegistry::new();
reg.with_logical_channel_for_pds(PDS_EACEM);
reg.with_logical_channel_for_pds(PDS_NORDIG);
let mut bytes = Vec::new();
bytes.extend_from_slice(&pds_descriptor(PDS_EACEM));
bytes.extend_from_slice(&logical_channel_descriptor(0x0001, true, 1));
let items: Vec<_> = reg.parse_loop(&bytes).collect::<Result<_, _>>().unwrap();
assert!(matches!(&items[1], AnyDescriptor::LogicalChannel(_)));
let mut bytes2 = Vec::new();
bytes2.extend_from_slice(&pds_descriptor(PDS_NORDIG));
bytes2.extend_from_slice(&logical_channel_descriptor(0x0002, false, 2));
let items2: Vec<_> = reg.parse_loop(&bytes2).collect::<Result<_, _>>().unwrap();
assert!(matches!(&items2[1], AnyDescriptor::LogicalChannel(_)));
}
#[test]
fn program_info_registration_scopes_es_info_with_extensions() {
use crate::descriptors::any::DescriptorLoop;
use crate::descriptors::avs3_video::Avs3VideoDescriptor;
use crate::descriptors::extension::registry::ExtensionRegistry;
use crate::descriptors::private_data_specifier::PDS_AVSV;
let program_info = [0x05, 4, b'A', b'V', b'S', b'V'];
let es_info = [0xD1, 8, 0x22, 0x42, 0xAA, 0x4B, 9, 14, 9, 0xFF];
let mut reg = DescriptorRegistry::new();
reg.with_avs3_video();
let ext = ExtensionRegistry::new();
let items: Vec<_> = DescriptorLoop::new(&es_info)
.iter_with_extensions(®, &ext)
.collect::<Result<_, _>>()
.unwrap();
assert!(matches!(
&items[0],
ExtIterItem::Descriptor(AnyDescriptor::Unknown { tag: 0xD1, .. })
));
let mut pi = DescriptorLoop::new(&program_info).iter_with_extensions(®, &ext);
for item in pi.by_ref() {
item.unwrap();
}
let scope = pi.avs_scope();
assert_eq!(scope, Some(PDS_AVSV));
let items: Vec<_> = DescriptorLoop::new(&es_info)
.iter_with_extensions_in_scope(®, &ext, scope)
.collect::<Result<_, _>>()
.unwrap();
match &items[0] {
ExtIterItem::Descriptor(AnyDescriptor::Other { tag: 0xD1, value }) => {
assert!(value.downcast_ref::<Avs3VideoDescriptor>().is_some());
}
other => panic!("expected Avs3Video via inherited scope, got {other:?}"),
}
}
#[test]
fn iter_with_extensions_surfaces_custom_extension() {
use crate::descriptors::any::{AnyDescriptor, DescriptorLoop};
use crate::descriptors::extension::registry::ExtensionRegistry;
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
struct MyCustomExt {
payload: Vec<u8>,
}
impl<'a> broadcast_common::Parse<'a> for MyCustomExt {
type Error = crate::error::Error;
fn parse(sel: &'a [u8]) -> crate::Result<Self> {
Ok(Self {
payload: sel.to_vec(),
})
}
}
impl crate::descriptors::extension::ExtensionBodyDef<'_> for MyCustomExt {
const TAG_EXTENSION: u8 = 0x42;
const NAME: &'static str = "MY_CUSTOM_EXT";
}
let mut ext_reg = ExtensionRegistry::new();
ext_reg.register::<MyCustomExt>();
let desc_reg = DescriptorRegistry::new();
let mut loop_bytes = vec![
0x4D, 0x07, b'e', b'n', b'g', 0x02, b'H', b'i', 0x00, ];
loop_bytes.extend_from_slice(&[0x7F, 0x03, 0x42, 0xAB, 0xCD]);
let dl = DescriptorLoop::new(&loop_bytes);
let items: Vec<_> = dl
.iter_with_extensions(&desc_reg, &ext_reg)
.collect::<Result<_, _>>()
.unwrap();
assert_eq!(items.len(), 2);
assert!(matches!(
&items[0],
ExtIterItem::Descriptor(AnyDescriptor::ShortEvent(_))
));
match &items[1] {
ExtIterItem::CustomExtension {
tag_extension,
value,
} => {
assert_eq!(*tag_extension, 0x42);
let concrete = value.downcast_ref::<MyCustomExt>().unwrap();
assert_eq!(concrete.payload, &[0xAB, 0xCD]);
}
other => panic!("expected CustomExtension, got {other:?}"),
}
}
}