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