use std::any::Any;
use std::collections::HashMap;
use crate::descriptors::any::AnyDescriptor;
#[cfg(not(feature = "serde"))]
pub trait DescriptorObject: std::fmt::Debug + Any + Send + Sync {
fn as_any(&self) -> &dyn Any;
}
#[cfg(feature = "serde")]
pub trait DescriptorObject: std::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: std::fmt::Debug + Any + Send + Sync,
{
fn as_any(&self) -> &dyn Any {
self
}
}
#[cfg(feature = "serde")]
impl<T> DescriptorObject for T
where
T: std::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: HashMap<(Option<u32>, u8), CustomParse>,
logical_channel: bool,
}
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 dvb_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 dvb_common::Parse>::parse(b)?) as Box<dyn DescriptorObject>)
}),
);
self
}
pub fn with_logical_channel(&mut self) -> &mut Self {
self.logical_channel = true;
self
}
#[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,
}
}
}
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 {
if 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 registry.logical_channel && tag == crate::descriptors::logical_channel::TAG {
use dvb_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::private_data_specifier::TAG {
use dvb_common::Parse;
if let Ok(pds) =
crate::descriptors::private_data_specifier::PrivateDataSpecifierDescriptor::parse(full)
{
*current = Some(pds.private_data_specifier);
}
}
}
impl<'r, 'a> Iterator for RegistryIter<'r, '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 std::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],
) -> Self {
Self {
desc_reg,
ext_reg,
bytes,
pos: 0,
fused: false,
current_pds: None,
}
}
}
impl<'r, 'a> Iterator for ExtRegistryIter<'r, '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 std::iter::FusedIterator for ExtRegistryIter<'_, '_> {}
#[cfg(test)]
mod tests {
use super::*;
use crate::descriptors::private_data_specifier;
use crate::traits::DescriptorDef;
const PDS_EACEM: u32 = 0x0000_0028;
const PDS_NORDIG: u32 = 0x0000_0031;
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
struct PdsEacem {
v: u8,
}
impl<'a> dvb_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<'a> DescriptorDef<'a> 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> dvb_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<'a> DescriptorDef<'a> 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> dvb_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<'a> DescriptorDef<'a> 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 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> dvb_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<'a> DescriptorDef<'a> 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:?}"),
}
}
#[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> dvb_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<'a> crate::descriptors::extension::ExtensionBodyDef<'a> 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:?}"),
}
}
}