1use crate::error::{Error, Result};
13use crate::traits::Table;
14use dvb_common::{Parse, Serialize};
15
16pub const TABLE_ID: u8 = 0x71;
18pub const PID: u16 = 0x0013;
20
21const HEADER_LEN: usize = 3;
22const ENTRY_LEN: usize = 9;
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31#[cfg_attr(feature = "serde", derive(serde::Serialize))]
32pub struct RstEntry {
33 pub transport_stream_id: u16,
35 pub original_network_id: u16,
37 pub service_id: u16,
39 pub event_id: u16,
41 pub running_status: u8,
43}
44
45#[derive(Debug, Clone, PartialEq, Eq)]
47#[cfg_attr(feature = "serde", derive(serde::Serialize))]
48pub struct Rst {
49 pub entries: Vec<RstEntry>,
51}
52
53impl<'a> Parse<'a> for Rst {
54 type Error = crate::error::Error;
55
56 fn parse(bytes: &'a [u8]) -> Result<Self> {
57 if bytes.len() < HEADER_LEN {
58 return Err(Error::BufferTooShort {
59 need: HEADER_LEN,
60 have: bytes.len(),
61 what: "Rst",
62 });
63 }
64 if bytes[0] != TABLE_ID {
65 return Err(Error::UnexpectedTableId {
66 table_id: bytes[0],
67 what: "Rst",
68 expected: &[TABLE_ID],
69 });
70 }
71 let section_length = ((bytes[1] & 0x0F) as usize) << 8 | bytes[2] as usize;
72 let total = HEADER_LEN + section_length;
73 if bytes.len() < total {
74 return Err(Error::SectionLengthOverflow {
75 declared: section_length,
76 available: bytes.len() - HEADER_LEN,
77 });
78 }
79 if section_length % ENTRY_LEN != 0 {
80 return Err(Error::SectionLengthOverflow {
81 declared: section_length,
82 available: (section_length / ENTRY_LEN) * ENTRY_LEN,
83 });
84 }
85 let mut entries = Vec::with_capacity(section_length / ENTRY_LEN);
86 let mut off = HEADER_LEN;
87 while off + ENTRY_LEN <= total {
88 entries.push(RstEntry {
89 transport_stream_id: u16::from_be_bytes([bytes[off], bytes[off + 1]]),
90 original_network_id: u16::from_be_bytes([bytes[off + 2], bytes[off + 3]]),
91 service_id: u16::from_be_bytes([bytes[off + 4], bytes[off + 5]]),
92 event_id: u16::from_be_bytes([bytes[off + 6], bytes[off + 7]]),
93 running_status: bytes[off + 8] & 0x07,
94 });
95 off += ENTRY_LEN;
96 }
97 Ok(Rst { entries })
98 }
99}
100
101impl Serialize for Rst {
102 type Error = crate::error::Error;
103
104 fn serialized_len(&self) -> usize {
105 HEADER_LEN + self.entries.len() * ENTRY_LEN
106 }
107
108 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
109 let len = self.serialized_len();
110 if buf.len() < len {
111 return Err(Error::OutputBufferTooSmall {
112 need: len,
113 have: buf.len(),
114 });
115 }
116 let section_length = (len - HEADER_LEN) as u16;
117 buf[0] = TABLE_ID;
118 buf[1] = 0x70 | ((section_length >> 8) as u8 & 0x0F);
121 buf[2] = (section_length & 0xFF) as u8;
122 let mut off = HEADER_LEN;
123 for e in &self.entries {
124 buf[off..off + 2].copy_from_slice(&e.transport_stream_id.to_be_bytes());
125 buf[off + 2..off + 4].copy_from_slice(&e.original_network_id.to_be_bytes());
126 buf[off + 4..off + 6].copy_from_slice(&e.service_id.to_be_bytes());
127 buf[off + 6..off + 8].copy_from_slice(&e.event_id.to_be_bytes());
128 buf[off + 8] = 0xF8 | (e.running_status & 0x07);
130 off += ENTRY_LEN;
131 }
132 Ok(len)
133 }
134}
135
136impl<'a> Table<'a> for Rst {
137 const TABLE_ID: u8 = TABLE_ID;
138 const PID: u16 = PID;
139}
140
141impl<'a> crate::traits::TableDef<'a> for Rst {
142 const TABLE_ID_RANGES: &'static [(u8, u8)] = &[(TABLE_ID, TABLE_ID)];
143 const NAME: &'static str = "RUNNING_STATUS";
144}
145
146#[cfg(test)]
147mod tests {
148 use super::*;
149
150 fn build_rst(entries: &[RstEntry]) -> Vec<u8> {
151 let section_length = (entries.len() * ENTRY_LEN) as u16;
152 let mut v = vec![
153 TABLE_ID,
154 0x70 | ((section_length >> 8) as u8 & 0x0F),
155 (section_length & 0xFF) as u8,
156 ];
157 for e in entries {
158 v.extend_from_slice(&e.transport_stream_id.to_be_bytes());
159 v.extend_from_slice(&e.original_network_id.to_be_bytes());
160 v.extend_from_slice(&e.service_id.to_be_bytes());
161 v.extend_from_slice(&e.event_id.to_be_bytes());
162 v.push(0xF8 | (e.running_status & 0x07));
163 }
164 v
165 }
166
167 fn entry(tsid: u16, onid: u16, sid: u16, evid: u16, rs: u8) -> RstEntry {
168 RstEntry {
169 transport_stream_id: tsid,
170 original_network_id: onid,
171 service_id: sid,
172 event_id: evid,
173 running_status: rs,
174 }
175 }
176
177 #[test]
178 fn parse_empty() {
179 let rst = Rst::parse(&build_rst(&[])).unwrap();
180 assert!(rst.entries.is_empty());
181 }
182
183 #[test]
184 fn parse_single_entry() {
185 let e = entry(0x1234, 0x0001, 0xABCD, 0x4000, 4);
186 let rst = Rst::parse(&build_rst(&[e])).unwrap();
187 assert_eq!(rst.entries.len(), 1);
188 assert_eq!(rst.entries[0], e);
189 assert_eq!(rst.entries[0].running_status, 4); }
191
192 #[test]
193 fn parse_multiple_entries() {
194 let es = [
195 entry(0x0001, 0x1000, 0x0010, 0x0100, 1),
196 entry(0x0002, 0x2000, 0x0020, 0x0200, 4),
197 entry(0x0003, 0x3000, 0x0030, 0x0300, 5),
198 ];
199 let rst = Rst::parse(&build_rst(&es)).unwrap();
200 assert_eq!(rst.entries, es);
201 }
202
203 #[test]
204 fn parse_rejects_wrong_tag() {
205 let mut bytes = build_rst(&[]);
206 bytes[0] = 0x72;
207 assert!(matches!(
208 Rst::parse(&bytes).unwrap_err(),
209 Error::UnexpectedTableId { table_id: 0x72, .. }
210 ));
211 }
212
213 #[test]
214 fn parse_rejects_short_buffer() {
215 assert!(matches!(
216 Rst::parse(&[0x71, 0x70]).unwrap_err(),
217 Error::BufferTooShort { .. }
218 ));
219 }
220
221 #[test]
222 fn parse_rejects_non_multiple_loop() {
223 let bytes = [TABLE_ID, 0x70, 0x04, 0x00, 0x00, 0x00, 0x00];
225 assert!(matches!(
226 Rst::parse(&bytes).unwrap_err(),
227 Error::SectionLengthOverflow { .. }
228 ));
229 }
230
231 #[test]
232 fn serialize_round_trip() {
233 let es = [
234 entry(0xCAFE, 0xBEEF, 0x1234, 0x5678, 4),
235 entry(0x0001, 0x0002, 0x0003, 0x0004, 5),
236 ];
237 let rst = Rst::parse(&build_rst(&es)).unwrap();
238 let mut buf = vec![0u8; rst.serialized_len()];
239 rst.serialize_into(&mut buf).unwrap();
240 assert_eq!(buf, build_rst(&es));
241 assert_eq!(Rst::parse(&buf).unwrap(), rst);
242 }
243
244 #[test]
245 fn serialize_empty_round_trip() {
246 let rst = Rst { entries: vec![] };
247 let mut buf = vec![0u8; rst.serialized_len()];
248 rst.serialize_into(&mut buf).unwrap();
249 assert_eq!(Rst::parse(&buf).unwrap(), rst);
250 }
251
252 #[test]
253 fn table_trait_constants() {
254 assert_eq!(<Rst as Table>::TABLE_ID, 0x71);
255 assert_eq!(<Rst as Table>::PID, 0x0013);
256 }
257
258 #[test]
259 fn serde_json_serializes_fields() {
260 let rst = Rst::parse(&build_rst(&[entry(1, 2, 3, 4, 4)])).unwrap();
262 let j = serde_json::to_string(&rst).unwrap();
263 let v: serde_json::Value = serde_json::from_str(&j).unwrap();
264 assert_eq!(v["entries"][0]["service_id"], 3);
265 }
266}