1use crate::error::{Error, Result};
14use crate::traits::Descriptor;
15use dvb_common::{Parse, Serialize};
16
17pub const TAG: u8 = 0x77;
19const HEADER_LEN: usize = 2;
20const FIXED_LEN: usize = 3;
21
22const MPE_FEC_MAX: u8 = 0x03;
24const FRAME_SIZE_MAX: u8 = 0x07;
26const MAX_AVERAGE_RATE_MAX: u8 = 0x0F;
28const TIME_SLICE_FEC_ID_MAX: u8 = 0x0F;
30
31#[derive(Debug, Clone, PartialEq, Eq)]
33#[cfg_attr(feature = "serde", derive(serde::Serialize))]
34pub struct TimeSliceFecIdentifierDescriptor<'a> {
35 pub time_slicing: bool,
37 pub mpe_fec: u8,
39 pub frame_size: u8,
41 pub max_burst_duration: u8,
43 pub max_average_rate: u8,
45 pub time_slice_fec_id: u8,
47 pub id_selector: &'a [u8],
49}
50
51impl<'a> Parse<'a> for TimeSliceFecIdentifierDescriptor<'a> {
52 type Error = crate::error::Error;
53 fn parse(bytes: &'a [u8]) -> Result<Self> {
54 if bytes.len() < HEADER_LEN {
55 return Err(Error::BufferTooShort {
56 need: HEADER_LEN,
57 have: bytes.len(),
58 what: "TimeSliceFecIdentifierDescriptor header",
59 });
60 }
61 if bytes[0] != TAG {
62 return Err(Error::InvalidDescriptor {
63 tag: bytes[0],
64 reason: "unexpected tag for time_slice_fec_identifier_descriptor",
65 });
66 }
67 let length = bytes[1] as usize;
68 let end = HEADER_LEN + length;
69 if bytes.len() < end {
70 return Err(Error::BufferTooShort {
71 need: end,
72 have: bytes.len(),
73 what: "TimeSliceFecIdentifierDescriptor body",
74 });
75 }
76 if length < FIXED_LEN {
77 return Err(Error::InvalidDescriptor {
78 tag: TAG,
79 reason: "time_slice_fec_identifier_descriptor body shorter than 3 bytes",
80 });
81 }
82 let body = &bytes[HEADER_LEN..end];
83 let b0 = body[0];
84 let time_slicing = (b0 & 0x80) != 0;
85 let mpe_fec = (b0 >> 5) & MPE_FEC_MAX;
86 let frame_size = b0 & FRAME_SIZE_MAX;
88 let max_burst_duration = body[1];
89 let max_average_rate = (body[2] >> 4) & MAX_AVERAGE_RATE_MAX;
90 let time_slice_fec_id = body[2] & TIME_SLICE_FEC_ID_MAX;
91 let id_selector = &body[FIXED_LEN..];
92 Ok(Self {
93 time_slicing,
94 mpe_fec,
95 frame_size,
96 max_burst_duration,
97 max_average_rate,
98 time_slice_fec_id,
99 id_selector,
100 })
101 }
102}
103
104impl Serialize for TimeSliceFecIdentifierDescriptor<'_> {
105 type Error = crate::error::Error;
106 fn serialized_len(&self) -> usize {
107 HEADER_LEN + FIXED_LEN + self.id_selector.len()
108 }
109
110 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
111 if self.mpe_fec > MPE_FEC_MAX {
112 return Err(Error::InvalidDescriptor {
113 tag: TAG,
114 reason: "mpe_fec exceeds 2 bits",
115 });
116 }
117 if self.frame_size > FRAME_SIZE_MAX {
118 return Err(Error::InvalidDescriptor {
119 tag: TAG,
120 reason: "frame_size exceeds 3 bits",
121 });
122 }
123 if self.max_average_rate > MAX_AVERAGE_RATE_MAX {
124 return Err(Error::InvalidDescriptor {
125 tag: TAG,
126 reason: "max_average_rate exceeds 4 bits",
127 });
128 }
129 if self.time_slice_fec_id > TIME_SLICE_FEC_ID_MAX {
130 return Err(Error::InvalidDescriptor {
131 tag: TAG,
132 reason: "time_slice_fec_id exceeds 4 bits",
133 });
134 }
135 if FIXED_LEN + self.id_selector.len() > u8::MAX as usize {
136 return Err(Error::InvalidDescriptor {
137 tag: TAG,
138 reason: "time_slice_fec_identifier_descriptor body exceeds 255 bytes",
139 });
140 }
141 let len = self.serialized_len();
142 if buf.len() < len {
143 return Err(Error::OutputBufferTooSmall {
144 need: len,
145 have: buf.len(),
146 });
147 }
148 buf[0] = TAG;
149 buf[1] = (FIXED_LEN + self.id_selector.len()) as u8;
150 buf[2] = (u8::from(self.time_slicing) << 7)
152 | ((self.mpe_fec & MPE_FEC_MAX) << 5)
153 | 0x18
154 | (self.frame_size & FRAME_SIZE_MAX);
155 buf[3] = self.max_burst_duration;
156 buf[4] = ((self.max_average_rate & MAX_AVERAGE_RATE_MAX) << 4)
157 | (self.time_slice_fec_id & TIME_SLICE_FEC_ID_MAX);
158 buf[HEADER_LEN + FIXED_LEN..len].copy_from_slice(self.id_selector);
159 Ok(len)
160 }
161}
162
163impl<'a> Descriptor<'a> for TimeSliceFecIdentifierDescriptor<'a> {
164 const TAG: u8 = TAG;
165 fn descriptor_length(&self) -> u8 {
166 (FIXED_LEN + self.id_selector.len()) as u8
167 }
168}
169
170impl<'a> crate::traits::DescriptorDef<'a> for TimeSliceFecIdentifierDescriptor<'a> {
171 const TAG: u8 = TAG;
172 const NAME: &'static str = "TIME_SLICE_FEC_IDENTIFIER";
173}
174
175#[cfg(test)]
176mod tests {
177 use super::*;
178
179 #[test]
180 fn parse_no_id_selector() {
181 let b0 = 0x80 | (1 << 5) | 0x18 | 0x03;
184 let bytes = [TAG, 3, b0, 0x2A, (5 << 4) | 0x0A];
185 let d = TimeSliceFecIdentifierDescriptor::parse(&bytes).unwrap();
186 assert!(d.time_slicing);
187 assert_eq!(d.mpe_fec, 1);
188 assert_eq!(d.frame_size, 3);
189 assert_eq!(d.max_burst_duration, 0x2A);
190 assert_eq!(d.max_average_rate, 5);
191 assert_eq!(d.time_slice_fec_id, 0xA);
192 assert!(d.id_selector.is_empty());
193 }
194
195 #[test]
196 fn parse_with_id_selector() {
197 let bytes = [TAG, 5, 0x00, 0x00, 0x00, 0xAA, 0xBB];
198 let d = TimeSliceFecIdentifierDescriptor::parse(&bytes).unwrap();
199 assert!(!d.time_slicing);
200 assert_eq!(d.id_selector, &[0xAA, 0xBB]);
201 }
202
203 #[test]
204 fn parse_rejects_wrong_tag() {
205 assert!(matches!(
206 TimeSliceFecIdentifierDescriptor::parse(&[0x78, 3, 0, 0, 0]).unwrap_err(),
207 Error::InvalidDescriptor { tag: 0x78, .. }
208 ));
209 }
210
211 #[test]
212 fn parse_rejects_body_too_short() {
213 let bytes = [TAG, 2, 0, 0];
214 assert!(matches!(
215 TimeSliceFecIdentifierDescriptor::parse(&bytes).unwrap_err(),
216 Error::InvalidDescriptor { .. }
217 ));
218 }
219
220 #[test]
221 fn parse_rejects_length_overrunning_buffer() {
222 let bytes = [TAG, 5, 0, 0, 0];
223 assert!(matches!(
224 TimeSliceFecIdentifierDescriptor::parse(&bytes).unwrap_err(),
225 Error::BufferTooShort { .. }
226 ));
227 }
228
229 #[test]
230 fn serialize_round_trip() {
231 let d = TimeSliceFecIdentifierDescriptor {
232 time_slicing: true,
233 mpe_fec: 1,
234 frame_size: 2,
235 max_burst_duration: 0x10,
236 max_average_rate: 6,
237 time_slice_fec_id: 0,
238 id_selector: &[0x01, 0x02, 0x03],
239 };
240 let mut buf = vec![0u8; d.serialized_len()];
241 d.serialize_into(&mut buf).unwrap();
242 assert_eq!(TimeSliceFecIdentifierDescriptor::parse(&buf).unwrap(), d);
243 }
244
245 #[test]
246 fn serialize_rejects_frame_size_over_range() {
247 let d = TimeSliceFecIdentifierDescriptor {
248 time_slicing: false,
249 mpe_fec: 0,
250 frame_size: 0x08,
251 max_burst_duration: 0,
252 max_average_rate: 0,
253 time_slice_fec_id: 0,
254 id_selector: &[],
255 };
256 let mut buf = vec![0u8; d.serialized_len()];
257 assert!(matches!(
258 d.serialize_into(&mut buf).unwrap_err(),
259 Error::InvalidDescriptor { .. }
260 ));
261 }
262
263 #[cfg(feature = "serde")]
264 #[test]
265 fn serde_serializes_to_stable_json() {
266 let d = TimeSliceFecIdentifierDescriptor {
269 time_slicing: true,
270 mpe_fec: 1,
271 frame_size: 3,
272 max_burst_duration: 0x44,
273 max_average_rate: 7,
274 time_slice_fec_id: 0xF,
275 id_selector: &[0xDE, 0xAD],
276 };
277 let j = serde_json::to_string(&d).unwrap();
278 let _v: serde_json::Value = serde_json::from_str(&j).unwrap();
281 assert!(j.contains("time_slice_fec_id"));
282 }
283}