1use super::descriptor_body;
8use crate::error::{Error, Result};
9use alloc::vec::Vec;
10use dvb_common::{Parse, Serialize};
11
12pub const TAG: u8 = 0x4B;
14const HEADER_LEN: usize = 2;
15const ENTRY_LEN: usize = 6;
16const MAX_BODY_LEN: usize = u8::MAX as usize;
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize))]
22pub struct NvodReferenceEntry {
23 pub transport_stream_id: u16,
25 pub original_network_id: u16,
27 pub service_id: u16,
29}
30
31#[derive(Debug, Clone, PartialEq, Eq)]
33#[cfg_attr(feature = "serde", derive(serde::Serialize))]
34pub struct NvodReferenceDescriptor {
35 pub entries: Vec<NvodReferenceEntry>,
37}
38
39impl<'a> Parse<'a> for NvodReferenceDescriptor {
40 type Error = crate::error::Error;
41 fn parse(bytes: &'a [u8]) -> Result<Self> {
42 let body = descriptor_body(
43 bytes,
44 TAG,
45 "NvodReferenceDescriptor",
46 "unexpected tag for NVOD_reference_descriptor",
47 )?;
48 if body.len() % ENTRY_LEN != 0 {
49 return Err(Error::InvalidDescriptor {
50 tag: TAG,
51 reason: "descriptor_length must be a multiple of 6",
52 });
53 }
54 let mut entries = Vec::with_capacity(body.len() / ENTRY_LEN);
55 for chunk in body.chunks_exact(ENTRY_LEN) {
56 let (tsid, rest) = chunk.split_first_chunk::<2>().unwrap();
58 let (onid, sid_bytes) = rest.split_first_chunk::<2>().unwrap();
59 let sid = sid_bytes.first_chunk::<2>().unwrap();
60 entries.push(NvodReferenceEntry {
61 transport_stream_id: u16::from_be_bytes(*tsid),
62 original_network_id: u16::from_be_bytes(*onid),
63 service_id: u16::from_be_bytes(*sid),
64 });
65 }
66 Ok(Self { entries })
67 }
68}
69
70impl Serialize for NvodReferenceDescriptor {
71 type Error = crate::error::Error;
72 fn serialized_len(&self) -> usize {
73 HEADER_LEN + ENTRY_LEN * self.entries.len()
74 }
75
76 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
77 let len = self.serialized_len();
78 if buf.len() < len {
79 return Err(Error::OutputBufferTooSmall {
80 need: len,
81 have: buf.len(),
82 });
83 }
84 let body_len = ENTRY_LEN * self.entries.len();
85 if body_len > MAX_BODY_LEN {
87 return Err(Error::InvalidDescriptor {
88 tag: TAG,
89 reason: "NVOD_reference_descriptor body exceeds 255 bytes",
90 });
91 }
92 buf[0] = TAG;
93 buf[1] = body_len as u8;
94 let mut pos = HEADER_LEN;
95 for e in &self.entries {
96 buf[pos..pos + 2].copy_from_slice(&e.transport_stream_id.to_be_bytes());
97 buf[pos + 2..pos + 4].copy_from_slice(&e.original_network_id.to_be_bytes());
98 buf[pos + 4..pos + 6].copy_from_slice(&e.service_id.to_be_bytes());
99 pos += ENTRY_LEN;
100 }
101 Ok(len)
102 }
103}
104impl<'a> crate::traits::DescriptorDef<'a> for NvodReferenceDescriptor {
105 const TAG: u8 = TAG;
106 const NAME: &'static str = "NVOD_REFERENCE";
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 #[test]
114 fn parse_single_triple() {
115 let bytes = [TAG, 6, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03];
116 let d = NvodReferenceDescriptor::parse(&bytes).unwrap();
117 assert_eq!(d.entries.len(), 1);
118 assert_eq!(d.entries[0].transport_stream_id, 1);
119 assert_eq!(d.entries[0].original_network_id, 2);
120 assert_eq!(d.entries[0].service_id, 3);
121 }
122
123 #[test]
124 fn parse_multiple_triples_preserves_order() {
125 let bytes = [
126 TAG, 12, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06,
127 ];
128 let d = NvodReferenceDescriptor::parse(&bytes).unwrap();
129 assert_eq!(d.entries.len(), 2);
130 assert_eq!(d.entries[1].transport_stream_id, 4);
131 assert_eq!(d.entries[1].original_network_id, 5);
132 assert_eq!(d.entries[1].service_id, 6);
133 }
134
135 #[test]
136 fn parse_rejects_wrong_tag() {
137 assert!(matches!(
138 NvodReferenceDescriptor::parse(&[0x4C, 6, 0, 0, 0, 0, 0, 0]).unwrap_err(),
139 Error::InvalidDescriptor { tag: 0x4C, .. }
140 ));
141 }
142
143 #[test]
144 fn parse_rejects_short_buffer() {
145 let bytes = [TAG, 12, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03];
146 assert!(matches!(
147 NvodReferenceDescriptor::parse(&bytes).unwrap_err(),
148 Error::BufferTooShort { .. }
149 ));
150 }
151
152 #[test]
153 fn parse_rejects_length_not_multiple_of_6() {
154 let bytes = [TAG, 5, 0x00, 0x01, 0x00, 0x02, 0x00];
155 assert!(matches!(
156 NvodReferenceDescriptor::parse(&bytes).unwrap_err(),
157 Error::InvalidDescriptor { tag: TAG, .. }
158 ));
159 }
160
161 #[test]
162 fn empty_descriptor_valid() {
163 let d = NvodReferenceDescriptor::parse(&[TAG, 0]).unwrap();
164 assert!(d.entries.is_empty());
165 }
166
167 #[test]
168 fn serialize_round_trip() {
169 let d = NvodReferenceDescriptor {
170 entries: vec![
171 NvodReferenceEntry {
172 transport_stream_id: 0x1234,
173 original_network_id: 0x5678,
174 service_id: 0x9ABC,
175 },
176 NvodReferenceEntry {
177 transport_stream_id: 0x0001,
178 original_network_id: 0x0002,
179 service_id: 0x0003,
180 },
181 ],
182 };
183 let mut buf = vec![0u8; d.serialized_len()];
184 d.serialize_into(&mut buf).unwrap();
185 assert_eq!(NvodReferenceDescriptor::parse(&buf).unwrap(), d);
186 }
187
188 #[test]
189 fn serialize_rejects_over_range_body() {
190 let d = NvodReferenceDescriptor {
192 entries: vec![
193 NvodReferenceEntry {
194 transport_stream_id: 1,
195 original_network_id: 2,
196 service_id: 3,
197 };
198 43
199 ],
200 };
201 let mut buf = vec![0u8; d.serialized_len()];
202 assert!(matches!(
203 d.serialize_into(&mut buf).unwrap_err(),
204 Error::InvalidDescriptor { tag: TAG, .. }
205 ));
206 }
207
208 #[cfg(feature = "serde")]
209 #[test]
210 fn serde_round_trip() {
211 let d = NvodReferenceDescriptor {
212 entries: vec![NvodReferenceEntry {
213 transport_stream_id: 1,
214 original_network_id: 2,
215 service_id: 3,
216 }],
217 };
218 let json = serde_json::to_string(&d).unwrap();
219 let _v: serde_json::Value = serde_json::from_str(&json).unwrap();
221 }
222}