1use crate::error::{Error, Result};
9use alloc::vec::Vec;
10use dvb_common::{Parse, Serialize};
11
12pub const TABLE_ID: u8 = 0x72;
14pub const PID: u16 = 0x0014;
16
17const HEADER_LEN: usize = 3;
18
19#[derive(Debug, Clone, PartialEq, Eq)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize))]
22pub struct StSection {
23 pub payload: Vec<u8>,
25}
26
27impl StSection {
28 #[inline]
30 #[must_use]
31 pub fn new(payload: Vec<u8>) -> Self {
32 Self { payload }
33 }
34
35 #[inline]
37 #[must_use]
38 pub fn len(&self) -> usize {
39 self.payload.len()
40 }
41
42 #[inline]
44 #[must_use]
45 pub fn is_empty(&self) -> bool {
46 self.payload.is_empty()
47 }
48}
49
50impl<'a> Parse<'a> for StSection {
51 type Error = crate::error::Error;
52
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: "StSection",
59 });
60 }
61
62 if bytes[0] != TABLE_ID {
63 return Err(Error::UnexpectedTableId {
64 table_id: bytes[0],
65 what: "StSection",
66 expected: &[TABLE_ID],
67 });
68 }
69
70 let section_length = ((bytes[1] & 0x0F) as u16) << 8 | bytes[2] as u16;
71 let payload_len = section_length as usize;
72
73 if bytes.len() < HEADER_LEN + payload_len {
74 return Err(Error::SectionLengthOverflow {
75 declared: payload_len,
76 available: bytes.len().saturating_sub(HEADER_LEN),
77 });
78 }
79
80 let payload = &bytes[HEADER_LEN..HEADER_LEN + payload_len];
83 Ok(Self {
84 payload: payload.to_vec(),
85 })
86 }
87}
88
89impl Serialize for StSection {
90 type Error = crate::error::Error;
91
92 fn serialized_len(&self) -> usize {
93 HEADER_LEN + self.payload.len()
94 }
95
96 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
97 let len = self.serialized_len();
98 if buf.len() < len {
99 return Err(Error::OutputBufferTooSmall {
100 need: len,
101 have: buf.len(),
102 });
103 }
104
105 buf[0] = TABLE_ID;
107
108 buf[1] = super::SECTION_B1_FLAGS_SHORT | ((self.payload.len() >> 8) as u8 & 0x0F);
111
112 buf[2] = (self.payload.len() & 0xFF) as u8;
114
115 buf[HEADER_LEN..len].copy_from_slice(&self.payload);
117
118 Ok(len)
119 }
120}
121impl<'a> crate::traits::TableDef<'a> for StSection {
122 const TABLE_ID_RANGES: &'static [(u8, u8)] = &[(TABLE_ID, TABLE_ID)];
123 const NAME: &'static str = "STUFFING";
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129
130 fn make_st_section(payload: &[u8]) -> Vec<u8> {
132 let mut buf = vec![TABLE_ID, 0x70, payload.len() as u8];
133 buf.extend_from_slice(payload);
134 buf
135 }
136
137 #[test]
138 fn parse_rejects_wrong_tag() {
139 let bytes = [0x71, 0x70, 0x02, 0x00, 0x00];
140 assert!(matches!(
141 StSection::parse(&bytes).unwrap_err(),
142 Error::UnexpectedTableId { table_id: 0x71, .. }
143 ));
144 }
145
146 #[test]
147 fn parse_empty_payload() {
148 let bytes = make_st_section(&[]);
149 let st = StSection::parse(&bytes).unwrap();
150 assert!(st.is_empty());
151 }
152
153 #[test]
156 fn parse_accepts_any_data_byte_value() {
157 let bytes = make_st_section(&[0x00, 0xFF, 0xAA]);
158 let st = StSection::parse(&bytes).unwrap();
159 assert_eq!(st.payload, vec![0x00, 0xFF, 0xAA]);
160 let mut buf = vec![0u8; st.serialized_len()];
161 st.serialize_into(&mut buf).unwrap();
162 assert_eq!(buf, bytes);
163 }
164
165 #[test]
166 fn serialize_writes_correct_header() {
167 let st = StSection::new(vec![0x00, 0x00]);
168 let mut buf = vec![0u8; st.serialized_len()];
169 st.serialize_into(&mut buf).unwrap();
170 assert_eq!(buf[0], TABLE_ID);
171 assert_eq!(buf[1], 0x70 | ((2 >> 8) as u8 & 0x0F));
172 assert_eq!(buf[2], 2);
173 }
174
175 #[test]
176 fn serialize_empty_payload() {
177 let st = StSection::new(vec![]);
178 let mut buf = vec![0u8; st.serialized_len()];
179 st.serialize_into(&mut buf).unwrap();
180 assert_eq!(buf, [TABLE_ID, 0x70, 0x00]);
181 }
182
183 #[test]
184 fn serialize_rejects_too_small_buffer() {
185 let st = StSection::new(vec![0x00]);
186 let mut too_small = vec![0u8; st.serialized_len() - 1];
187 let err = st.serialize_into(&mut too_small).unwrap_err();
188 assert!(matches!(err, Error::OutputBufferTooSmall { .. }));
189 }
190
191 #[test]
192 fn round_trip_preserves_all_fields() {
193 let st = StSection::new(vec![0x00, 0x00, 0x00]);
194 let mut buf = vec![0u8; st.serialized_len()];
195 st.serialize_into(&mut buf).unwrap();
196 let re = StSection::parse(&buf).unwrap();
197 assert_eq!(st, re);
198 }
199
200 #[test]
201 fn round_trip_empty() {
202 let st = StSection::new(vec![]);
203 let mut buf = vec![0u8; st.serialized_len()];
204 st.serialize_into(&mut buf).unwrap();
205 let re = StSection::parse(&buf).unwrap();
206 assert_eq!(st, re);
207 }
208
209 #[test]
210 fn round_trip_many_stuffs() {
211 let st = StSection::new(vec![0x00; 185]);
212 let mut buf = vec![0u8; st.serialized_len()];
213 st.serialize_into(&mut buf).unwrap();
214 let re = StSection::parse(&buf).unwrap();
215 assert_eq!(st, re);
216 }
217
218 #[test]
219 fn parse_rejects_buffer_too_short() {
220 let bytes = [0x72, 0x70]; assert!(matches!(
222 StSection::parse(&bytes).unwrap_err(),
223 Error::BufferTooShort { need: 3, .. }
224 ));
225 }
226
227 #[test]
228 fn parse_rejects_section_length_exceeds_buffer() {
229 let bytes = [0x72, 0x70, 10, 0x00, 0x00];
231 assert!(matches!(
232 StSection::parse(&bytes).unwrap_err(),
233 Error::SectionLengthOverflow { .. }
234 ));
235 }
236
237 #[test]
238 fn table_trait_constants() {
239 assert_eq!(TABLE_ID, 0x72);
240 assert_eq!(PID, 0x0014);
241 }
242
243 #[test]
244 fn serialized_len_matches_wire_size() {
245 let st = StSection::new(vec![0x00; 50]);
246 assert_eq!(st.serialized_len(), HEADER_LEN + 50);
247 }
248
249 #[test]
250 fn to_bytes_produces_valid_section() {
251 let st = StSection::new(vec![0x00, 0x00]);
252 let bytes = st.to_bytes();
253 assert_eq!(bytes[0], TABLE_ID);
254 assert_eq!(bytes.len(), st.serialized_len());
255 }
256
257 #[test]
258 fn len_and_is_empty() {
259 let empty = StSection::new(vec![]);
260 assert!(empty.is_empty());
261 assert_eq!(empty.len(), 0);
262
263 let filled = StSection::new(vec![0x00; 10]);
264 assert!(!filled.is_empty());
265 assert_eq!(filled.len(), 10);
266 }
267
268 #[test]
269 fn new_constructor() {
270 let st = StSection::new(vec![0x00]);
271 assert_eq!(st.len(), 1);
272 }
273}