1use crate::error::{Error, Result};
18use crate::traits::Descriptor;
19use dvb_common::{Parse, Serialize};
20
21pub const TAG: u8 = 0x57;
23const HEADER_LEN: usize = 2;
24const FIXED_LEN: usize = 3;
26
27const FOREIGN_AVAIL_MASK: u8 = 0x20; const CONNECTION_TYPE_MASK: u8 = 0x1F; const BYTE0_RESERVED: u8 = 0xC0; const BYTE1_RESERVED: u8 = 0x80; const BYTE2_RESERVED: u8 = 0x80; const MAX_COUNTRY_PREFIX: usize = 0x03; const MAX_INTL_AREA: usize = 0x07; const MAX_OPERATOR: usize = 0x03; const MAX_NATIONAL_AREA: usize = 0x07; const MAX_CORE_NUMBER: usize = 0x0F; #[derive(Debug, Clone, PartialEq, Eq)]
42#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
43#[cfg_attr(feature = "serde", serde(bound(deserialize = "'de: 'a")))]
44pub struct TelephoneDescriptor<'a> {
45 pub foreign_availability: bool,
47 pub connection_type: u8,
49 #[cfg_attr(feature = "serde", serde(borrow))]
51 pub country_prefix: &'a [u8],
52 #[cfg_attr(feature = "serde", serde(borrow))]
54 pub international_area_code: &'a [u8],
55 #[cfg_attr(feature = "serde", serde(borrow))]
57 pub operator_code: &'a [u8],
58 #[cfg_attr(feature = "serde", serde(borrow))]
60 pub national_area_code: &'a [u8],
61 #[cfg_attr(feature = "serde", serde(borrow))]
63 pub core_number: &'a [u8],
64}
65
66impl<'a> Parse<'a> for TelephoneDescriptor<'a> {
67 type Error = crate::error::Error;
68 fn parse(bytes: &'a [u8]) -> Result<Self> {
69 if bytes.len() < HEADER_LEN {
70 return Err(Error::BufferTooShort {
71 need: HEADER_LEN,
72 have: bytes.len(),
73 what: "TelephoneDescriptor header",
74 });
75 }
76 if bytes[0] != TAG {
77 return Err(Error::InvalidDescriptor {
78 tag: bytes[0],
79 reason: "unexpected tag for telephone_descriptor",
80 });
81 }
82 let length = bytes[1] as usize;
83 if length < FIXED_LEN {
84 return Err(Error::InvalidDescriptor {
85 tag: TAG,
86 reason: "telephone_descriptor length too short for fixed fields",
87 });
88 }
89 let end = HEADER_LEN + length;
90 if bytes.len() < end {
91 return Err(Error::BufferTooShort {
92 need: end,
93 have: bytes.len(),
94 what: "TelephoneDescriptor body",
95 });
96 }
97 let body = &bytes[HEADER_LEN..end];
98 let foreign_availability = body[0] & FOREIGN_AVAIL_MASK != 0;
100 let connection_type = body[0] & CONNECTION_TYPE_MASK;
101 let country_prefix_length = ((body[1] >> 5) & 0x03) as usize;
102 let international_area_code_length = ((body[1] >> 2) & 0x07) as usize;
103 let operator_code_length = (body[1] & 0x03) as usize;
104 let national_area_code_length = ((body[2] >> 4) & 0x07) as usize;
105 let core_number_length = (body[2] & 0x0F) as usize;
106 let total_chars = country_prefix_length
107 + international_area_code_length
108 + operator_code_length
109 + national_area_code_length
110 + core_number_length;
111 if FIXED_LEN + total_chars > body.len() {
112 return Err(Error::InvalidDescriptor {
113 tag: TAG,
114 reason: "sum of telephone char-field lengths exceeds descriptor body",
115 });
116 }
117 let mut pos = FIXED_LEN;
118 let mut take = |n: usize| {
119 let s = &body[pos..pos + n];
120 pos += n;
121 s
122 };
123 let country_prefix = take(country_prefix_length);
124 let international_area_code = take(international_area_code_length);
125 let operator_code = take(operator_code_length);
126 let national_area_code = take(national_area_code_length);
127 let core_number = take(core_number_length);
128 Ok(Self {
129 foreign_availability,
130 connection_type,
131 country_prefix,
132 international_area_code,
133 operator_code,
134 national_area_code,
135 core_number,
136 })
137 }
138}
139
140impl Serialize for TelephoneDescriptor<'_> {
141 type Error = crate::error::Error;
142 fn serialized_len(&self) -> usize {
143 HEADER_LEN
144 + FIXED_LEN
145 + self.country_prefix.len()
146 + self.international_area_code.len()
147 + self.operator_code.len()
148 + self.national_area_code.len()
149 + self.core_number.len()
150 }
151
152 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
153 let len = self.serialized_len();
154 if buf.len() < len {
155 return Err(Error::OutputBufferTooSmall {
156 need: len,
157 have: buf.len(),
158 });
159 }
160 if self.country_prefix.len() > MAX_COUNTRY_PREFIX
162 || self.international_area_code.len() > MAX_INTL_AREA
163 || self.operator_code.len() > MAX_OPERATOR
164 || self.national_area_code.len() > MAX_NATIONAL_AREA
165 || self.core_number.len() > MAX_CORE_NUMBER
166 {
167 return Err(Error::InvalidDescriptor {
168 tag: TAG,
169 reason: "telephone char-field exceeds its length-field capacity",
170 });
171 }
172 buf[0] = TAG;
173 buf[1] = (len - HEADER_LEN) as u8;
174 buf[2] = BYTE0_RESERVED
176 | if self.foreign_availability {
177 FOREIGN_AVAIL_MASK
178 } else {
179 0
180 }
181 | (self.connection_type & CONNECTION_TYPE_MASK);
182 buf[3] = BYTE1_RESERVED
184 | ((self.country_prefix.len() as u8 & 0x03) << 5)
185 | ((self.international_area_code.len() as u8 & 0x07) << 2)
186 | (self.operator_code.len() as u8 & 0x03);
187 buf[4] = BYTE2_RESERVED
189 | ((self.national_area_code.len() as u8 & 0x07) << 4)
190 | (self.core_number.len() as u8 & 0x0F);
191 let mut pos = HEADER_LEN + FIXED_LEN;
192 for field in [
193 self.country_prefix,
194 self.international_area_code,
195 self.operator_code,
196 self.national_area_code,
197 self.core_number,
198 ] {
199 buf[pos..pos + field.len()].copy_from_slice(field);
200 pos += field.len();
201 }
202 Ok(len)
203 }
204}
205
206impl<'a> Descriptor<'a> for TelephoneDescriptor<'a> {
207 const TAG: u8 = TAG;
208 fn descriptor_length(&self) -> u8 {
209 (self.serialized_len() - HEADER_LEN) as u8
210 }
211}
212
213impl<'a> crate::traits::DescriptorDef<'a> for TelephoneDescriptor<'a> {
214 const TAG: u8 = TAG;
215 const NAME: &'static str = "TELEPHONE";
216}
217
218#[cfg(test)]
219mod tests {
220 use super::*;
221
222 fn sample() -> TelephoneDescriptor<'static> {
223 TelephoneDescriptor {
224 foreign_availability: true,
225 connection_type: 0x05,
226 country_prefix: b"44",
227 international_area_code: b"171",
228 operator_code: b"01",
229 national_area_code: b"207",
230 core_number: b"123456",
231 }
232 }
233
234 #[test]
235 fn parse_extracts_all_fields() {
236 let d = sample();
237 let mut buf = vec![0u8; d.serialized_len()];
238 d.serialize_into(&mut buf).unwrap();
239 let p = TelephoneDescriptor::parse(&buf).unwrap();
240 assert!(p.foreign_availability);
241 assert_eq!(p.connection_type, 0x05);
242 assert_eq!(p.country_prefix, b"44");
243 assert_eq!(p.international_area_code, b"171");
244 assert_eq!(p.operator_code, b"01");
245 assert_eq!(p.national_area_code, b"207");
246 assert_eq!(p.core_number, b"123456");
247 }
248
249 #[test]
250 fn parse_minimal_no_chars() {
251 let bytes = [TAG, 3, 0x20, 0x00, 0x00];
253 let d = TelephoneDescriptor::parse(&bytes).unwrap();
254 assert!(d.foreign_availability);
255 assert!(d.country_prefix.is_empty());
256 assert!(d.core_number.is_empty());
257 }
258
259 #[test]
260 fn parse_rejects_wrong_tag() {
261 assert!(matches!(
262 TelephoneDescriptor::parse(&[0x58, 3, 0, 0, 0]).unwrap_err(),
263 Error::InvalidDescriptor { tag: 0x58, .. }
264 ));
265 }
266
267 #[test]
268 fn parse_rejects_short_buffer() {
269 let bytes = [TAG, 3, 0x20, 0x00];
271 assert!(matches!(
272 TelephoneDescriptor::parse(&bytes).unwrap_err(),
273 Error::BufferTooShort { .. }
274 ));
275 }
276
277 #[test]
278 fn parse_rejects_length_below_fixed() {
279 let bytes = [TAG, 2, 0x20, 0x00];
280 assert!(matches!(
281 TelephoneDescriptor::parse(&bytes).unwrap_err(),
282 Error::InvalidDescriptor { tag: TAG, .. }
283 ));
284 }
285
286 #[test]
287 fn parse_rejects_char_lengths_overrun() {
288 let bytes = [TAG, 3, 0x20, 0x60, 0x00];
291 assert!(matches!(
292 TelephoneDescriptor::parse(&bytes).unwrap_err(),
293 Error::InvalidDescriptor { tag: TAG, .. }
294 ));
295 }
296
297 #[test]
298 fn serialize_round_trip() {
299 let d = sample();
300 let mut buf = vec![0u8; d.serialized_len()];
301 d.serialize_into(&mut buf).unwrap();
302 assert_eq!(TelephoneDescriptor::parse(&buf).unwrap(), d);
303 }
304
305 #[test]
306 fn serialize_emits_reserved_ones() {
307 let d = TelephoneDescriptor {
308 foreign_availability: false,
309 connection_type: 0,
310 country_prefix: b"",
311 international_area_code: b"",
312 operator_code: b"",
313 national_area_code: b"",
314 core_number: b"",
315 };
316 let mut buf = vec![0u8; d.serialized_len()];
317 d.serialize_into(&mut buf).unwrap();
318 assert_eq!(buf[2] & BYTE0_RESERVED, BYTE0_RESERVED);
320 assert_eq!(buf[3] & BYTE1_RESERVED, BYTE1_RESERVED);
321 assert_eq!(buf[4] & BYTE2_RESERVED, BYTE2_RESERVED);
322 }
323
324 #[test]
325 fn serialize_rejects_over_range_field() {
326 let d = TelephoneDescriptor {
328 foreign_availability: false,
329 connection_type: 0,
330 country_prefix: b"",
331 international_area_code: b"",
332 operator_code: b"1234",
333 national_area_code: b"",
334 core_number: b"",
335 };
336 let mut buf = vec![0u8; d.serialized_len()];
337 assert!(matches!(
338 d.serialize_into(&mut buf).unwrap_err(),
339 Error::InvalidDescriptor { tag: TAG, .. }
340 ));
341 }
342
343 #[cfg(feature = "serde")]
344 #[test]
345 fn serde_serialize_stable() {
346 let d = sample();
351 let json = serde_json::to_string(&d).unwrap();
352 assert!(json.contains("connection_type"));
353 assert!(json.contains("foreign_availability"));
354 assert_eq!(json, serde_json::to_string(&sample()).unwrap());
355 }
356}