Skip to main content

dvb_si/collect/
bat.rs

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