dvb_si/descriptors/
tva_id.rs1use crate::error::{Error, Result};
11use crate::traits::Descriptor;
12use dvb_common::{Parse, Serialize};
13
14pub const TAG: u8 = 0x75;
16const HEADER_LEN: usize = 2;
17const ENTRY_LEN: usize = 3;
18
19const RUNNING_STATUS_MAX: u8 = 0x07;
21
22#[derive(Debug, Clone, PartialEq, Eq)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25pub struct TvaIdEntry {
26 pub tva_id: u16,
28 pub running_status: u8,
30}
31
32#[derive(Debug, Clone, PartialEq, Eq)]
34#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
35pub struct TvaIdDescriptor {
36 pub entries: Vec<TvaIdEntry>,
38}
39
40impl<'a> Parse<'a> for TvaIdDescriptor {
41 type Error = crate::error::Error;
42 fn parse(bytes: &'a [u8]) -> Result<Self> {
43 if bytes.len() < HEADER_LEN {
44 return Err(Error::BufferTooShort {
45 need: HEADER_LEN,
46 have: bytes.len(),
47 what: "TvaIdDescriptor header",
48 });
49 }
50 if bytes[0] != TAG {
51 return Err(Error::InvalidDescriptor {
52 tag: bytes[0],
53 reason: "unexpected tag for TVA_id_descriptor",
54 });
55 }
56 let length = bytes[1] as usize;
57 let end = HEADER_LEN + length;
58 if bytes.len() < end {
59 return Err(Error::BufferTooShort {
60 need: end,
61 have: bytes.len(),
62 what: "TvaIdDescriptor body",
63 });
64 }
65 if length % ENTRY_LEN != 0 {
66 return Err(Error::InvalidDescriptor {
67 tag: TAG,
68 reason: "TVA_id_descriptor length must be a multiple of 3",
69 });
70 }
71 let body = &bytes[HEADER_LEN..end];
72 let mut entries = Vec::with_capacity(length / ENTRY_LEN);
73 for chunk in body.chunks_exact(ENTRY_LEN) {
74 let tva_id = u16::from_be_bytes([chunk[0], chunk[1]]);
75 let running_status = chunk[2] & RUNNING_STATUS_MAX;
77 entries.push(TvaIdEntry {
78 tva_id,
79 running_status,
80 });
81 }
82 Ok(Self { entries })
83 }
84}
85
86impl Serialize for TvaIdDescriptor {
87 type Error = crate::error::Error;
88 fn serialized_len(&self) -> usize {
89 HEADER_LEN + self.entries.len() * ENTRY_LEN
90 }
91
92 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
93 for e in &self.entries {
94 if e.running_status > RUNNING_STATUS_MAX {
95 return Err(Error::InvalidDescriptor {
96 tag: TAG,
97 reason: "running_status exceeds 3 bits",
98 });
99 }
100 }
101 if self.entries.len() * ENTRY_LEN > u8::MAX as usize {
102 return Err(Error::InvalidDescriptor {
103 tag: TAG,
104 reason: "TVA_id_descriptor body exceeds 255 bytes",
105 });
106 }
107 let len = self.serialized_len();
108 if buf.len() < len {
109 return Err(Error::OutputBufferTooSmall {
110 need: len,
111 have: buf.len(),
112 });
113 }
114 buf[0] = TAG;
115 buf[1] = (self.entries.len() * ENTRY_LEN) as u8;
116 let mut pos = HEADER_LEN;
117 for e in &self.entries {
118 buf[pos..pos + 2].copy_from_slice(&e.tva_id.to_be_bytes());
119 buf[pos + 2] = 0xF8 | (e.running_status & RUNNING_STATUS_MAX);
121 pos += ENTRY_LEN;
122 }
123 Ok(len)
124 }
125}
126
127impl<'a> Descriptor<'a> for TvaIdDescriptor {
128 const TAG: u8 = TAG;
129 fn descriptor_length(&self) -> u8 {
130 (self.entries.len() * ENTRY_LEN) as u8
131 }
132}
133
134impl<'a> crate::traits::DescriptorDef<'a> for TvaIdDescriptor {
135 const TAG: u8 = TAG;
136 const NAME: &'static str = "TVA_ID";
137}
138
139#[cfg(test)]
140mod tests {
141 use super::*;
142
143 #[test]
144 fn parse_single_entry() {
145 let bytes = [TAG, 3, 0x12, 0x34, 0xFC];
147 let d = TvaIdDescriptor::parse(&bytes).unwrap();
148 assert_eq!(d.entries.len(), 1);
149 assert_eq!(d.entries[0].tva_id, 0x1234);
150 assert_eq!(d.entries[0].running_status, 4);
151 }
152
153 #[test]
154 fn parse_multiple_entries() {
155 let bytes = [TAG, 6, 0x00, 0x01, 0x01, 0xAB, 0xCD, 0x06];
156 let d = TvaIdDescriptor::parse(&bytes).unwrap();
157 assert_eq!(d.entries.len(), 2);
158 assert_eq!(d.entries[0].tva_id, 0x0001);
159 assert_eq!(d.entries[0].running_status, 1);
160 assert_eq!(d.entries[1].tva_id, 0xABCD);
161 assert_eq!(d.entries[1].running_status, 6);
162 }
163
164 #[test]
165 fn parse_ignores_reserved_bits() {
166 let bytes = [TAG, 3, 0x00, 0x00, 0xFF];
167 let d = TvaIdDescriptor::parse(&bytes).unwrap();
168 assert_eq!(d.entries[0].running_status, 0x07);
169 }
170
171 #[test]
172 fn parse_rejects_wrong_tag() {
173 assert!(matches!(
174 TvaIdDescriptor::parse(&[0x74, 0]).unwrap_err(),
175 Error::InvalidDescriptor { tag: 0x74, .. }
176 ));
177 }
178
179 #[test]
180 fn parse_rejects_length_not_multiple_of_3() {
181 let bytes = [TAG, 2, 0, 0];
182 assert!(matches!(
183 TvaIdDescriptor::parse(&bytes).unwrap_err(),
184 Error::InvalidDescriptor { .. }
185 ));
186 }
187
188 #[test]
189 fn empty_descriptor_valid() {
190 let bytes = [TAG, 0];
191 let d = TvaIdDescriptor::parse(&bytes).unwrap();
192 assert!(d.entries.is_empty());
193 }
194
195 #[test]
196 fn serialize_round_trip() {
197 let d = TvaIdDescriptor {
198 entries: vec![
199 TvaIdEntry {
200 tva_id: 0x1000,
201 running_status: 2,
202 },
203 TvaIdEntry {
204 tva_id: 0xFFFF,
205 running_status: 0,
206 },
207 ],
208 };
209 let mut buf = vec![0u8; d.serialized_len()];
210 d.serialize_into(&mut buf).unwrap();
211 assert_eq!(TvaIdDescriptor::parse(&buf).unwrap(), d);
212 }
213
214 #[test]
215 fn serialize_rejects_running_status_over_range() {
216 let d = TvaIdDescriptor {
217 entries: vec![TvaIdEntry {
218 tva_id: 0,
219 running_status: 0x08,
220 }],
221 };
222 let mut buf = vec![0u8; d.serialized_len()];
223 assert!(matches!(
224 d.serialize_into(&mut buf).unwrap_err(),
225 Error::InvalidDescriptor { .. }
226 ));
227 }
228
229 #[cfg(feature = "serde")]
230 #[test]
231 fn serde_round_trip() {
232 let d = TvaIdDescriptor {
233 entries: vec![TvaIdEntry {
234 tva_id: 0x4242,
235 running_status: 4,
236 }],
237 };
238 let j = serde_json::to_string(&d).unwrap();
239 let back: TvaIdDescriptor = serde_json::from_str(&j).unwrap();
240 assert_eq!(back, d);
241 }
242}