1use derive_more::with_trait::{Display, Error};
6
7use crate::attr::ChannelNumber;
8
9const PADDING: usize = 4;
12
13const NUMBER_SIZE: usize = 2;
17
18const LENGTH_SIZE: usize = 2;
22
23#[derive(Debug)]
28pub struct ChannelData {
29 number: u16,
33
34 data: Vec<u8>,
36}
37
38impl ChannelData {
39 pub const HEADER_SIZE: usize = LENGTH_SIZE + NUMBER_SIZE;
43
44 #[expect( clippy::missing_asserts_for_indexing,
47 reason = "length is checked with the first `if` expression",
48 )]
49 pub(crate) fn is_channel_data(data: &[u8]) -> bool {
50 if data.len() < Self::HEADER_SIZE {
51 return false;
52 }
53 let len = usize::from(u16::from_be_bytes([
54 data[NUMBER_SIZE],
55 data[NUMBER_SIZE + 1],
56 ]));
57
58 if len > data[Self::HEADER_SIZE..].len() {
59 return false;
60 }
61
62 ChannelNumber::new(u16::from_be_bytes([data[0], data[1]])).is_ok()
63 }
64
65 pub(crate) fn decode(mut raw: Vec<u8>) -> Result<Self, FormatError> {
71 if raw.len() < Self::HEADER_SIZE {
72 return Err(FormatError::BadChannelDataLength);
73 }
74
75 let number = u16::from_be_bytes([raw[0], raw[1]]);
76 if ChannelNumber::new(number).is_err() {
77 return Err(FormatError::InvalidChannelNumber);
78 }
79
80 let l = usize::from(u16::from_be_bytes([
81 raw[NUMBER_SIZE],
82 raw[NUMBER_SIZE + 1],
83 ]));
84
85 if l > raw[Self::HEADER_SIZE..].len() {
86 return Err(FormatError::BadChannelDataLength);
87 }
88
89 drop(raw.drain(0..Self::HEADER_SIZE));
91 if l != raw.len() {
92 raw.truncate(l);
93 }
94
95 Ok(Self { data: raw, number })
96 }
97
98 pub(crate) fn data(self) -> Vec<u8> {
100 self.data
101 }
102
103 pub(crate) const fn num(&self) -> u16 {
107 self.number
108 }
109
110 pub(crate) fn encode(
124 buf: &mut [u8],
125 payload_n: usize,
126 chan_num: u16,
127 ) -> Result<usize, FormatError> {
128 let length = Self::HEADER_SIZE + payload_n;
129 let padded_length = nearest_padded_value_length(length);
130 if buf.len() < padded_length {
131 return Err(FormatError::BufferTooShort);
132 }
133
134 #[expect(clippy::map_err_ignore, reason = "useless")]
135 let len = u16::try_from(payload_n)
136 .map_err(|_| FormatError::BadChannelDataLength)?;
137
138 buf[..NUMBER_SIZE].copy_from_slice(&chan_num.to_be_bytes());
139 buf[NUMBER_SIZE..Self::HEADER_SIZE].copy_from_slice(&len.to_be_bytes());
140 buf[length..padded_length].fill(0);
141
142 Ok(padded_length)
143 }
144}
145
146pub(crate) const fn nearest_padded_value_length(l: usize) -> usize {
148 let mut n = PADDING * (l / PADDING);
149 if n < l {
150 n += PADDING;
151 }
152 n
153}
154
155#[derive(Clone, Copy, Debug, Display, Error, Eq, PartialEq)]
157pub enum FormatError {
158 #[display("Channel Number not in [0x4000, 0x7FFF]")]
162 InvalidChannelNumber,
163
164 #[display("Invalid `ChannelData` length")]
166 BadChannelDataLength,
167
168 #[display("Provided buffer cannot fit encoded message")]
170 BufferTooShort,
171}
172
173#[cfg(test)]
174mod spec {
175 use super::{ChannelData, FormatError};
176 use crate::attr::ChannelNumber;
177
178 #[test]
179 fn encodes() {
180 let mut buf = [0, 0, 0, 0, 1, 2, 3, 4];
181 let encoded_n =
182 ChannelData::encode(&mut buf, 4, ChannelNumber::MIN + 1).unwrap();
183 assert_eq!(encoded_n, 8);
184 let decoded = ChannelData::decode(buf.to_vec()).unwrap();
185
186 assert!(
187 ChannelData::is_channel_data(&buf[..encoded_n]),
188 "wrong `is_channel_data`",
189 );
190 assert_eq!(vec![1, 2, 3, 4], decoded.data, "wrong decoded data");
191 assert_eq!(ChannelNumber::MIN + 1, decoded.number, "wrong number");
192 }
193
194 #[test]
195 fn encoded_equality() {
196 let tests = [
197 (
198 "equal",
199 ChannelData { number: ChannelNumber::MIN, data: vec![1, 2, 3] },
200 ChannelData { number: ChannelNumber::MIN, data: vec![1, 2, 3] },
201 true,
202 ),
203 (
204 "number",
205 ChannelData {
206 number: ChannelNumber::MIN + 1,
207 data: vec![1, 2, 3],
208 },
209 ChannelData { number: ChannelNumber::MIN, data: vec![1, 2, 3] },
210 false,
211 ),
212 (
213 "length",
214 ChannelData {
215 number: ChannelNumber::MIN,
216 data: vec![1, 2, 3, 4],
217 },
218 ChannelData { number: ChannelNumber::MIN, data: vec![1, 2, 3] },
219 false,
220 ),
221 (
222 "data",
223 ChannelData { number: ChannelNumber::MIN, data: vec![1, 2, 2] },
224 ChannelData { number: ChannelNumber::MIN, data: vec![1, 2, 3] },
225 false,
226 ),
227 ];
228
229 for (name, a, b, r) in tests {
230 let mut a_buf = vec![0; 100];
231 a_buf[ChannelData::HEADER_SIZE
232 ..ChannelData::HEADER_SIZE + a.data.len()]
233 .copy_from_slice(&a.data);
234 let a_enc_len =
235 ChannelData::encode(a_buf.as_mut(), a.data.len(), a.number)
236 .unwrap();
237
238 let mut b_buf = vec![0; 100];
239 b_buf[ChannelData::HEADER_SIZE
240 ..ChannelData::HEADER_SIZE + b.data.len()]
241 .copy_from_slice(&b.data);
242 let b_enc_len =
243 ChannelData::encode(b_buf.as_mut(), b.data.len(), b.number)
244 .unwrap();
245
246 let v = a_buf[..a_enc_len] == b_buf[..b_enc_len];
247
248 assert_eq!(v, r, "wrong equality of {name}");
249 }
250 }
251
252 #[test]
253 fn fails_decoding_correctly() {
254 let tests = [
255 ("small", vec![1, 2, 3], FormatError::BadChannelDataLength),
256 (
257 "zeroes",
258 vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
259 FormatError::InvalidChannelNumber,
260 ),
261 (
262 "bad chan number",
263 vec![63, 255, 0, 0, 0, 4, 0, 0, 1, 2, 3, 4],
264 FormatError::InvalidChannelNumber,
265 ),
266 (
267 "bad length",
268 vec![0x40, 0x40, 0x02, 0x23, 0x16, 0, 0, 0, 0, 0, 0, 0],
269 FormatError::BadChannelDataLength,
270 ),
271 ];
272 for (name, buf, want_err) in tests {
273 if let Err(e) = ChannelData::decode(buf) {
274 assert_eq!(want_err, e, "wrong error of {name}");
275 } else {
276 panic!("expected `Err`, but got `Ok` in {name}");
277 }
278 }
279 }
280
281 #[test]
282 fn is_channel_data_detects_correctly() {
283 let tests = [
284 ("small", vec![1, 2, 3, 4], false),
285 ("zeroes", vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], false),
286 ];
287 for (name, buf, r) in tests {
288 let v = ChannelData::is_channel_data(&buf);
289
290 assert_eq!(v, r, "wrong result in {name}");
291 }
292 }
293
294 const CHANDATA_TEST_HEX: [&str; 2] = [
295 "40000064000100502112a442453731722f2b322b6e4e7a5800060009443758343a3377\
296 6c59000000c0570004000003e7802a00081d5136dab65b169300250000002400046e00\
297 1eff0008001465d11a330e104a9f5f598af4abc6a805f26003cf802800046b334442",
298 "4000022316fefd0000000000000011012c0b000120000100000000012000011d00011a\
299 308201163081bda003020102020900afe52871340bd13e300a06082a8648ce3d040302\
300 3011310f300d06035504030c06576562525443301e170d313830383131303335323030\
301 5a170d3138303931313033353230305a3011310f300d06035504030c06576562525443\
302 3059301306072a8648ce3d020106082a8648ce3d030107034200048080e348bd41469c\
303 fb7a7df316676fd72a06211765a50a0f0b07526c872dcf80093ed5caa3f5a40a725dd7\
304 4b41b79bdd19ee630c5313c8601d6983286c8722c1300a06082a8648ce3d0403020348\
305 003045022100d13a0a131bc2a9f27abd3d4c547f7ef172996a0c0755c707b6a3e048d8\
306 762ded0220055fc8182818a644a3d3b5b157304cc3f1421fadb06263bfb451cd28be4b\
307 c9ee16fefd0000000000000012002d10000021000200000000002120f7e23c97df45a9\
308 6e13cb3e76b37eff5e73e2aee0b6415d29443d0bd24f578b7e16fefd00000000000000\
309 1300580f00004c000300000000004c040300483046022100fdbb74eab1aca1532e6ac0\
310 ab267d5b83a24bb4d5d7d504936e2785e6e388b2bd022100f6a457b9edd9ead52a9d0e\
311 9a19240b3a68b95699546c044f863cf8349bc8046214fefd0000000000000014000101\
312 16fefd0001000000000004003000010000000000040aae2421e7d549632a7def8ed068\
313 98c3c5b53f5b812a963a39ab6cdd303b79bdb237f3314c1da21b",
314 ];
315
316 #[test]
317 fn chrome_channel_data() {
318 let mut data = vec![];
319 let mut messages = vec![];
320
321 for h in &CHANDATA_TEST_HEX {
323 let b = match hex::decode(h) {
324 Ok(b) => b,
325 Err(_) => panic!("hex decode error"),
326 };
327 data.push(b);
328 }
329
330 for packet in data {
333 let m = ChannelData::decode(packet.clone()).unwrap();
334
335 let mut buf = m.data.clone();
336 let payload_size = m.data.len();
337 buf.splice(
339 0..0,
340 std::iter::repeat(0u8).take(ChannelData::HEADER_SIZE),
341 );
342 buf.resize(buf.len() + 3, 0);
343
344 let encoded_len =
345 ChannelData::encode(&mut buf, payload_size, m.number).unwrap();
346 let decoded =
347 ChannelData::decode(buf[..encoded_len].to_vec()).unwrap();
348
349 assert_eq!(m.data, decoded.data, "wrong payload");
350 assert_eq!(m.number, decoded.number, "wrong number");
351
352 messages.push(m);
353 }
354
355 assert_eq!(messages.len(), 2, "wrong number of messages");
356 }
357}