1use std::collections::{BTreeMap, HashMap};
16use std::sync::Arc;
17
18use crate::descriptors::{AnyDescriptor, DescriptorLoop, DescriptorRegistry};
19use crate::section::Section;
20use crate::tables::{bat, eit, nit, sdt};
21use dvb_common::Parse;
22
23pub type CollectResult<T> = core::result::Result<T, CollectError>;
25
26#[derive(Debug, thiserror::Error)]
32#[non_exhaustive]
33pub enum CollectError {
34 #[error("section parse failed: {0}")]
36 Section(#[from] crate::Error),
37
38 #[error(
40 "table_id {table_id:#04x} is a short-form section and cannot be multi-section collected"
41 )]
42 ShortFormSection {
43 table_id: u8,
45 },
46
47 #[error(
49 "section_number {section_number} exceeds last_section_number {last_section_number} for table_id {table_id:#04x}"
50 )]
51 SectionNumberOutOfRange {
52 table_id: u8,
54 section_number: u8,
56 last_section_number: u8,
58 },
59
60 #[error("conflicting bytes for table_id {table_id:#04x} section {section_number}")]
62 ConflictingSection {
63 table_id: u8,
65 section_number: u8,
67 },
68
69 #[error(
71 "EIT schedule table_id {table_id:#04x} is outside advertised range {first_table_id:#04x}..={last_table_id:#04x}"
72 )]
73 EitTableIdOutOfRange {
74 table_id: u8,
76 first_table_id: u8,
78 last_table_id: u8,
80 },
81}
82
83#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
88pub struct SectionSetKey {
89 pub pid: Option<u16>,
91 pub table_id: u8,
93 pub extension_id: u16,
95 pub current_next_indicator: bool,
97}
98
99#[derive(Debug, Clone, Copy, PartialEq, Eq)]
101pub struct SectionSetMeta {
102 pub key: SectionSetKey,
104 pub version_number: u8,
106 pub last_section_number: u8,
108}
109
110#[derive(Debug)]
111struct PartialSectionSet {
112 meta: SectionSetMeta,
113 slots: Vec<Option<Arc<[u8]>>>,
114 filled: usize,
115 emitted: bool,
116}
117
118impl PartialSectionSet {
119 fn new(meta: SectionSetMeta) -> Self {
120 let len = meta.last_section_number as usize + 1;
121 Self {
122 meta,
123 slots: vec![None; len],
124 filled: 0,
125 emitted: false,
126 }
127 }
128
129 fn reset(&mut self, meta: SectionSetMeta) {
130 *self = Self::new(meta);
131 }
132
133 fn insert(&mut self, section_number: u8, bytes: Arc<[u8]>) -> CollectResult<bool> {
134 let index = section_number as usize;
135 if let Some(existing) = &self.slots[index] {
136 if existing.as_ref() == bytes.as_ref() {
137 return Ok(false);
138 }
139 return Err(CollectError::ConflictingSection {
140 table_id: self.meta.key.table_id,
141 section_number,
142 });
143 }
144
145 self.slots[index] = Some(bytes);
146 self.filled += 1;
147 self.emitted = false;
148 Ok(true)
149 }
150
151 fn complete(&self) -> bool {
152 self.filled == self.slots.len()
153 }
154
155 fn to_complete(&self) -> Option<CompleteSectionSet> {
156 if !self.complete() || self.emitted {
157 return None;
158 }
159
160 let sections = self
161 .slots
162 .iter()
163 .map(|slot| slot.as_ref().expect("complete set has no holes").clone())
164 .collect();
165 Some(CompleteSectionSet {
166 meta: self.meta,
167 sections,
168 })
169 }
170}
171
172#[derive(Debug, Default)]
175pub struct SectionSetCollector {
176 partial: HashMap<SectionSetKey, PartialSectionSet>,
177}
178
179#[derive(Debug, Default)]
185pub struct EitCollector {
186 sections: HashMap<EitSectionSetKey, PartialEitSectionSet>,
187 schedules: HashMap<EitLogicalKey, PartialEitSchedule>,
188}
189
190impl EitCollector {
191 #[must_use]
193 pub fn new() -> Self {
194 Self::default()
195 }
196
197 pub fn push_section(&mut self, bytes: impl AsRef<[u8]>) -> CollectResult<Option<CompletedEit>> {
209 self.push_section_with_pid(None, bytes)
210 }
211
212 pub fn push_section_with_pid(
214 &mut self,
215 pid: Option<u16>,
216 bytes: impl AsRef<[u8]>,
217 ) -> CollectResult<Option<CompletedEit>> {
218 let raw = bytes.as_ref();
219 let section = Section::parse(raw)?;
220 if !section.section_syntax_indicator {
221 return Err(CollectError::ShortFormSection {
222 table_id: section.table_id,
223 });
224 }
225 if section.section_number > section.last_section_number {
226 return Err(CollectError::SectionNumberOutOfRange {
227 table_id: section.table_id,
228 section_number: section.section_number,
229 last_section_number: section.last_section_number,
230 });
231 }
232 section.validate_crc(raw)?;
233
234 let eit = eit::EitSection::parse(raw)?;
235 let logical_key = EitLogicalKey {
236 pid,
237 kind: eit.kind,
238 service_id: eit.service_id,
239 transport_stream_id: eit.transport_stream_id,
240 original_network_id: eit.original_network_id,
241 current_next_indicator: eit.current_next_indicator,
242 };
243 let key = EitSectionSetKey {
244 logical_key,
245 table_id: eit.table_id,
246 };
247 let meta = EitSectionSetMeta {
248 key,
249 version_number: eit.version_number,
250 last_section_number: eit.last_section_number,
251 };
252 let bytes: Arc<[u8]> = Arc::from(raw);
253
254 let partial = self
255 .sections
256 .entry(key)
257 .or_insert_with(|| PartialEitSectionSet::new(meta));
258 if partial.meta.version_number != meta.version_number
259 || partial.meta.last_section_number != meta.last_section_number
260 {
261 partial.reset(meta);
262 }
263
264 partial.insert(eit.section_number, bytes)?;
265 let complete = match partial.to_complete() {
266 Some(complete) => complete,
267 None => return Ok(None),
268 };
269 partial.emitted = true;
270
271 match eit.kind {
272 eit::EitKind::PresentFollowingActual | eit::EitKind::PresentFollowingOther => {
273 Ok(Some(CompletedEit::PresentFollowing(complete)))
274 }
275 eit::EitKind::ScheduleActual | eit::EitKind::ScheduleOther => {
276 let first_table_id = match eit.kind {
277 eit::EitKind::ScheduleActual => eit::TABLE_ID_SCHEDULE_ACTUAL_FIRST,
278 eit::EitKind::ScheduleOther => eit::TABLE_ID_SCHEDULE_OTHER_FIRST,
279 _ => unreachable!("matched schedule kind above"),
280 };
281 if eit.table_id < first_table_id || eit.table_id > eit.last_table_id {
282 return Err(CollectError::EitTableIdOutOfRange {
283 table_id: eit.table_id,
284 first_table_id,
285 last_table_id: eit.last_table_id,
286 });
287 }
288 let meta = EitScheduleMeta {
289 key: logical_key,
290 first_table_id,
291 last_table_id: eit.last_table_id,
292 };
293 let schedule = self
294 .schedules
295 .entry(logical_key)
296 .or_insert_with(|| PartialEitSchedule::new(meta));
297 if schedule.meta.last_table_id != meta.last_table_id {
298 schedule.reset(meta);
299 }
300 schedule.insert(eit.table_id, complete);
301 if let Some(complete) = schedule.to_complete() {
302 schedule.emitted = true;
303 Ok(Some(CompletedEit::Schedule(complete)))
304 } else {
305 Ok(None)
306 }
307 }
308 }
309 }
310
311 pub fn clear(&mut self) {
317 self.sections.clear();
318 self.schedules.clear();
319 }
320
321 pub fn retain_logical<F>(&mut self, mut keep: F)
327 where
328 F: FnMut(&EitLogicalKey) -> bool,
329 {
330 self.sections.retain(|key, _| keep(&key.logical_key));
331 self.schedules.retain(|key, _| keep(key));
332 }
333
334 #[must_use]
336 pub fn section_set_len(&self) -> usize {
337 self.sections.len()
338 }
339
340 #[must_use]
342 pub fn schedule_len(&self) -> usize {
343 self.schedules.len()
344 }
345}
346
347#[derive(Debug, Clone)]
349pub enum CompletedEit {
350 PresentFollowing(CompleteSectionSet),
352 Schedule(CompleteEitSchedule),
354}
355
356impl CompletedEit {
357 pub fn tables(&self) -> crate::Result<Vec<CompleteEit<'_>>> {
359 self.tables_with_registry(None)
360 }
361
362 pub fn tables_with_registry<'a>(
364 &'a self,
365 registry: Option<&'a DescriptorRegistry>,
366 ) -> crate::Result<Vec<CompleteEit<'a>>> {
367 match self {
368 Self::PresentFollowing(set) => Ok(vec![CompleteEit::parse(set, registry)?]),
369 Self::Schedule(schedule) => schedule.tables_with_registry(registry),
370 }
371 }
372}
373
374#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
376pub struct EitLogicalKey {
377 pub pid: Option<u16>,
379 pub kind: eit::EitKind,
381 pub service_id: u16,
383 pub transport_stream_id: u16,
385 pub original_network_id: u16,
387 pub current_next_indicator: bool,
389}
390
391#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
392struct EitSectionSetKey {
393 logical_key: EitLogicalKey,
394 table_id: u8,
395}
396
397#[derive(Debug, Clone, Copy, PartialEq, Eq)]
398struct EitScheduleMeta {
399 key: EitLogicalKey,
400 first_table_id: u8,
401 last_table_id: u8,
402}
403
404#[derive(Debug, Clone, Copy, PartialEq, Eq)]
405struct EitSectionSetMeta {
406 key: EitSectionSetKey,
407 version_number: u8,
408 last_section_number: u8,
409}
410
411#[derive(Debug)]
412struct PartialEitSectionSet {
413 meta: EitSectionSetMeta,
414 slots: Vec<Option<Arc<[u8]>>>,
415 filled: usize,
416 emitted: bool,
417}
418
419impl PartialEitSectionSet {
420 fn new(meta: EitSectionSetMeta) -> Self {
421 let len = meta.last_section_number as usize + 1;
422 Self {
423 meta,
424 slots: vec![None; len],
425 filled: 0,
426 emitted: false,
427 }
428 }
429
430 fn reset(&mut self, meta: EitSectionSetMeta) {
431 *self = Self::new(meta);
432 }
433
434 fn insert(&mut self, section_number: u8, bytes: Arc<[u8]>) -> CollectResult<bool> {
435 let index = section_number as usize;
436 if let Some(existing) = &self.slots[index] {
437 if existing.as_ref() == bytes.as_ref() {
438 return Ok(false);
439 }
440 return Err(CollectError::ConflictingSection {
441 table_id: self.meta.key.table_id,
442 section_number,
443 });
444 }
445
446 self.slots[index] = Some(bytes);
447 self.filled += 1;
448 self.emitted = false;
449 Ok(true)
450 }
451
452 fn complete(&self) -> bool {
453 self.filled == self.slots.len()
454 }
455
456 fn to_complete(&self) -> Option<CompleteSectionSet> {
457 if !self.complete() || self.emitted {
458 return None;
459 }
460
461 let sections = self
462 .slots
463 .iter()
464 .map(|slot| {
465 slot.as_ref()
466 .expect("complete EIT set has no holes")
467 .clone()
468 })
469 .collect();
470 Some(CompleteSectionSet {
471 meta: SectionSetMeta {
472 key: SectionSetKey {
473 pid: self.meta.key.logical_key.pid,
474 table_id: self.meta.key.table_id,
475 extension_id: self.meta.key.logical_key.service_id,
476 current_next_indicator: self.meta.key.logical_key.current_next_indicator,
477 },
478 version_number: self.meta.version_number,
479 last_section_number: self.meta.last_section_number,
480 },
481 sections,
482 })
483 }
484}
485
486#[derive(Debug)]
487struct PartialEitSchedule {
488 meta: EitScheduleMeta,
489 table_sets: BTreeMap<u8, CompleteSectionSet>,
490 emitted: bool,
491}
492
493impl PartialEitSchedule {
494 fn new(meta: EitScheduleMeta) -> Self {
495 Self {
496 meta,
497 table_sets: BTreeMap::new(),
498 emitted: false,
499 }
500 }
501
502 fn reset(&mut self, meta: EitScheduleMeta) {
503 *self = Self::new(meta);
504 }
505
506 fn insert(&mut self, table_id: u8, set: CompleteSectionSet) {
507 self.table_sets.insert(table_id, set);
508 self.emitted = false;
509 }
510
511 fn complete(&self) -> bool {
512 (self.meta.first_table_id..=self.meta.last_table_id)
513 .all(|table_id| self.table_sets.contains_key(&table_id))
514 }
515
516 fn to_complete(&self) -> Option<CompleteEitSchedule> {
517 if !self.complete() || self.emitted {
518 return None;
519 }
520 let table_sets = (self.meta.first_table_id..=self.meta.last_table_id)
521 .map(|table_id| {
522 self.table_sets
523 .get(&table_id)
524 .expect("complete EIT schedule has no missing table IDs")
525 .clone()
526 })
527 .collect();
528 Some(CompleteEitSchedule {
529 first_table_id: self.meta.first_table_id,
530 last_table_id: self.meta.last_table_id,
531 table_sets,
532 })
533 }
534}
535
536#[derive(Debug, Clone)]
539pub struct CompleteEitSchedule {
540 first_table_id: u8,
541 last_table_id: u8,
542 table_sets: Vec<CompleteSectionSet>,
543}
544
545impl CompleteEitSchedule {
546 #[must_use]
548 pub const fn first_table_id(&self) -> u8 {
549 self.first_table_id
550 }
551
552 #[must_use]
554 pub const fn last_table_id(&self) -> u8 {
555 self.last_table_id
556 }
557
558 #[must_use]
560 pub fn table_sets(&self) -> &[CompleteSectionSet] {
561 &self.table_sets
562 }
563
564 pub fn table_versions(&self) -> impl ExactSizeIterator<Item = (u8, u8)> + '_ {
569 self.table_sets
570 .iter()
571 .map(|set| (set.meta.key.table_id, set.meta.version_number))
572 }
573
574 pub fn tables(&self) -> crate::Result<Vec<CompleteEit<'_>>> {
576 self.tables_with_registry(None)
577 }
578
579 pub fn tables_with_registry<'a>(
582 &'a self,
583 registry: Option<&'a DescriptorRegistry>,
584 ) -> crate::Result<Vec<CompleteEit<'a>>> {
585 self.table_sets
586 .iter()
587 .map(|set| CompleteEit::parse(set, registry))
588 .collect()
589 }
590}
591
592impl SectionSetCollector {
593 #[must_use]
595 pub fn new() -> Self {
596 Self::default()
597 }
598
599 pub fn push_section(
609 &mut self,
610 bytes: impl AsRef<[u8]>,
611 ) -> CollectResult<Option<CompleteSectionSet>> {
612 self.push_section_with_pid(None, bytes)
613 }
614
615 pub fn push_section_with_pid(
620 &mut self,
621 pid: Option<u16>,
622 bytes: impl AsRef<[u8]>,
623 ) -> CollectResult<Option<CompleteSectionSet>> {
624 let raw = bytes.as_ref();
625 let section = Section::parse(raw)?;
626 if !section.section_syntax_indicator {
627 return Err(CollectError::ShortFormSection {
628 table_id: section.table_id,
629 });
630 }
631 if section.section_number > section.last_section_number {
632 return Err(CollectError::SectionNumberOutOfRange {
633 table_id: section.table_id,
634 section_number: section.section_number,
635 last_section_number: section.last_section_number,
636 });
637 }
638 section.validate_crc(raw)?;
639
640 let key = SectionSetKey {
641 pid,
642 table_id: section.table_id,
643 extension_id: section.extension_id,
644 current_next_indicator: section.current_next_indicator,
645 };
646 let meta = SectionSetMeta {
647 key,
648 version_number: section.version_number,
649 last_section_number: section.last_section_number,
650 };
651 let bytes: Arc<[u8]> = Arc::from(raw);
652
653 let partial = self
654 .partial
655 .entry(key)
656 .or_insert_with(|| PartialSectionSet::new(meta));
657
658 if partial.meta.version_number != meta.version_number
659 || partial.meta.last_section_number != meta.last_section_number
660 {
661 partial.reset(meta);
662 }
663
664 partial.insert(section.section_number, bytes)?;
665 let complete = partial.to_complete();
666 if complete.is_some() {
667 partial.emitted = true;
668 }
669 Ok(complete)
670 }
671
672 pub fn clear(&mut self) {
674 self.partial.clear();
675 }
676
677 #[must_use]
679 pub fn len(&self) -> usize {
680 self.partial.len()
681 }
682
683 #[must_use]
685 pub fn is_empty(&self) -> bool {
686 self.partial.is_empty()
687 }
688}
689
690#[derive(Debug, Clone)]
693pub struct CompleteSectionSet {
694 meta: SectionSetMeta,
695 sections: Vec<Arc<[u8]>>,
696}
697
698#[derive(Debug)]
706pub struct CompleteTable<T> {
707 meta: SectionSetMeta,
708 sections: Vec<T>,
709}
710
711impl<T> CompleteTable<T> {
712 #[must_use]
714 pub const fn meta(&self) -> SectionSetMeta {
715 self.meta
716 }
717
718 #[must_use]
720 pub fn sections(&self) -> &[T] {
721 &self.sections
722 }
723
724 #[must_use]
726 pub fn into_sections(self) -> Vec<T> {
727 self.sections
728 }
729}
730
731impl CompleteSectionSet {
732 #[must_use]
734 pub const fn meta(&self) -> SectionSetMeta {
735 self.meta
736 }
737
738 #[must_use]
740 pub fn section_bytes(&self) -> impl ExactSizeIterator<Item = &[u8]> {
741 self.sections.iter().map(AsRef::as_ref)
742 }
743
744 pub fn parse_sections<'a, T>(&'a self) -> crate::Result<Vec<T>>
749 where
750 T: Parse<'a, Error = crate::Error>,
751 {
752 self.section_bytes().map(T::parse).collect()
753 }
754
755 pub fn table<'a, T>(&'a self) -> crate::Result<CompleteTable<T>>
760 where
761 T: Parse<'a, Error = crate::Error>,
762 {
763 Ok(CompleteTable {
764 meta: self.meta,
765 sections: self.parse_sections()?,
766 })
767 }
768
769 pub fn nit(&self) -> crate::Result<CompleteNit<'_>> {
771 CompleteNit::parse(self, None)
772 }
773
774 pub fn nit_with_registry<'a>(
776 &'a self,
777 registry: &'a DescriptorRegistry,
778 ) -> crate::Result<CompleteNit<'a>> {
779 CompleteNit::parse(self, Some(registry))
780 }
781
782 pub fn bat(&self) -> crate::Result<CompleteBat<'_>> {
784 CompleteBat::parse(self, None)
785 }
786
787 pub fn bat_with_registry<'a>(
789 &'a self,
790 registry: &'a DescriptorRegistry,
791 ) -> crate::Result<CompleteBat<'a>> {
792 CompleteBat::parse(self, Some(registry))
793 }
794
795 pub fn sdt(&self) -> crate::Result<CompleteSdt<'_>> {
797 CompleteSdt::parse(self, None)
798 }
799
800 pub fn sdt_with_registry<'a>(
802 &'a self,
803 registry: &'a DescriptorRegistry,
804 ) -> crate::Result<CompleteSdt<'a>> {
805 CompleteSdt::parse(self, Some(registry))
806 }
807
808 pub fn eit(&self) -> crate::Result<CompleteEit<'_>> {
810 CompleteEit::parse(self, None)
811 }
812
813 pub fn eit_with_registry<'a>(
815 &'a self,
816 registry: &'a DescriptorRegistry,
817 ) -> crate::Result<CompleteEit<'a>> {
818 CompleteEit::parse(self, Some(registry))
819 }
820}
821
822#[derive(Debug)]
825pub struct ParsedDescriptorLoop<'a> {
826 raw: DescriptorLoop<'a>,
827 descriptors: Vec<crate::Result<AnyDescriptor<'a>>>,
828}
829
830impl<'a> ParsedDescriptorLoop<'a> {
831 fn parse(raw: DescriptorLoop<'a>, registry: Option<&'a DescriptorRegistry>) -> Self {
832 let descriptors = match registry {
833 Some(registry) => registry.parse_loop(raw.raw()).collect(),
834 None => raw.iter().collect(),
835 };
836 Self { raw, descriptors }
837 }
838
839 #[must_use]
841 pub const fn raw(&self) -> DescriptorLoop<'a> {
842 self.raw
843 }
844
845 pub fn descriptors(&self) -> &[crate::Result<AnyDescriptor<'a>>] {
847 &self.descriptors
848 }
849}
850
851#[derive(Debug)]
853pub struct CompleteNitTransportStream<'a> {
854 pub transport_stream_id: u16,
856 pub original_network_id: u16,
858 pub descriptors: ParsedDescriptorLoop<'a>,
860}
861
862#[derive(Debug)]
864pub struct CompleteNit<'a> {
865 pub kind: nit::NitKind,
867 pub network_id: u16,
869 pub version_number: u8,
871 pub current_next_indicator: bool,
873 pub network_descriptors: ParsedDescriptorLoop<'a>,
875 pub transport_streams: Vec<CompleteNitTransportStream<'a>>,
877}
878
879impl<'a> CompleteNit<'a> {
880 fn parse(
881 set: &'a CompleteSectionSet,
882 registry: Option<&'a DescriptorRegistry>,
883 ) -> crate::Result<Self> {
884 let sections: Vec<nit::NitSection<'a>> = set.parse_sections()?;
885 let first = sections.first().ok_or(crate::Error::BufferTooShort {
886 need: 1,
887 have: 0,
888 what: "CompleteNit sections",
889 })?;
890 let mut transport_streams = Vec::new();
891 for section in §ions {
892 transport_streams.extend(section.transport_streams.iter().map(|ts| {
893 CompleteNitTransportStream {
894 transport_stream_id: ts.transport_stream_id,
895 original_network_id: ts.original_network_id,
896 descriptors: ParsedDescriptorLoop::parse(ts.descriptors, registry),
897 }
898 }));
899 }
900 Ok(Self {
901 kind: first.kind,
902 network_id: first.network_id,
903 version_number: first.version_number,
904 current_next_indicator: first.current_next_indicator,
905 network_descriptors: ParsedDescriptorLoop::parse(first.network_descriptors, registry),
909 transport_streams,
910 })
911 }
912}
913
914#[derive(Debug)]
916pub struct CompleteBatTransportStream<'a> {
917 pub transport_stream_id: u16,
919 pub original_network_id: u16,
921 pub descriptors: ParsedDescriptorLoop<'a>,
923}
924
925#[derive(Debug)]
927pub struct CompleteBat<'a> {
928 pub bouquet_id: u16,
930 pub version_number: u8,
932 pub current_next_indicator: bool,
934 pub bouquet_descriptors: ParsedDescriptorLoop<'a>,
936 pub transport_streams: Vec<CompleteBatTransportStream<'a>>,
938}
939
940impl<'a> CompleteBat<'a> {
941 fn parse(
942 set: &'a CompleteSectionSet,
943 registry: Option<&'a DescriptorRegistry>,
944 ) -> crate::Result<Self> {
945 let sections: Vec<bat::BatSection<'a>> = set.parse_sections()?;
946 let first = sections.first().ok_or(crate::Error::BufferTooShort {
947 need: 1,
948 have: 0,
949 what: "CompleteBat sections",
950 })?;
951 let mut transport_streams = Vec::new();
952 for section in §ions {
953 transport_streams.extend(section.transport_streams.iter().map(|ts| {
954 CompleteBatTransportStream {
955 transport_stream_id: ts.transport_stream_id,
956 original_network_id: ts.original_network_id,
957 descriptors: ParsedDescriptorLoop::parse(ts.descriptors, registry),
958 }
959 }));
960 }
961 Ok(Self {
962 bouquet_id: first.bouquet_id,
963 version_number: first.version_number,
964 current_next_indicator: first.current_next_indicator,
965 bouquet_descriptors: ParsedDescriptorLoop::parse(first.bouquet_descriptors, registry),
969 transport_streams,
970 })
971 }
972}
973
974#[derive(Debug)]
976pub struct CompleteSdtService<'a> {
977 pub service_id: u16,
979 pub eit_schedule_flag: bool,
981 pub eit_present_following_flag: bool,
983 pub running_status: u8,
985 pub free_ca_mode: bool,
987 pub descriptors: ParsedDescriptorLoop<'a>,
989}
990
991#[derive(Debug)]
993pub struct CompleteSdt<'a> {
994 pub kind: sdt::SdtKind,
996 pub transport_stream_id: u16,
998 pub version_number: u8,
1000 pub current_next_indicator: bool,
1002 pub original_network_id: u16,
1004 pub services: Vec<CompleteSdtService<'a>>,
1006}
1007
1008impl<'a> CompleteSdt<'a> {
1009 fn parse(
1010 set: &'a CompleteSectionSet,
1011 registry: Option<&'a DescriptorRegistry>,
1012 ) -> crate::Result<Self> {
1013 let sections: Vec<sdt::SdtSection<'a>> = set.parse_sections()?;
1014 let first = sections.first().ok_or(crate::Error::BufferTooShort {
1015 need: 1,
1016 have: 0,
1017 what: "CompleteSdt sections",
1018 })?;
1019 let mut services = Vec::new();
1020 for section in §ions {
1021 services.extend(section.services.iter().map(|svc| CompleteSdtService {
1022 service_id: svc.service_id,
1023 eit_schedule_flag: svc.eit_schedule_flag,
1024 eit_present_following_flag: svc.eit_present_following_flag,
1025 running_status: svc.running_status,
1026 free_ca_mode: svc.free_ca_mode,
1027 descriptors: ParsedDescriptorLoop::parse(svc.descriptors, registry),
1028 }));
1029 }
1030 Ok(Self {
1031 kind: first.kind,
1032 transport_stream_id: first.transport_stream_id,
1033 version_number: first.version_number,
1034 current_next_indicator: first.current_next_indicator,
1035 original_network_id: first.original_network_id,
1036 services,
1037 })
1038 }
1039}
1040
1041#[derive(Debug)]
1043pub struct CompleteEitEvent<'a> {
1044 pub event_id: u16,
1046 pub start_time_raw: [u8; 5],
1048 pub duration_raw: [u8; 3],
1050 pub running_status: u8,
1052 pub free_ca_mode: bool,
1054 pub descriptors: ParsedDescriptorLoop<'a>,
1056}
1057
1058#[derive(Debug)]
1064pub struct CompleteEit<'a> {
1065 pub kind: eit::EitKind,
1067 pub table_id: u8,
1069 pub service_id: u16,
1071 pub version_number: u8,
1073 pub current_next_indicator: bool,
1075 pub transport_stream_id: u16,
1077 pub original_network_id: u16,
1079 pub segment_last_section_number: u8,
1081 pub last_table_id: u8,
1083 pub events: Vec<CompleteEitEvent<'a>>,
1085}
1086
1087impl<'a> CompleteEit<'a> {
1088 fn parse(
1089 set: &'a CompleteSectionSet,
1090 registry: Option<&'a DescriptorRegistry>,
1091 ) -> crate::Result<Self> {
1092 let sections: Vec<eit::EitSection<'a>> = set.parse_sections()?;
1093 let first = sections.first().ok_or(crate::Error::BufferTooShort {
1094 need: 1,
1095 have: 0,
1096 what: "CompleteEit sections",
1097 })?;
1098 let mut events = Vec::new();
1099 for section in §ions {
1100 events.extend(section.events.iter().map(|event| CompleteEitEvent {
1101 event_id: event.event_id,
1102 start_time_raw: event.start_time_raw,
1103 duration_raw: event.duration_raw,
1104 running_status: event.running_status,
1105 free_ca_mode: event.free_ca_mode,
1106 descriptors: ParsedDescriptorLoop::parse(event.descriptors, registry),
1107 }));
1108 }
1109 Ok(Self {
1110 kind: first.kind,
1111 table_id: first.table_id,
1112 service_id: first.service_id,
1113 version_number: first.version_number,
1114 current_next_indicator: first.current_next_indicator,
1115 transport_stream_id: first.transport_stream_id,
1116 original_network_id: first.original_network_id,
1117 segment_last_section_number: first.segment_last_section_number,
1118 last_table_id: first.last_table_id,
1119 events,
1120 })
1121 }
1122}