Skip to main content

dvb_si/descriptors/
fmx_buffer_size.rs

1//! FmxBufferSize Descriptor — ISO/IEC 13818-1 §2.6.50, Table 2-80 (tag 0x22).
2//!
3//! Carries a DefaultFlexMuxBufferDescriptor() followed by a loop of
4//! FlexMuxBufferDescriptor() entries — both from ISO/IEC 14496-1 §11.2,
5//! carried as opaque bytes.
6
7use super::descriptor_body;
8use crate::error::{Error, Result};
9use dvb_common::{Parse, Serialize};
10
11/// Descriptor tag for FmxBufferSize_descriptor.
12pub const TAG: u8 = 0x22;
13const HEADER_LEN: usize = 2;
14
15/// FmxBufferSize Descriptor.
16#[derive(Debug, Clone, PartialEq, Eq)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize))]
18#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
19pub struct FmxBufferSizeDescriptor<'a> {
20    /// DefaultFlexMuxBufferDescriptor() carried as opaque bytes.
21    #[cfg_attr(feature = "serde", serde(borrow))]
22    pub default_flex_mux_buffer_descriptor: &'a [u8],
23    /// FlexMuxBufferDescriptor() entries, each 4 opaque bytes.
24    #[cfg_attr(feature = "serde", serde(borrow))]
25    pub flex_mux_buffer_descriptors: &'a [u8],
26}
27
28impl<'a> Parse<'a> for FmxBufferSizeDescriptor<'a> {
29    type Error = crate::error::Error;
30
31    fn parse(bytes: &'a [u8]) -> Result<Self> {
32        let body = descriptor_body(
33            bytes,
34            TAG,
35            "FmxBufferSizeDescriptor",
36            "unexpected tag for FmxBufferSize_descriptor",
37        )?;
38        // The DefaultFlexMuxBufferDescriptor length is not fixed by the spec;
39        // it is determined by the descriptor_length. The spec says:
40        // "for (i = 0; i < descriptor_length; i += 4)" after DefaultFlexMuxBufferDescriptor().
41        // This means the DefaultFlexMuxBufferDescriptor size is descriptor_length % 4,
42        // and the rest is FlexMuxBufferDescriptor entries.
43        // However, without knowing the Default... size, we cannot split safely.
44        // We store the whole body as opaque, with a warning.
45        //
46        // Actually, looking more carefully: the spec shows the loop advances i+=4
47        // starting *after* DefaultFlexMuxBufferDescriptor(). That means Default is
48        // the first (descriptor_length % 4) != 0 bytes or a well-known size. But
49        // the size is not specified in ISO/IEC 13818-1. We'll split via total
50        // descriptor_length mod 4 — if non-zero, the remainder is Default.
51        //
52        // Simpler: the DefaultFlexMuxBufferDescriptor() size is descriptor_length % 4
53        // (because FlexMuxBufferDescriptor entries are each 4 bytes). If length is
54        // a multiple of 4, Default size is 0.
55
56        let default_len = body.len() % 4;
57        Ok(Self {
58            default_flex_mux_buffer_descriptor: &body[..default_len],
59            flex_mux_buffer_descriptors: &body[default_len..],
60        })
61    }
62}
63
64impl Serialize for FmxBufferSizeDescriptor<'_> {
65    type Error = crate::error::Error;
66
67    fn serialized_len(&self) -> usize {
68        HEADER_LEN
69            + self.default_flex_mux_buffer_descriptor.len()
70            + self.flex_mux_buffer_descriptors.len()
71    }
72
73    fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
74        let len = self.serialized_len();
75        if buf.len() < len {
76            return Err(Error::OutputBufferTooSmall {
77                need: len,
78                have: buf.len(),
79            });
80        }
81        buf[0] = TAG;
82        buf[1] = (len - HEADER_LEN) as u8;
83        let mut off = HEADER_LEN;
84        buf[off..off + self.default_flex_mux_buffer_descriptor.len()]
85            .copy_from_slice(self.default_flex_mux_buffer_descriptor);
86        off += self.default_flex_mux_buffer_descriptor.len();
87        buf[off..len].copy_from_slice(self.flex_mux_buffer_descriptors);
88        Ok(len)
89    }
90}
91impl<'a> crate::traits::DescriptorDef<'a> for FmxBufferSizeDescriptor<'a> {
92    const TAG: u8 = TAG;
93    const NAME: &'static str = "FMX_BUFFER_SIZE";
94}
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99
100    #[test]
101    fn parse_no_default() {
102        let bytes = [TAG, 4, 0x01, 0x02, 0x03, 0x04];
103        let d = FmxBufferSizeDescriptor::parse(&bytes).unwrap();
104        assert!(d.default_flex_mux_buffer_descriptor.is_empty());
105        assert_eq!(d.flex_mux_buffer_descriptors, &[0x01, 0x02, 0x03, 0x04]);
106    }
107
108    #[test]
109    fn parse_with_default() {
110        let bytes = [TAG, 7, 0xAA, 0xBB, 0xCC, 0x01, 0x02, 0x03, 0x04];
111        let d = FmxBufferSizeDescriptor::parse(&bytes).unwrap();
112        assert_eq!(d.default_flex_mux_buffer_descriptor, &[0xAA, 0xBB, 0xCC]);
113        assert_eq!(d.flex_mux_buffer_descriptors, &[0x01, 0x02, 0x03, 0x04]);
114    }
115
116    #[test]
117    fn parse_empty_all() {
118        let d = FmxBufferSizeDescriptor::parse(&[TAG, 0]).unwrap();
119        assert!(d.default_flex_mux_buffer_descriptor.is_empty());
120        assert!(d.flex_mux_buffer_descriptors.is_empty());
121    }
122
123    #[test]
124    fn parse_rejects_wrong_tag() {
125        let err = FmxBufferSizeDescriptor::parse(&[0x02, 0]).unwrap_err();
126        assert!(matches!(err, Error::InvalidDescriptor { tag: 0x02, .. }));
127    }
128
129    #[test]
130    fn serialize_round_trip() {
131        let d = FmxBufferSizeDescriptor {
132            default_flex_mux_buffer_descriptor: &[0xDD],
133            flex_mux_buffer_descriptors: &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
134        };
135        let mut buf = vec![0u8; d.serialized_len()];
136        d.serialize_into(&mut buf).unwrap();
137        let reparsed = FmxBufferSizeDescriptor::parse(&buf).unwrap();
138        assert_eq!(d, reparsed);
139    }
140
141    #[test]
142    fn serialize_rejects_small_buffer() {
143        let d = FmxBufferSizeDescriptor {
144            default_flex_mux_buffer_descriptor: &[],
145            flex_mux_buffer_descriptors: &[1, 2, 3, 4],
146        };
147        let mut tiny = vec![0u8; 3];
148        let err = d.serialize_into(&mut tiny).unwrap_err();
149        assert!(matches!(err, Error::OutputBufferTooSmall { .. }));
150    }
151}