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