Skip to main content

dvb_si/descriptors/
flex_mux_timing.rs

1//! FlexMuxTiming Descriptor — ISO/IEC 13818-1 §2.6.54, Table 2-82 (tag 0x2C).
2//!
3//! Carries flex-mux timing parameters: FCR_ES_ID, FCRResolution, FCRLength,
4//! and FmxRateLength.
5
6use super::descriptor_body;
7use crate::error::{Error, Result};
8use dvb_common::{Parse, Serialize};
9
10/// Descriptor tag for FlexMuxTiming_descriptor.
11pub const TAG: u8 = 0x2C;
12const HEADER_LEN: usize = 2;
13const BODY_LEN: u8 = 10;
14
15/// FlexMuxTiming Descriptor.
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize))]
18pub struct FlexMuxTimingDescriptor {
19    /// ES_ID of the FlexMux clock reference stream.
20    pub fcr_es_id: u16,
21    /// Clock resolution in Hz.
22    pub fcr_resolution: u32,
23    /// FCR length in bytes.
24    pub fcr_length: u8,
25    /// FlexMux rate length in bits.
26    pub fmx_rate_length: u8,
27}
28
29impl<'a> Parse<'a> for FlexMuxTimingDescriptor {
30    type Error = crate::error::Error;
31
32    fn parse(bytes: &'a [u8]) -> Result<Self> {
33        let body = descriptor_body(
34            bytes,
35            TAG,
36            "FlexMuxTimingDescriptor",
37            "unexpected tag for FlexMuxTiming_descriptor",
38        )?;
39        if body.len() != BODY_LEN as usize {
40            return Err(Error::InvalidDescriptor {
41                tag: TAG,
42                reason: "FlexMuxTiming_descriptor length must equal 10",
43            });
44        }
45        Ok(Self {
46            fcr_es_id: u16::from_be_bytes([body[0], body[1]]),
47            fcr_resolution: u32::from_be_bytes([body[2], body[3], body[4], body[5]]),
48            fcr_length: body[6],
49            fmx_rate_length: body[7],
50        })
51    }
52}
53
54impl Serialize for FlexMuxTimingDescriptor {
55    type Error = crate::error::Error;
56
57    fn serialized_len(&self) -> usize {
58        HEADER_LEN + BODY_LEN as usize
59    }
60
61    fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
62        let len = self.serialized_len();
63        if buf.len() < len {
64            return Err(Error::OutputBufferTooSmall {
65                need: len,
66                have: buf.len(),
67            });
68        }
69        buf[0] = TAG;
70        buf[1] = BODY_LEN;
71        buf[HEADER_LEN..HEADER_LEN + 2].copy_from_slice(&self.fcr_es_id.to_be_bytes());
72        buf[HEADER_LEN + 2..HEADER_LEN + 6].copy_from_slice(&self.fcr_resolution.to_be_bytes());
73        buf[HEADER_LEN + 6] = self.fcr_length;
74        buf[HEADER_LEN + 7] = self.fmx_rate_length;
75        Ok(len)
76    }
77}
78impl<'a> crate::traits::DescriptorDef<'a> for FlexMuxTimingDescriptor {
79    const TAG: u8 = TAG;
80    const NAME: &'static str = "FLEX_MUX_TIMING";
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    #[test]
88    fn parse_extracts_fields() {
89        let bytes = [
90            TAG, 10, 0x00, 0x01, 0x12, 0x34, 0x56, 0x78, 0x05, 0x1E, 0, 0,
91        ];
92        let d = FlexMuxTimingDescriptor::parse(&bytes).unwrap();
93        assert_eq!(d.fcr_es_id, 0x0001);
94        assert_eq!(d.fcr_resolution, 0x12345678);
95        assert_eq!(d.fcr_length, 0x05);
96        assert_eq!(d.fmx_rate_length, 0x1E);
97    }
98
99    #[test]
100    fn parse_rejects_wrong_tag() {
101        let err =
102            FlexMuxTimingDescriptor::parse(&[0x02, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).unwrap_err();
103        assert!(matches!(err, Error::InvalidDescriptor { tag: 0x02, .. }));
104    }
105
106    #[test]
107    fn parse_rejects_wrong_length() {
108        let err = FlexMuxTimingDescriptor::parse(&[TAG, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0]).unwrap_err();
109        assert!(matches!(err, Error::InvalidDescriptor { .. }));
110    }
111
112    #[test]
113    fn parse_rejects_short_buffer() {
114        let err = FlexMuxTimingDescriptor::parse(&[TAG, 11, 0, 0]).unwrap_err();
115        assert!(matches!(err, Error::BufferTooShort { .. }));
116    }
117
118    #[test]
119    fn serialize_round_trip() {
120        let d = FlexMuxTimingDescriptor {
121            fcr_es_id: 0xBEEF,
122            fcr_resolution: 0xDEADBEEF,
123            fcr_length: 0x42,
124            fmx_rate_length: 0x99,
125        };
126        let mut buf = vec![0u8; d.serialized_len()];
127        d.serialize_into(&mut buf).unwrap();
128        let reparsed = FlexMuxTimingDescriptor::parse(&buf).unwrap();
129        assert_eq!(d, reparsed);
130    }
131
132    #[test]
133    fn serialize_rejects_small_buffer() {
134        let d = FlexMuxTimingDescriptor {
135            fcr_es_id: 0,
136            fcr_resolution: 0,
137            fcr_length: 0,
138            fmx_rate_length: 0,
139        };
140        let mut tiny = vec![0u8; 5];
141        let err = d.serialize_into(&mut tiny).unwrap_err();
142        assert!(matches!(err, Error::OutputBufferTooSmall { .. }));
143    }
144}