Skip to main content

dvb_si/collect/
bat.rs

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