1use crate::descriptors::DescriptorRegistry;
2use crate::tables::bat;
3use alloc::vec::Vec;
4
5use super::{CompleteSectionSet, ParsedDescriptorLoop};
6
7#[derive(Debug)]
9#[non_exhaustive]
10pub struct CompleteBatTransportStream<'a> {
11 pub transport_stream_id: u16,
13 pub original_network_id: u16,
15 pub descriptors: ParsedDescriptorLoop<'a>,
17}
18
19#[derive(Debug)]
21#[non_exhaustive]
22pub struct CompleteBat<'a> {
23 pub bouquet_id: u16,
25 pub version_number: u8,
27 pub current_next_indicator: bool,
29 pub bouquet_descriptors: ParsedDescriptorLoop<'a>,
34 pub transport_streams: Vec<CompleteBatTransportStream<'a>>,
36}
37
38impl<'a> CompleteBat<'a> {
39 pub(crate) fn parse(
40 set: &'a CompleteSectionSet,
41 registry: Option<&'a DescriptorRegistry>,
42 ) -> crate::Result<Self> {
43 let sections: Vec<bat::BatSection<'a>> = set.parse_sections()?;
44 let first = sections.first().ok_or(crate::Error::BufferTooShort {
45 need: 1,
46 have: 0,
47 what: "CompleteBat sections",
48 })?;
49 let mut transport_streams = Vec::new();
50 for section in §ions {
51 transport_streams.extend(section.transport_streams.iter().map(|ts| {
52 CompleteBatTransportStream {
53 transport_stream_id: ts.transport_stream_id,
54 original_network_id: ts.original_network_id,
55 descriptors: ParsedDescriptorLoop::parse(ts.descriptors, registry),
56 }
57 }));
58 }
59 Ok(Self {
60 bouquet_id: first.bouquet_id,
61 version_number: first.version_number,
62 current_next_indicator: first.current_next_indicator,
63 bouquet_descriptors: ParsedDescriptorLoop::parse_all(
64 sections.iter().map(|section| section.bouquet_descriptors),
65 registry,
66 ),
67 transport_streams,
68 })
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::super::SectionSetCollector;
75 use crate::descriptors::DescriptorLoop;
76 use crate::tables::bat::BatSection;
77
78 fn build_bat_section(
79 bouquet_id: u16,
80 version: u8,
81 section_number: u8,
82 last_section_number: u8,
83 bouquet_desc: &[u8],
84 ts_entries: &[(u16, u16, &[u8])],
85 ) -> Vec<u8> {
86 use broadcast_common::Serialize;
87 let bat = BatSection::new(
88 bouquet_id,
89 version,
90 true,
91 section_number,
92 last_section_number,
93 DescriptorLoop::new(bouquet_desc),
94 ts_entries
95 .iter()
96 .map(|(tsid, onid, desc)| {
97 crate::tables::bat::BatTransportStream::new(
98 *tsid,
99 *onid,
100 DescriptorLoop::new(desc),
101 )
102 })
103 .collect(),
104 );
105 let mut buf = vec![0u8; bat.serialized_len()];
106 bat.serialize_into(&mut buf).unwrap();
107 buf
108 }
109
110 #[test]
111 fn complete_bat_preserves_bouquet_descriptors_and_ts_entries() {
112 let bouquet_name = [0x47u8, 0x03, b'F', b'o', b'o'];
113 let ts_desc = [0x43u8, 0x01, 0x01];
114
115 let sec = build_bat_section(
116 0x1234,
117 3,
118 0,
119 0,
120 &bouquet_name,
121 &[(0x1001, 0x2002, &ts_desc)],
122 );
123
124 let mut collector = SectionSetCollector::new();
125 let set = collector.push_section(&sec).unwrap().unwrap();
126 let complete = set.bat().unwrap();
127
128 assert_eq!(complete.bouquet_id, 0x1234);
129 assert_eq!(complete.version_number, 3);
130 assert!(complete.current_next_indicator);
131 assert_eq!(complete.transport_streams.len(), 1);
132 assert_eq!(complete.transport_streams[0].transport_stream_id, 0x1001);
133 assert_eq!(complete.transport_streams[0].original_network_id, 0x2002);
134 }
135}