1use crate::error::{Error, Result};
16use crate::traits::Descriptor;
17use dvb_common::{Parse, Serialize};
18
19pub const TAG: u8 = 0x7D;
21const HEADER_LEN: usize = 2;
22const BODY_LEN: usize = 5;
23
24const VERSION_MAX: u8 = 0x1F;
26const UPDATE_POLICY_MAX: u8 = 0x07;
28
29#[derive(Debug, Clone, PartialEq, Eq)]
31#[cfg_attr(feature = "serde", derive(serde::Serialize))]
32pub struct XaitLocationDescriptor {
33 pub xait_original_network_id: u16,
35 pub xait_service_id: u16,
37 pub xait_version_number: u8,
39 pub xait_update_policy: u8,
41}
42
43impl<'a> Parse<'a> for XaitLocationDescriptor {
44 type Error = crate::error::Error;
45 fn parse(bytes: &'a [u8]) -> Result<Self> {
46 if bytes.len() < HEADER_LEN {
47 return Err(Error::BufferTooShort {
48 need: HEADER_LEN,
49 have: bytes.len(),
50 what: "XaitLocationDescriptor header",
51 });
52 }
53 if bytes[0] != TAG {
54 return Err(Error::InvalidDescriptor {
55 tag: bytes[0],
56 reason: "unexpected tag for xait_location_descriptor",
57 });
58 }
59 let length = bytes[1] as usize;
60 let end = HEADER_LEN + length;
61 if bytes.len() < end {
62 return Err(Error::BufferTooShort {
63 need: end,
64 have: bytes.len(),
65 what: "XaitLocationDescriptor body",
66 });
67 }
68 if length < BODY_LEN {
69 return Err(Error::InvalidDescriptor {
70 tag: TAG,
71 reason: "xait_location_descriptor body shorter than 5 bytes",
72 });
73 }
74 let body = &bytes[HEADER_LEN..end];
75 let xait_original_network_id = u16::from_be_bytes([body[0], body[1]]);
76 let xait_service_id = u16::from_be_bytes([body[2], body[3]]);
77 let xait_version_number = (body[4] >> 3) & VERSION_MAX;
78 let xait_update_policy = body[4] & UPDATE_POLICY_MAX;
79 Ok(Self {
80 xait_original_network_id,
81 xait_service_id,
82 xait_version_number,
83 xait_update_policy,
84 })
85 }
86}
87
88impl Serialize for XaitLocationDescriptor {
89 type Error = crate::error::Error;
90 fn serialized_len(&self) -> usize {
91 HEADER_LEN + BODY_LEN
92 }
93
94 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
95 if self.xait_version_number > VERSION_MAX {
96 return Err(Error::InvalidDescriptor {
97 tag: TAG,
98 reason: "xait_version_number exceeds 5 bits",
99 });
100 }
101 if self.xait_update_policy > UPDATE_POLICY_MAX {
102 return Err(Error::InvalidDescriptor {
103 tag: TAG,
104 reason: "xait_update_policy exceeds 3 bits",
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] = BODY_LEN as u8;
116 buf[2..4].copy_from_slice(&self.xait_original_network_id.to_be_bytes());
117 buf[4..6].copy_from_slice(&self.xait_service_id.to_be_bytes());
118 buf[6] = ((self.xait_version_number & VERSION_MAX) << 3)
119 | (self.xait_update_policy & UPDATE_POLICY_MAX);
120 Ok(len)
121 }
122}
123
124impl<'a> Descriptor<'a> for XaitLocationDescriptor {
125 const TAG: u8 = TAG;
126 fn descriptor_length(&self) -> u8 {
127 BODY_LEN as u8
128 }
129}
130
131impl<'a> crate::traits::DescriptorDef<'a> for XaitLocationDescriptor {
132 const TAG: u8 = TAG;
133 const NAME: &'static str = "XAIT_LOCATION";
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139
140 #[test]
141 fn parse_extracts_fields() {
142 let bytes = [TAG, 5, 0x20, 0x24, 0x12, 0x34, (5 << 3) | 1];
144 let d = XaitLocationDescriptor::parse(&bytes).unwrap();
145 assert_eq!(d.xait_original_network_id, 0x2024);
146 assert_eq!(d.xait_service_id, 0x1234);
147 assert_eq!(d.xait_version_number, 5);
148 assert_eq!(d.xait_update_policy, 1);
149 }
150
151 #[test]
152 fn parse_ignores_trailing_bytes() {
153 let bytes = [TAG, 6, 0x00, 0x01, 0x00, 0x02, 0x00, 0xFF];
154 let d = XaitLocationDescriptor::parse(&bytes).unwrap();
155 assert_eq!(d.xait_original_network_id, 0x0001);
156 assert_eq!(d.xait_service_id, 0x0002);
157 assert_eq!(d.xait_version_number, 0);
158 assert_eq!(d.xait_update_policy, 0);
159 }
160
161 #[test]
162 fn parse_rejects_wrong_tag() {
163 let bytes = [0x7C, 5, 0, 0, 0, 0, 0];
164 assert!(matches!(
165 XaitLocationDescriptor::parse(&bytes).unwrap_err(),
166 Error::InvalidDescriptor { tag: 0x7C, .. }
167 ));
168 }
169
170 #[test]
171 fn parse_rejects_body_too_short() {
172 let bytes = [TAG, 4, 0, 0, 0, 0];
173 assert!(matches!(
174 XaitLocationDescriptor::parse(&bytes).unwrap_err(),
175 Error::InvalidDescriptor { .. }
176 ));
177 }
178
179 #[test]
180 fn parse_rejects_length_overrunning_buffer() {
181 let bytes = [TAG, 5, 0, 0, 0];
182 assert!(matches!(
183 XaitLocationDescriptor::parse(&bytes).unwrap_err(),
184 Error::BufferTooShort { .. }
185 ));
186 }
187
188 #[test]
189 fn serialize_round_trip() {
190 let d = XaitLocationDescriptor {
191 xait_original_network_id: 0x233A,
192 xait_service_id: 0x4470,
193 xait_version_number: 0x1F,
194 xait_update_policy: 0,
195 };
196 let mut buf = vec![0u8; d.serialized_len()];
197 d.serialize_into(&mut buf).unwrap();
198 assert_eq!(XaitLocationDescriptor::parse(&buf).unwrap(), d);
199 }
200
201 #[test]
202 fn serialize_rejects_version_over_range() {
203 let d = XaitLocationDescriptor {
204 xait_original_network_id: 0,
205 xait_service_id: 0,
206 xait_version_number: 0x20,
207 xait_update_policy: 0,
208 };
209 let mut buf = vec![0u8; d.serialized_len()];
210 assert!(matches!(
211 d.serialize_into(&mut buf).unwrap_err(),
212 Error::InvalidDescriptor { .. }
213 ));
214 }
215
216 #[test]
217 fn serialize_rejects_update_policy_over_range() {
218 let d = XaitLocationDescriptor {
219 xait_original_network_id: 0,
220 xait_service_id: 0,
221 xait_version_number: 0,
222 xait_update_policy: 0x08,
223 };
224 let mut buf = vec![0u8; d.serialized_len()];
225 assert!(matches!(
226 d.serialize_into(&mut buf).unwrap_err(),
227 Error::InvalidDescriptor { .. }
228 ));
229 }
230
231 #[cfg(feature = "serde")]
232 #[test]
233 fn serde_round_trip() {
234 let d = XaitLocationDescriptor {
235 xait_original_network_id: 0x0001,
236 xait_service_id: 0x0539,
237 xait_version_number: 3,
238 xait_update_policy: 1,
239 };
240 let j = serde_json::to_string(&d).unwrap();
241 let _v: serde_json::Value = serde_json::from_str(&j).unwrap();
243 }
244}