1use alloc::boxed::Box;
69use alloc::collections::BTreeMap;
70
71use crate::descriptors::any::AnyDescriptor;
72use crate::descriptors::private_data_specifier::PDS_NORDIG;
73
74broadcast_common::declare_object_trait! {
75 pub trait DescriptorObject, "descriptor"
83}
84
85pub(crate) type CustomParse =
92 Box<dyn for<'a> Fn(&'a [u8]) -> crate::Result<Box<dyn DescriptorObject>> + Send + Sync>;
93
94#[derive(Default)]
124pub struct DescriptorRegistry {
125 custom: BTreeMap<(Option<u32>, u8), CustomParse>,
126 logical_channel: bool,
127 logical_channel_pds: alloc::collections::BTreeSet<u32>,
128}
129
130impl DescriptorRegistry {
131 #[must_use]
133 pub fn new() -> Self {
134 Self::default()
135 }
136
137 pub fn register<T>(&mut self) -> &mut Self
158 where
159 T: for<'a> crate::traits::DescriptorDef<'a> + DescriptorObject + 'static,
160 {
161 let tag = <T as crate::traits::DescriptorDef<'static>>::TAG;
162 self.custom.insert(
163 (None, tag),
164 Box::new(|b| {
165 Ok(Box::new(<T as broadcast_common::Parse>::parse(b)?)
166 as Box<dyn DescriptorObject>)
167 }),
168 );
169 self
170 }
171
172 pub fn register_for_pds<T>(&mut self, pds: u32) -> &mut Self
184 where
185 T: for<'a> crate::traits::DescriptorDef<'a> + DescriptorObject + 'static,
186 {
187 let tag = <T as crate::traits::DescriptorDef<'static>>::TAG;
188 self.custom.insert(
189 (Some(pds), tag),
190 Box::new(|b| {
191 Ok(Box::new(<T as broadcast_common::Parse>::parse(b)?)
192 as Box<dyn DescriptorObject>)
193 }),
194 );
195 self
196 }
197
198 pub fn with_logical_channel(&mut self) -> &mut Self {
204 self.logical_channel = true;
205 self
206 }
207
208 pub fn with_logical_channel_for_pds(&mut self, pds: u32) -> &mut Self {
220 self.logical_channel_pds.insert(pds);
221 self
222 }
223
224 pub fn with_nordig_lcn(&mut self) -> &mut Self {
228 self.register_for_pds::<crate::descriptors::nordig::NordigLogicalChannelV1>(PDS_NORDIG);
229 self.register_for_pds::<crate::descriptors::nordig::NordigLogicalChannelV2>(PDS_NORDIG);
230 self
231 }
232
233 pub fn with_avs3_audio(&mut self) -> &mut Self {
239 self.register_for_pds::<crate::descriptors::avs3_audio::Avs3AudioDescriptor>(
240 crate::descriptors::PDS_AVSA,
241 );
242 self
243 }
244
245 pub fn with_avs3_video(&mut self) -> &mut Self {
252 self.register_for_pds::<crate::descriptors::avs3_video::Avs3VideoDescriptor>(
253 crate::descriptors::PDS_AVSV,
254 );
255 self
256 }
257
258 pub fn with_avs2_video(&mut self) -> &mut Self {
263 self.register_for_pds::<crate::descriptors::avs2_video::Avs2VideoDescriptor>(
264 crate::descriptors::PDS_AVSV,
265 );
266 self
267 }
268
269 pub fn with_avs2_audio(&mut self) -> &mut Self {
273 self.register_for_pds::<crate::descriptors::avs2_audio::Avs2AudioDescriptor>(
274 crate::descriptors::PDS_AVSA,
275 );
276 self
277 }
278
279 pub fn with_tuwa_avs3_video(&mut self) -> &mut Self {
283 self.register::<crate::descriptors::tuwa_avs3_video::TuwaAvs3VideoDescriptor>()
284 }
285
286 pub fn with_china_caption_service(&mut self) -> &mut Self {
292 self.register::<crate::descriptors::china_caption_service::ChinaCaptionServiceDescriptor>()
293 }
294
295 pub fn with_atsc_caption_service(&mut self) -> &mut Self {
300 self.register::<crate::descriptors::atsc_caption_service::AtscCaptionServiceDescriptor>()
301 }
302
303 #[must_use]
313 pub fn parse_loop<'r, 'a>(&'r self, bytes: &'a [u8]) -> RegistryIter<'r, 'a> {
314 RegistryIter {
315 registry: self,
316 bytes,
317 pos: 0,
318 fused: false,
319 current_pds: None,
320 }
321 }
322
323 #[must_use]
337 pub fn parse_loop_in_scope<'r, 'a>(
338 &'r self,
339 bytes: &'a [u8],
340 inherited: Option<u32>,
341 ) -> RegistryIter<'r, 'a> {
342 RegistryIter {
343 registry: self,
344 bytes,
345 pos: 0,
346 fused: false,
347 current_pds: inherited,
348 }
349 }
350}
351
352pub struct RegistryIter<'r, 'a> {
360 registry: &'r DescriptorRegistry,
361 bytes: &'a [u8],
362 pos: usize,
363 fused: bool,
364 current_pds: Option<u32>,
365}
366
367pub(crate) fn dispatch_entry<'a>(
373 registry: &DescriptorRegistry,
374 current_pds: Option<u32>,
375 tag: u8,
376 full: &'a [u8],
377) -> crate::Result<AnyDescriptor<'a>> {
378 if let Some(pds) = current_pds
379 && let Some(parse_fn) = registry.custom.get(&(Some(pds), tag))
380 {
381 return parse_fn(full).map(|value| AnyDescriptor::Other { tag, value });
382 }
383 if let Some(parse_fn) = registry.custom.get(&(None, tag)) {
384 return parse_fn(full).map(|value| AnyDescriptor::Other { tag, value });
385 }
386 if let Some(pds) = current_pds
387 && tag == crate::descriptors::logical_channel::TAG
388 && registry.logical_channel_pds.contains(&pds)
389 {
390 use broadcast_common::Parse;
391 return crate::descriptors::logical_channel::LogicalChannelDescriptor::parse(full)
392 .map(AnyDescriptor::LogicalChannel);
393 }
394 if registry.logical_channel && tag == crate::descriptors::logical_channel::TAG {
395 use broadcast_common::Parse;
396 return crate::descriptors::logical_channel::LogicalChannelDescriptor::parse(full)
397 .map(AnyDescriptor::LogicalChannel);
398 }
399 if let Some(res) = AnyDescriptor::dispatch(tag, full) {
400 return res;
401 }
402 Ok(AnyDescriptor::Unknown {
403 tag,
404 body: &full[2..],
405 })
406}
407
408fn update_pds(current: &mut Option<u32>, tag: u8, full: &[u8]) {
409 if tag == crate::descriptors::registration::TAG {
415 use broadcast_common::Parse;
416 if let Ok(reg) = crate::descriptors::registration::RegistrationDescriptor::parse(full) {
417 let id = u32::from_be_bytes(reg.format_identifier);
418 if id == crate::descriptors::PDS_AVSA || id == crate::descriptors::PDS_AVSV {
419 *current = Some(id);
420 }
421 }
422 }
423 if tag == crate::descriptors::private_data_specifier::TAG {
424 use broadcast_common::Parse;
425 if let Ok(pds) =
426 crate::descriptors::private_data_specifier::PrivateDataSpecifierDescriptor::parse(full)
427 {
428 *current = Some(pds.private_data_specifier);
429 }
430 }
431}
432
433impl RegistryIter<'_, '_> {
434 #[must_use]
440 pub fn avs_scope(&self) -> Option<u32> {
441 self.current_pds
442 .filter(|p| *p == crate::descriptors::PDS_AVSA || *p == crate::descriptors::PDS_AVSV)
443 }
444}
445
446impl<'a> Iterator for RegistryIter<'_, 'a> {
447 type Item = crate::Result<AnyDescriptor<'a>>;
448
449 fn next(&mut self) -> Option<Self::Item> {
450 let (tag, full) = match crate::descriptors::any::next_loop_entry(
451 self.bytes,
452 &mut self.pos,
453 &mut self.fused,
454 )? {
455 Ok(v) => v,
456 Err(e) => return Some(Err(e)),
457 };
458
459 update_pds(&mut self.current_pds, tag, full);
460
461 Some(dispatch_entry(self.registry, self.current_pds, tag, full))
462 }
463}
464
465impl core::iter::FusedIterator for RegistryIter<'_, '_> {}
466
467#[derive(Debug)]
479#[cfg_attr(feature = "serde", derive(serde::Serialize))]
480#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
481#[non_exhaustive]
482pub enum ExtIterItem<'a> {
483 Descriptor(AnyDescriptor<'a>),
485 CustomExtension {
487 tag_extension: u8,
489 #[cfg_attr(
492 feature = "serde",
493 serde(serialize_with = "super::extension::registry::serialize_erased")
494 )]
495 value: Box<dyn super::extension::registry::ExtensionObject>,
496 },
497}
498
499pub struct ExtRegistryIter<'r, 'a> {
509 desc_reg: &'r DescriptorRegistry,
510 ext_reg: &'r super::extension::registry::ExtensionRegistry,
511 bytes: &'a [u8],
512 pos: usize,
513 fused: bool,
514 current_pds: Option<u32>,
515}
516
517impl<'r, 'a> ExtRegistryIter<'r, 'a> {
518 pub(crate) fn new(
519 desc_reg: &'r DescriptorRegistry,
520 ext_reg: &'r super::extension::registry::ExtensionRegistry,
521 bytes: &'a [u8],
522 inherited: Option<u32>,
523 ) -> Self {
524 Self {
525 desc_reg,
526 ext_reg,
527 bytes,
528 pos: 0,
529 fused: false,
530 current_pds: inherited,
531 }
532 }
533
534 #[must_use]
537 pub fn avs_scope(&self) -> Option<u32> {
538 self.current_pds
539 .filter(|p| *p == crate::descriptors::PDS_AVSA || *p == crate::descriptors::PDS_AVSV)
540 }
541}
542
543impl<'a> Iterator for ExtRegistryIter<'_, 'a> {
544 type Item = crate::Result<ExtIterItem<'a>>;
545
546 fn next(&mut self) -> Option<Self::Item> {
547 let (tag, full) = match crate::descriptors::any::next_loop_entry(
548 self.bytes,
549 &mut self.pos,
550 &mut self.fused,
551 )? {
552 Ok(v) => v,
553 Err(e) => return Some(Err(e)),
554 };
555
556 update_pds(&mut self.current_pds, tag, full);
557
558 let len = full.len() - 2;
559 if tag == crate::descriptors::extension::TAG && len >= 1 {
560 let tag_extension = full[2];
561 if self.ext_reg.has_custom(tag_extension) {
562 return Some(match self.ext_reg.parse_body(tag_extension, &full[3..]) {
563 Ok(super::extension::registry::RegisteredExtension::Custom {
564 tag_extension,
565 value,
566 }) => Ok(ExtIterItem::CustomExtension {
567 tag_extension,
568 value,
569 }),
570 Ok(super::extension::registry::RegisteredExtension::Builtin(d)) => {
571 Ok(ExtIterItem::Descriptor(AnyDescriptor::Extension(d)))
572 }
573 Err(e) => Err(e),
574 });
575 }
576 }
577
578 Some(
579 dispatch_entry(self.desc_reg, self.current_pds, tag, full).map(ExtIterItem::Descriptor),
580 )
581 }
582}
583
584impl core::iter::FusedIterator for ExtRegistryIter<'_, '_> {}
585
586#[cfg(test)]
587mod tests {
588 use super::*;
589 use crate::descriptors::private_data_specifier;
590 use crate::descriptors::private_data_specifier::{PDS_EACEM, PDS_NORDIG};
591 use crate::traits::DescriptorDef;
592
593 #[test]
594 fn pds_constants_match_the_register() {
595 assert_eq!(
598 private_data_specifier::private_data_specifier_name(PDS_EACEM),
599 Some("EACEM/EICTA")
600 );
601 assert_eq!(
602 private_data_specifier::private_data_specifier_name(PDS_NORDIG),
603 Some("NorDig")
604 );
605 }
606
607 #[derive(Debug, PartialEq, Eq)]
608 #[cfg_attr(feature = "serde", derive(serde::Serialize))]
609 struct PdsEacem {
610 v: u8,
611 }
612
613 impl<'a> broadcast_common::Parse<'a> for PdsEacem {
614 type Error = crate::error::Error;
615 fn parse(bytes: &'a [u8]) -> crate::Result<Self> {
616 if bytes.len() < 3 {
617 return Err(crate::error::Error::BufferTooShort(
618 broadcast_common::error::BufferTooShort {
619 need: 3,
620 have: bytes.len(),
621 what: "PdsEacem",
622 },
623 ));
624 }
625 Ok(Self { v: bytes[2] })
626 }
627 }
628
629 impl DescriptorDef<'_> for PdsEacem {
630 const TAG: u8 = 0x83;
631 const NAME: &'static str = "PDS_EACEM";
632 }
633
634 #[derive(Debug, PartialEq, Eq)]
635 #[cfg_attr(feature = "serde", derive(serde::Serialize))]
636 struct PdsNordig {
637 w: u8,
638 }
639
640 impl<'a> broadcast_common::Parse<'a> for PdsNordig {
641 type Error = crate::error::Error;
642 fn parse(bytes: &'a [u8]) -> crate::Result<Self> {
643 if bytes.len() < 3 {
644 return Err(crate::error::Error::BufferTooShort(
645 broadcast_common::error::BufferTooShort {
646 need: 3,
647 have: bytes.len(),
648 what: "PdsNordig",
649 },
650 ));
651 }
652 Ok(Self { w: bytes[2] })
653 }
654 }
655
656 impl DescriptorDef<'_> for PdsNordig {
657 const TAG: u8 = 0x83;
658 const NAME: &'static str = "PDS_NORDIG";
659 }
660
661 #[derive(Debug, PartialEq, Eq)]
662 #[cfg_attr(feature = "serde", derive(serde::Serialize))]
663 struct PdsAgnostic {
664 z: u8,
665 }
666
667 impl<'a> broadcast_common::Parse<'a> for PdsAgnostic {
668 type Error = crate::error::Error;
669 fn parse(bytes: &'a [u8]) -> crate::Result<Self> {
670 if bytes.len() < 3 {
671 return Err(crate::error::Error::BufferTooShort(
672 broadcast_common::error::BufferTooShort {
673 need: 3,
674 have: bytes.len(),
675 what: "PdsAgnostic",
676 },
677 ));
678 }
679 Ok(Self { z: bytes[2] })
680 }
681 }
682
683 impl DescriptorDef<'_> for PdsAgnostic {
684 const TAG: u8 = 0x84;
685 const NAME: &'static str = "PDS_AGNOSTIC";
686 }
687
688 fn pds_descriptor(pds: u32) -> Vec<u8> {
689 let mut v = vec![private_data_specifier::TAG, 4];
690 v.extend_from_slice(&pds.to_be_bytes());
691 v
692 }
693
694 #[test]
695 fn pds_scoped_same_tag_resolves_by_pds() {
696 let mut reg = DescriptorRegistry::new();
697 reg.register_for_pds::<PdsEacem>(PDS_EACEM);
698 reg.register_for_pds::<PdsNordig>(PDS_NORDIG);
699
700 let mut bytes = Vec::new();
701 bytes.extend_from_slice(&pds_descriptor(PDS_EACEM));
702 bytes.extend_from_slice(&[0x83, 0x01, 0xAA]);
703
704 let items: Vec<_> = reg.parse_loop(&bytes).collect::<Result<_, _>>().unwrap();
705 assert_eq!(items.len(), 2);
706 assert!(matches!(items[0], AnyDescriptor::PrivateDataSpecifier(_)));
707 match &items[1] {
708 AnyDescriptor::Other { tag, value } => {
709 assert_eq!(*tag, 0x83);
710 let c = value.downcast_ref::<PdsEacem>().unwrap();
711 assert_eq!(c.v, 0xAA);
712 }
713 other => panic!("expected Other (PdsEacem), got {other:?}"),
714 }
715
716 let mut bytes2 = Vec::new();
717 bytes2.extend_from_slice(&pds_descriptor(PDS_NORDIG));
718 bytes2.extend_from_slice(&[0x83, 0x01, 0xBB]);
719
720 let items2: Vec<_> = reg.parse_loop(&bytes2).collect::<Result<_, _>>().unwrap();
721 match &items2[1] {
722 AnyDescriptor::Other { tag, value } => {
723 assert_eq!(*tag, 0x83);
724 let c = value.downcast_ref::<PdsNordig>().unwrap();
725 assert_eq!(c.w, 0xBB);
726 }
727 other => panic!("expected Other (PdsNordig), got {other:?}"),
728 }
729 }
730
731 #[test]
732 fn pds_scoped_does_not_match_wrong_pds() {
733 let mut reg = DescriptorRegistry::new();
734 reg.register_for_pds::<PdsEacem>(PDS_EACEM);
735
736 let mut bytes = Vec::new();
737 bytes.extend_from_slice(&pds_descriptor(PDS_NORDIG));
738 bytes.extend_from_slice(&[0x83, 0x01, 0xCC]);
739
740 let items: Vec<_> = reg.parse_loop(&bytes).collect::<Result<_, _>>().unwrap();
741 assert_eq!(items.len(), 2);
742 assert!(matches!(items[0], AnyDescriptor::PrivateDataSpecifier(_)));
743 match &items[1] {
744 AnyDescriptor::Unknown { tag, .. } => assert_eq!(*tag, 0x83),
745 other => panic!("expected Unknown (wrong PDS), got {other:?}"),
746 }
747 }
748
749 #[test]
752 fn avs2_and_tuwa_descriptors_are_scoped() {
753 use crate::descriptors::avs2_audio::Avs2AudioDescriptor;
754 use crate::descriptors::avs2_video::Avs2VideoDescriptor;
755 use crate::descriptors::private_data_specifier::{PDS_AVSA, PDS_AVSV};
756 use crate::descriptors::tuwa_avs3_video::TuwaAvs3VideoDescriptor;
757 let mut reg = DescriptorRegistry::new();
758 reg.with_avs2_video()
759 .with_avs2_audio()
760 .with_tuwa_avs3_video();
761
762 let v = [0x40, 5, 0x20, 0x42, 0x00, 0xA9, 0x5F];
763 let items: Vec<_> = reg.parse_loop(&v).collect::<Result<_, _>>().unwrap();
765 assert!(matches!(items[0], AnyDescriptor::NetworkName(_)));
766 let mut b = vec![0x05, 4, b'A', b'V', b'S', b'V'];
768 b.extend_from_slice(&v);
769 let items: Vec<_> = reg.parse_loop(&b).collect::<Result<_, _>>().unwrap();
770 match &items[1] {
771 AnyDescriptor::Other { tag: 0x40, value } => {
772 assert!(value.downcast_ref::<Avs2VideoDescriptor>().is_some());
773 }
774 other => panic!("expected Avs2Video, got {other:?}"),
775 }
776 let mut b = pds_descriptor(PDS_AVSV);
778 b.extend_from_slice(&v);
779 let items: Vec<_> = reg.parse_loop(&b).collect::<Result<_, _>>().unwrap();
780 assert!(matches!(items[1], AnyDescriptor::Other { tag: 0x40, .. }));
781
782 let a = [0xD3, 2, 6, 0x20];
783 let mut b = vec![0x05, 4, b'A', b'V', b'S', b'A'];
784 b.extend_from_slice(&a);
785 let items: Vec<_> = reg.parse_loop(&b).collect::<Result<_, _>>().unwrap();
786 match &items[1] {
787 AnyDescriptor::Other { tag: 0xD3, value } => {
788 assert!(value.downcast_ref::<Avs2AudioDescriptor>().is_some());
789 }
790 other => panic!("expected Avs2Audio, got {other:?}"),
791 }
792 let mut b = pds_descriptor(PDS_AVSA);
793 b.extend_from_slice(&a);
794 assert!(matches!(
795 reg.parse_loop(&b).collect::<Result<Vec<_>, _>>().unwrap()[1],
796 AnyDescriptor::Other { tag: 0xD3, .. }
797 ));
798 let items: Vec<_> = reg.parse_loop(&a).collect::<Result<_, _>>().unwrap();
800 assert!(matches!(items[0], AnyDescriptor::Unknown { tag: 0xD3, .. }));
801
802 let t = [62, 7, 0x22, 0x42, 0xAA, 0x4F, 9, 14, 9];
804 let items: Vec<_> = reg.parse_loop(&t).collect::<Result<_, _>>().unwrap();
805 match &items[0] {
806 AnyDescriptor::Other { tag: 62, value } => {
807 assert!(value.downcast_ref::<TuwaAvs3VideoDescriptor>().is_some());
808 }
809 other => panic!("expected TuwaAvs3Video, got {other:?}"),
810 }
811 let plain = DescriptorRegistry::new();
812 let items: Vec<_> = plain.parse_loop(&t).collect::<Result<_, _>>().unwrap();
813 assert!(matches!(items[0], AnyDescriptor::Unknown { tag: 62, .. }));
814 }
815
816 #[test]
821 fn program_info_registration_scopes_es_info_descriptors() {
822 use crate::descriptors::avs3_video::Avs3VideoDescriptor;
823 use crate::descriptors::private_data_specifier::PDS_AVSV;
824 let program_info = [0x05, 4, b'A', b'V', b'S', b'V'];
825 let es_info = [0xD1, 8, 0x22, 0x42, 0xAA, 0x4B, 9, 14, 9, 0xFF];
827 let mut reg = DescriptorRegistry::new();
828 reg.with_avs3_video();
829
830 let items: Vec<_> = reg.parse_loop(&es_info).collect::<Result<_, _>>().unwrap();
832 assert!(matches!(items[0], AnyDescriptor::Unknown { tag: 0xD1, .. }));
833
834 let mut pi = reg.parse_loop(&program_info);
836 assert_eq!(pi.avs_scope(), None, "no entry consumed yet");
837 for item in pi.by_ref() {
838 item.unwrap();
839 }
840 let scope = pi.avs_scope();
841 assert_eq!(scope, Some(PDS_AVSV));
842 let items: Vec<_> = reg
843 .parse_loop_in_scope(&es_info, scope)
844 .collect::<Result<_, _>>()
845 .unwrap();
846 match &items[0] {
847 AnyDescriptor::Other { tag: 0xD1, value } => {
848 assert!(value.downcast_ref::<Avs3VideoDescriptor>().is_some());
849 }
850 other => panic!("expected Avs3Video via inherited scope, got {other:?}"),
851 }
852 let hevc = [0x05, 4, b'H', b'E', b'V', b'C'];
854 let mut pi = reg.parse_loop(&hevc);
855 for item in pi.by_ref() {
856 item.unwrap();
857 }
858 assert_eq!(pi.avs_scope(), None);
859 }
860
861 #[test]
864 fn avs3_video_descriptor_scopes() {
865 use crate::descriptors::avs3_video::Avs3VideoDescriptor;
866 use crate::descriptors::private_data_specifier::PDS_AVSV;
867 let desc = [0xD1, 8, 0x22, 0x42, 0xAA, 0x4B, 9, 14, 9, 0xFF];
868 let mut reg = DescriptorRegistry::new();
869 reg.with_avs3_video();
870 let check = |bytes: &[u8], idx: usize| {
871 let items: Vec<_> = reg.parse_loop(bytes).collect::<Result<_, _>>().unwrap();
872 match &items[idx] {
873 AnyDescriptor::Other { tag, value } => {
874 assert_eq!(*tag, 0xD1);
875 assert_eq!(
876 value
877 .downcast_ref::<Avs3VideoDescriptor>()
878 .unwrap()
879 .profile_id,
880 0x22
881 );
882 }
883 other => panic!("expected Other, got {other:?}"),
884 }
885 };
886 let mut pds = pds_descriptor(PDS_AVSV);
887 pds.extend_from_slice(&desc);
888 check(&pds, 1);
889 let mut registration = vec![0x05, 4, b'A', b'V', b'S', b'V'];
890 registration.extend_from_slice(&desc);
891 check(®istration, 1);
892 let items: Vec<_> = reg.parse_loop(&desc).collect::<Result<_, _>>().unwrap();
894 assert!(matches!(items[0], AnyDescriptor::Unknown { tag: 0xD1, .. }));
895 let mut other = vec![0x05, 4, b'A', b'C', b'-', b'3'];
896 other.extend_from_slice(&desc);
897 let items: Vec<_> = reg.parse_loop(&other).collect::<Result<_, _>>().unwrap();
898 assert!(matches!(items[1], AnyDescriptor::Unknown { tag: 0xD1, .. }));
899 let adesc = [0xD2, 2, 0x72, 0x45];
901 let mut areg = DescriptorRegistry::new();
902 areg.with_avs3_audio();
903 let mut b = vec![0x05, 4, b'A', b'V', b'S', b'A'];
904 b.extend_from_slice(&adesc);
905 let items: Vec<_> = areg.parse_loop(&b).collect::<Result<_, _>>().unwrap();
906 assert!(matches!(items[1], AnyDescriptor::Other { tag: 0xD2, .. }));
907 }
908
909 #[test]
912 fn avs3_audio_descriptor_is_pds_scoped() {
913 use crate::descriptors::avs3_audio::Avs3AudioDescriptor;
914 use crate::descriptors::private_data_specifier::PDS_AVSA;
915 let desc = [0xD2, 6, 0x03, 0xAA, 0x95, 0x04, 0x00, 0x6A];
916 let mut reg = DescriptorRegistry::new();
917 reg.with_avs3_audio();
918
919 let mut bytes = Vec::new();
920 bytes.extend_from_slice(&pds_descriptor(PDS_AVSA));
921 bytes.extend_from_slice(&desc);
922 let items: Vec<_> = reg.parse_loop(&bytes).collect::<Result<_, _>>().unwrap();
923 match &items[1] {
924 AnyDescriptor::Other { tag, value } => {
925 assert_eq!(*tag, 0xD2);
926 let d = value.downcast_ref::<Avs3AudioDescriptor>().unwrap();
927 assert_eq!(d.sampling_frequency_index, 3);
928 }
929 other => panic!("expected Other (Avs3AudioDescriptor), got {other:?}"),
930 }
931
932 let items: Vec<_> = reg.parse_loop(&desc).collect::<Result<_, _>>().unwrap();
934 assert!(matches!(items[0], AnyDescriptor::Unknown { tag: 0xD2, .. }));
935 let mut other = Vec::new();
936 other.extend_from_slice(&pds_descriptor(PDS_NORDIG));
937 other.extend_from_slice(&desc);
938 let items: Vec<_> = reg.parse_loop(&other).collect::<Result<_, _>>().unwrap();
939 assert!(matches!(items[1], AnyDescriptor::Unknown { tag: 0xD2, .. }));
940 }
941
942 #[test]
945 fn china_caption_service_is_opt_in() {
946 use crate::descriptors::china_caption_service::ChinaCaptionServiceDescriptor;
947 let desc = [
948 0x86, 9, 0xE1, b'c', b'h', b'i', 0xC1, 0xC2, 0xFF, 0xE1, 0x00,
949 ];
950 let plain = DescriptorRegistry::new();
951 let items: Vec<_> = plain.parse_loop(&desc).collect::<Result<_, _>>().unwrap();
952 assert!(matches!(items[0], AnyDescriptor::Unknown { tag: 0x86, .. }));
953 let mut reg = DescriptorRegistry::new();
954 reg.with_china_caption_service();
955 let items: Vec<_> = reg.parse_loop(&desc).collect::<Result<_, _>>().unwrap();
956 match &items[0] {
957 AnyDescriptor::Other { tag, value } => {
958 assert_eq!(*tag, 0x86);
959 let d = value
960 .downcast_ref::<ChinaCaptionServiceDescriptor>()
961 .unwrap();
962 assert_eq!(d.services.len(), 1);
963 }
964 other => panic!("expected Other, got {other:?}"),
965 }
966 }
967
968 #[test]
969 fn atsc_caption_service_is_opt_in() {
970 use crate::descriptors::atsc_caption_service::AtscCaptionServiceDescriptor;
971 let desc = [0x86, 7, 0xE1, b'e', b'n', b'g', 0xC1, 0x7F, 0xFF];
972 let plain = DescriptorRegistry::new();
973 let items: Vec<_> = plain.parse_loop(&desc).collect::<Result<_, _>>().unwrap();
974 assert!(matches!(items[0], AnyDescriptor::Unknown { tag: 0x86, .. }));
975 let mut reg = DescriptorRegistry::new();
976 reg.with_atsc_caption_service();
977 let items: Vec<_> = reg.parse_loop(&desc).collect::<Result<_, _>>().unwrap();
978 match &items[0] {
979 AnyDescriptor::Other { value, .. } => {
980 let d = value
981 .downcast_ref::<AtscCaptionServiceDescriptor>()
982 .unwrap();
983 assert_eq!(d.services.len(), 1);
984 }
985 other => panic!("expected Other, got {other:?}"),
986 }
987 }
988
989 #[test]
990 fn pds_agnostic_matches_without_pds() {
991 let mut reg = DescriptorRegistry::new();
992 reg.register::<PdsAgnostic>();
993
994 let bytes = [0x84, 0x01, 0xDD];
995 let items: Vec<_> = reg.parse_loop(&bytes).collect::<Result<_, _>>().unwrap();
996 assert_eq!(items.len(), 1);
997 match &items[0] {
998 AnyDescriptor::Other { tag, value } => {
999 assert_eq!(*tag, 0x84);
1000 let c = value.downcast_ref::<PdsAgnostic>().unwrap();
1001 assert_eq!(c.z, 0xDD);
1002 }
1003 other => panic!("expected Other, got {other:?}"),
1004 }
1005 }
1006
1007 #[test]
1008 fn pds_scoped_takes_precedence_over_agnostic() {
1009 #[derive(Debug, PartialEq, Eq)]
1013 #[cfg_attr(feature = "serde", derive(serde::Serialize))]
1014 struct Agnostic83 {
1015 a: u8,
1016 }
1017
1018 impl<'a> broadcast_common::Parse<'a> for Agnostic83 {
1019 type Error = crate::error::Error;
1020 fn parse(bytes: &'a [u8]) -> crate::Result<Self> {
1021 if bytes.len() < 3 {
1022 return Err(crate::error::Error::BufferTooShort(
1023 broadcast_common::error::BufferTooShort {
1024 need: 3,
1025 have: bytes.len(),
1026 what: "Agnostic83",
1027 },
1028 ));
1029 }
1030 Ok(Self { a: bytes[2] })
1031 }
1032 }
1033
1034 impl DescriptorDef<'_> for Agnostic83 {
1035 const TAG: u8 = 0x83;
1036 const NAME: &'static str = "AGNOSTIC_83";
1037 }
1038
1039 let mut reg = DescriptorRegistry::new();
1040 reg.register::<Agnostic83>();
1041 reg.register_for_pds::<PdsEacem>(PDS_EACEM);
1042
1043 let items: Vec<_> = reg
1045 .parse_loop(&[0x83, 0x01, 0xEE])
1046 .collect::<Result<_, _>>()
1047 .unwrap();
1048 match &items[0] {
1049 AnyDescriptor::Other { value, .. } => {
1050 assert!(value.downcast_ref::<Agnostic83>().is_some());
1051 assert!(value.downcast_ref::<PdsEacem>().is_none());
1052 }
1053 other => panic!("expected Other, got {other:?}"),
1054 }
1055
1056 let mut bytes = Vec::new();
1058 bytes.extend_from_slice(&pds_descriptor(PDS_EACEM));
1059 bytes.extend_from_slice(&[0x83, 0x01, 0xFF]);
1060 let items: Vec<_> = reg.parse_loop(&bytes).collect::<Result<_, _>>().unwrap();
1061 match &items[1] {
1062 AnyDescriptor::Other { value, .. } => {
1063 assert!(value.downcast_ref::<PdsEacem>().is_some());
1064 assert!(value.downcast_ref::<Agnostic83>().is_none());
1065 }
1066 other => panic!("expected Other, got {other:?}"),
1067 }
1068 }
1069
1070 fn logical_channel_descriptor(service_id: u16, visible: bool, lcn: u16) -> Vec<u8> {
1071 let mut v = vec![crate::descriptors::logical_channel::TAG, 4];
1073 v.extend_from_slice(&service_id.to_be_bytes());
1074 let flags = (u8::from(visible) << 7) | ((lcn >> 8) as u8 & 0x03);
1075 v.push(flags);
1076 v.push((lcn & 0xFF) as u8);
1077 v
1078 }
1079
1080 #[test]
1081 fn logical_channel_pds_scoped_matches_correct_pds() {
1082 let mut reg = DescriptorRegistry::new();
1083 reg.with_logical_channel_for_pds(PDS_EACEM);
1084
1085 let mut bytes = Vec::new();
1086 bytes.extend_from_slice(&pds_descriptor(PDS_EACEM));
1087 bytes.extend_from_slice(&logical_channel_descriptor(0x1234, true, 101));
1088
1089 let items: Vec<_> = reg.parse_loop(&bytes).collect::<Result<_, _>>().unwrap();
1090 assert_eq!(items.len(), 2);
1091 assert!(matches!(items[0], AnyDescriptor::PrivateDataSpecifier(_)));
1092 match &items[1] {
1093 AnyDescriptor::LogicalChannel(lc) => {
1094 assert_eq!(lc.entries.len(), 1);
1095 assert_eq!(lc.entries[0].service_id, 0x1234);
1096 assert!(lc.entries[0].visible_service);
1097 assert_eq!(lc.entries[0].logical_channel_number, 101);
1098 }
1099 other => panic!("expected LogicalChannel, got {other:?}"),
1100 }
1101 }
1102
1103 #[test]
1104 fn logical_channel_pds_scoped_rejects_no_pds() {
1105 let mut reg = DescriptorRegistry::new();
1106 reg.with_logical_channel_for_pds(PDS_EACEM);
1107
1108 let bytes = logical_channel_descriptor(0x1234, true, 101);
1109 let items: Vec<_> = reg.parse_loop(&bytes).collect::<Result<_, _>>().unwrap();
1110 assert_eq!(items.len(), 1);
1111 assert!(matches!(
1112 &items[0],
1113 AnyDescriptor::Unknown { tag: 0x83, .. }
1114 ));
1115 }
1116
1117 #[test]
1118 fn logical_channel_pds_scoped_rejects_wrong_pds() {
1119 let mut reg = DescriptorRegistry::new();
1120 reg.with_logical_channel_for_pds(PDS_EACEM);
1121
1122 let mut bytes = Vec::new();
1123 bytes.extend_from_slice(&pds_descriptor(PDS_NORDIG));
1124 bytes.extend_from_slice(&logical_channel_descriptor(0x1234, true, 101));
1125
1126 let items: Vec<_> = reg.parse_loop(&bytes).collect::<Result<_, _>>().unwrap();
1127 assert_eq!(items.len(), 2);
1128 assert!(matches!(items[0], AnyDescriptor::PrivateDataSpecifier(_)));
1129 assert!(matches!(
1130 &items[1],
1131 AnyDescriptor::Unknown { tag: 0x83, .. }
1132 ));
1133 }
1134
1135 #[test]
1136 fn logical_channel_pds_scoped_multiple_pds() {
1137 let mut reg = DescriptorRegistry::new();
1138 reg.with_logical_channel_for_pds(PDS_EACEM);
1139 reg.with_logical_channel_for_pds(PDS_NORDIG);
1140
1141 let mut bytes = Vec::new();
1143 bytes.extend_from_slice(&pds_descriptor(PDS_EACEM));
1144 bytes.extend_from_slice(&logical_channel_descriptor(0x0001, true, 1));
1145 let items: Vec<_> = reg.parse_loop(&bytes).collect::<Result<_, _>>().unwrap();
1146 assert!(matches!(&items[1], AnyDescriptor::LogicalChannel(_)));
1147
1148 let mut bytes2 = Vec::new();
1150 bytes2.extend_from_slice(&pds_descriptor(PDS_NORDIG));
1151 bytes2.extend_from_slice(&logical_channel_descriptor(0x0002, false, 2));
1152 let items2: Vec<_> = reg.parse_loop(&bytes2).collect::<Result<_, _>>().unwrap();
1153 assert!(matches!(&items2[1], AnyDescriptor::LogicalChannel(_)));
1154 }
1155
1156 #[test]
1158 fn program_info_registration_scopes_es_info_with_extensions() {
1159 use crate::descriptors::any::DescriptorLoop;
1160 use crate::descriptors::avs3_video::Avs3VideoDescriptor;
1161 use crate::descriptors::extension::registry::ExtensionRegistry;
1162 use crate::descriptors::private_data_specifier::PDS_AVSV;
1163 let program_info = [0x05, 4, b'A', b'V', b'S', b'V'];
1164 let es_info = [0xD1, 8, 0x22, 0x42, 0xAA, 0x4B, 9, 14, 9, 0xFF];
1165 let mut reg = DescriptorRegistry::new();
1166 reg.with_avs3_video();
1167 let ext = ExtensionRegistry::new();
1168
1169 let items: Vec<_> = DescriptorLoop::new(&es_info)
1170 .iter_with_extensions(®, &ext)
1171 .collect::<Result<_, _>>()
1172 .unwrap();
1173 assert!(matches!(
1174 &items[0],
1175 ExtIterItem::Descriptor(AnyDescriptor::Unknown { tag: 0xD1, .. })
1176 ));
1177
1178 let mut pi = DescriptorLoop::new(&program_info).iter_with_extensions(®, &ext);
1179 for item in pi.by_ref() {
1180 item.unwrap();
1181 }
1182 let scope = pi.avs_scope();
1183 assert_eq!(scope, Some(PDS_AVSV));
1184 let items: Vec<_> = DescriptorLoop::new(&es_info)
1185 .iter_with_extensions_in_scope(®, &ext, scope)
1186 .collect::<Result<_, _>>()
1187 .unwrap();
1188 match &items[0] {
1189 ExtIterItem::Descriptor(AnyDescriptor::Other { tag: 0xD1, value }) => {
1190 assert!(value.downcast_ref::<Avs3VideoDescriptor>().is_some());
1191 }
1192 other => panic!("expected Avs3Video via inherited scope, got {other:?}"),
1193 }
1194 }
1195
1196 #[test]
1197 fn iter_with_extensions_surfaces_custom_extension() {
1198 use crate::descriptors::any::{AnyDescriptor, DescriptorLoop};
1199 use crate::descriptors::extension::registry::ExtensionRegistry;
1200
1201 #[derive(Debug, PartialEq, Eq)]
1202 #[cfg_attr(feature = "serde", derive(serde::Serialize))]
1203 struct MyCustomExt {
1204 payload: Vec<u8>,
1205 }
1206
1207 impl<'a> broadcast_common::Parse<'a> for MyCustomExt {
1208 type Error = crate::error::Error;
1209 fn parse(sel: &'a [u8]) -> crate::Result<Self> {
1210 Ok(Self {
1211 payload: sel.to_vec(),
1212 })
1213 }
1214 }
1215
1216 impl crate::descriptors::extension::ExtensionBodyDef<'_> for MyCustomExt {
1217 const TAG_EXTENSION: u8 = 0x42;
1218 const NAME: &'static str = "MY_CUSTOM_EXT";
1219 }
1220
1221 let mut ext_reg = ExtensionRegistry::new();
1222 ext_reg.register::<MyCustomExt>();
1223
1224 let desc_reg = DescriptorRegistry::new();
1225
1226 let mut loop_bytes = vec![
1228 0x4D, 0x07, b'e', b'n', b'g', 0x02, b'H', b'i', 0x00, ];
1230 loop_bytes.extend_from_slice(&[0x7F, 0x03, 0x42, 0xAB, 0xCD]);
1232
1233 let dl = DescriptorLoop::new(&loop_bytes);
1234 let items: Vec<_> = dl
1235 .iter_with_extensions(&desc_reg, &ext_reg)
1236 .collect::<Result<_, _>>()
1237 .unwrap();
1238 assert_eq!(items.len(), 2);
1239 assert!(matches!(
1241 &items[0],
1242 ExtIterItem::Descriptor(AnyDescriptor::ShortEvent(_))
1243 ));
1244 match &items[1] {
1246 ExtIterItem::CustomExtension {
1247 tag_extension,
1248 value,
1249 } => {
1250 assert_eq!(*tag_extension, 0x42);
1251 let concrete = value.downcast_ref::<MyCustomExt>().unwrap();
1252 assert_eq!(concrete.payload, &[0xAB, 0xCD]);
1253 }
1254 other => panic!("expected CustomExtension, got {other:?}"),
1255 }
1256 }
1257}