Skip to main content

dvb_si/descriptors/
adaptation_field_data.rs

1//! Adaptation Field Data Descriptor — ETSI EN 300 468 §6.2.1 (tag 0x70, Table 13, PDF p. 54).
2//!
3//! Carried inside the PMT ES_info loop. Fixed 1-byte body: a bit-flag field
4//! `adaptation_field_data_identifier` signalling which data fields are carried
5//! in the adaptation field private_data (Table 14).
6
7use super::descriptor_body;
8use crate::error::{Error, Result};
9use dvb_common::{Parse, Serialize};
10
11/// Descriptor tag for adaptation_field_data_descriptor.
12pub const TAG: u8 = 0x70;
13/// Length of the header (tag byte + length byte).
14pub const HEADER_LEN: usize = 2;
15/// Fixed body length: one identifier flag byte.
16pub const BODY_LEN: usize = 1;
17
18/// Table 14 bit positions (0-based from LSB): `b₁` = bit 0, `b₂` = bit 1, …
19const ANNOUNCEMENT_SWITCHING_DATA: u8 = 1 << 0;
20const AU_INFORMATION: u8 = 1 << 1;
21const PVR_ASSIST_INFORMATION: u8 = 1 << 2;
22
23/// Decoded adaptation field data flags — ETSI EN 300 468 Table 14.
24///
25/// Bit numbering per the spec: `b₁` (LSB, transmitted last per §5.1.6)
26/// through `b₈` (MSB).
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub struct AdaptationFieldDataFlags {
29    /// Announcement switching data (`b₁` = bit 0).
30    pub announcement_switching_data: bool,
31    /// AU information (`b₂` = bit 1).
32    pub au_information: bool,
33    /// PVR assist information (`b₃` = bit 2).
34    pub pvr_assist_information: bool,
35}
36
37/// Adaptation Field Data Descriptor.
38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39#[cfg_attr(feature = "serde", derive(serde::Serialize))]
40pub struct AdaptationFieldDataDescriptor {
41    /// 8-bit adaptation_field_data_identifier flag field (Table 14).
42    pub adaptation_field_data_identifier: u8,
43}
44
45impl AdaptationFieldDataDescriptor {
46    /// Decodes the `adaptation_field_data_identifier` flag byte into named
47    /// booleans per ETSI EN 300 468 Table 14.
48    #[must_use]
49    pub fn flags(&self) -> AdaptationFieldDataFlags {
50        let b = self.adaptation_field_data_identifier;
51        AdaptationFieldDataFlags {
52            announcement_switching_data: (b & ANNOUNCEMENT_SWITCHING_DATA) != 0,
53            au_information: (b & AU_INFORMATION) != 0,
54            pvr_assist_information: (b & PVR_ASSIST_INFORMATION) != 0,
55        }
56    }
57}
58
59impl<'a> Parse<'a> for AdaptationFieldDataDescriptor {
60    type Error = crate::error::Error;
61    fn parse(bytes: &'a [u8]) -> Result<Self> {
62        let body = descriptor_body(
63            bytes,
64            TAG,
65            "AdaptationFieldDataDescriptor",
66            "unexpected tag for adaptation_field_data_descriptor",
67        )?;
68        if body.len() != BODY_LEN {
69            return Err(Error::InvalidDescriptor {
70                tag: TAG,
71                reason: "adaptation_field_data_descriptor length must be exactly 1",
72            });
73        }
74        Ok(Self {
75            adaptation_field_data_identifier: body[0],
76        })
77    }
78}
79
80impl Serialize for AdaptationFieldDataDescriptor {
81    type Error = crate::error::Error;
82    fn serialized_len(&self) -> usize {
83        HEADER_LEN + BODY_LEN
84    }
85
86    fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
87        let len = self.serialized_len();
88        if buf.len() < len {
89            return Err(Error::OutputBufferTooSmall {
90                need: len,
91                have: buf.len(),
92            });
93        }
94        buf[0] = TAG;
95        buf[1] = BODY_LEN as u8;
96        buf[HEADER_LEN] = self.adaptation_field_data_identifier;
97        Ok(len)
98    }
99}
100impl<'a> crate::traits::DescriptorDef<'a> for AdaptationFieldDataDescriptor {
101    const TAG: u8 = TAG;
102    const NAME: &'static str = "ADAPTATION_FIELD_DATA";
103}
104
105#[cfg(test)]
106mod tests {
107    use super::*;
108
109    #[test]
110    fn parse_extracts_identifier() {
111        let bytes = [TAG, 1, 0x07];
112        let d = AdaptationFieldDataDescriptor::parse(&bytes).unwrap();
113        assert_eq!(d.adaptation_field_data_identifier, 0x07);
114    }
115
116    #[test]
117    fn flags_decode_all_set() {
118        // bits 0,1,2 set → 0b0000_0111 = 0x07
119        let d = AdaptationFieldDataDescriptor {
120            adaptation_field_data_identifier: 0x07,
121        };
122        let f = d.flags();
123        assert!(f.announcement_switching_data);
124        assert!(f.au_information);
125        assert!(f.pvr_assist_information);
126    }
127
128    #[test]
129    fn flags_decode_none_set() {
130        let d = AdaptationFieldDataDescriptor {
131            adaptation_field_data_identifier: 0x00,
132        };
133        let f = d.flags();
134        assert!(!f.announcement_switching_data);
135        assert!(!f.au_information);
136        assert!(!f.pvr_assist_information);
137    }
138
139    #[test]
140    fn flags_decode_au_only() {
141        // bit 1 only → 0b0000_0010 = 0x02
142        let d = AdaptationFieldDataDescriptor {
143            adaptation_field_data_identifier: 0x02,
144        };
145        let f = d.flags();
146        assert!(!f.announcement_switching_data);
147        assert!(f.au_information);
148        assert!(!f.pvr_assist_information);
149    }
150
151    #[test]
152    fn flags_decode_pvr_only() {
153        // bit 2 only → 0b0000_0100 = 0x04
154        let d = AdaptationFieldDataDescriptor {
155            adaptation_field_data_identifier: 0x04,
156        };
157        let f = d.flags();
158        assert!(!f.announcement_switching_data);
159        assert!(!f.au_information);
160        assert!(f.pvr_assist_information);
161    }
162
163    #[test]
164    fn parse_rejects_wrong_tag() {
165        assert!(matches!(
166            AdaptationFieldDataDescriptor::parse(&[0x71, 1, 0]).unwrap_err(),
167            Error::InvalidDescriptor { tag: 0x71, .. }
168        ));
169    }
170
171    #[test]
172    fn parse_rejects_wrong_length() {
173        assert!(matches!(
174            AdaptationFieldDataDescriptor::parse(&[TAG, 0]).unwrap_err(),
175            Error::InvalidDescriptor { tag: TAG, .. }
176        ));
177    }
178
179    #[test]
180    fn parse_rejects_short_body() {
181        assert!(matches!(
182            AdaptationFieldDataDescriptor::parse(&[TAG, 1]).unwrap_err(),
183            Error::BufferTooShort { .. }
184        ));
185    }
186
187    #[test]
188    fn serialize_round_trip() {
189        let d = AdaptationFieldDataDescriptor {
190            adaptation_field_data_identifier: 0x05,
191        };
192        let mut buf = vec![0u8; d.serialized_len()];
193        d.serialize_into(&mut buf).unwrap();
194        assert_eq!(buf, [TAG, 1, 0x05]);
195        assert_eq!(AdaptationFieldDataDescriptor::parse(&buf).unwrap(), d);
196    }
197
198    #[test]
199    fn serialize_rejects_too_small_buffer() {
200        let d = AdaptationFieldDataDescriptor {
201            adaptation_field_data_identifier: 0,
202        };
203        let mut buf = vec![0u8; 2];
204        assert!(matches!(
205            d.serialize_into(&mut buf).unwrap_err(),
206            Error::OutputBufferTooSmall { .. }
207        ));
208    }
209
210    #[cfg(feature = "serde")]
211    #[test]
212    fn serde_round_trip() {
213        let d = AdaptationFieldDataDescriptor {
214            adaptation_field_data_identifier: 0x05,
215        };
216        let json = serde_json::to_string(&d).unwrap();
217        // Serialize-only: assert the emitted JSON re-parses (serialize-stable).
218        let _v: serde_json::Value = serde_json::from_str(&json).unwrap();
219    }
220}