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