1use crate::{EncodeError, ParseError};
2
3#[derive(Debug)]
8pub struct OptionEncoder<'a> {
9 buf: &'a mut [u8],
10 pos: usize,
11 last_number: u16,
12 wrote_any: bool,
13}
14
15impl<'a> OptionEncoder<'a> {
16 pub fn new(buf: &'a mut [u8]) -> Self {
18 Self {
19 buf,
20 pos: 0,
21 last_number: 0,
22 wrote_any: false,
23 }
24 }
25
26 pub fn with_last_number(buf: &'a mut [u8], last_number: u16) -> Self {
28 Self {
29 buf,
30 pos: 0,
31 last_number,
32 wrote_any: true,
33 }
34 }
35
36 pub fn put(&mut self, number: u16, value: &[u8]) -> Result<(), EncodeError> {
38 if self.wrote_any && number < self.last_number {
39 return Err(EncodeError::OptionOutOfOrder);
40 }
41 let delta = if self.wrote_any {
42 number - self.last_number
43 } else {
44 number
45 };
46 let delta_len = encoded_len(delta);
47 let value_len = encoded_len(value.len() as u16);
48 let required = 1 + delta_len + value_len + value.len();
49 if self.pos + required > self.buf.len() {
50 return Err(EncodeError::BufferTooSmall);
51 }
52
53 let header_pos = self.pos;
54 self.pos += 1;
55 let delta_nibble = write_extended(&mut self.buf[self.pos..], delta)?;
56 self.pos += delta_len;
57 let len_nibble = write_extended(&mut self.buf[self.pos..], value.len() as u16)?;
58 self.pos += value_len;
59 self.buf[header_pos] = (delta_nibble << 4) | len_nibble;
60 self.buf[self.pos..self.pos + value.len()].copy_from_slice(value);
61 self.pos += value.len();
62 self.last_number = number;
63 self.wrote_any = true;
64 Ok(())
65 }
66
67 pub fn end_marker(&mut self) -> Result<(), EncodeError> {
69 if self.pos >= self.buf.len() {
70 return Err(EncodeError::BufferTooSmall);
71 }
72 self.buf[self.pos] = 0xFF;
73 self.pos += 1;
74 Ok(())
75 }
76
77 pub fn put_u32(&mut self, number: u16, value: u32) -> Result<(), EncodeError> {
79 let (bytes, len) = minimal_u32(value);
80 self.put(number, &bytes[4 - len..])
81 }
82
83 pub fn put_i32(&mut self, number: u16, value: i32) -> Result<(), EncodeError> {
85 let (bytes, len) = minimal_i32(value);
86 self.put(number, &bytes[4 - len..])
87 }
88
89 pub fn finish(self) -> usize {
91 self.pos
92 }
93}
94
95#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
109pub struct TraceSignalEntry([u8; 2]);
110
111impl TraceSignalEntry {
112 pub const UNMEASURED: Self = Self([0, 0]);
120
121 pub const fn new(rssi_dbm: i16, snr_centibels: i16) -> Self {
123 Self([saturate_rssi(rssi_dbm), saturate_snr(snr_centibels)])
124 }
125
126 pub const fn from_measurements(rssi_dbm: Option<i16>, snr_centibels: Option<i16>) -> Self {
131 Self([
132 match rssi_dbm {
133 Some(rssi) => saturate_rssi(rssi),
134 None => Self::UNMEASURED.0[0],
135 },
136 match snr_centibels {
137 Some(snr) => saturate_snr(snr),
138 None => Self::UNMEASURED.0[1],
139 },
140 ])
141 }
142
143 pub const fn as_bytes(self) -> [u8; 2] {
145 self.0
146 }
147}
148
149const fn saturate_rssi(rssi_dbm: i16) -> u8 {
150 if rssi_dbm >= 0 {
151 0
152 } else if rssi_dbm < -255 {
153 255
154 } else {
155 (-rssi_dbm) as u8
156 }
157}
158
159const fn saturate_snr(snr_centibels: i16) -> u8 {
160 if snr_centibels > 127 {
161 127u8
162 } else if snr_centibels < -128 {
163 0x80
164 } else {
165 (snr_centibels as i8) as u8
166 }
167}
168
169pub fn parse_be_u32(bytes: &[u8]) -> Result<u32, ParseError> {
173 if bytes.len() > 4 {
174 return Err(ParseError::MalformedOption);
175 }
176 let mut arr = [0u8; 4];
177 arr[4 - bytes.len()..].copy_from_slice(bytes);
178 Ok(u32::from_be_bytes(arr))
179}
180
181pub fn parse_be_i32(bytes: &[u8]) -> Result<i32, ParseError> {
185 if bytes.is_empty() {
186 return Ok(0);
187 }
188 if bytes.len() > 4 {
189 return Err(ParseError::MalformedOption);
190 }
191 let sign = if bytes[0] & 0x80 != 0 { 0xFF } else { 0x00 };
192 let mut arr = [sign; 4];
193 arr[4 - bytes.len()..].copy_from_slice(bytes);
194 Ok(i32::from_be_bytes(arr))
195}
196
197fn minimal_u32(v: u32) -> ([u8; 4], usize) {
198 let bytes = v.to_be_bytes();
199 let skip = bytes.iter().position(|&b| b != 0).unwrap_or(4);
200 (bytes, 4 - skip)
201}
202
203fn minimal_i32(v: i32) -> ([u8; 4], usize) {
204 if v == 0 {
205 return ([0u8; 4], 0);
206 }
207 let bytes = v.to_be_bytes();
208 let mut skip = 0;
209 if v > 0 {
210 while skip < 3 && bytes[skip] == 0x00 && (bytes[skip + 1] & 0x80 == 0) {
211 skip += 1;
212 }
213 } else {
214 while skip < 3 && bytes[skip] == 0xFF && (bytes[skip + 1] & 0x80 != 0) {
215 skip += 1;
216 }
217 }
218 (bytes, 4 - skip)
219}
220
221#[derive(Clone, Debug)]
226pub struct OptionDecoder<'a> {
227 data: &'a [u8],
228 pos: usize,
229 last_number: u16,
230 finished: bool,
231 errored: bool,
232}
233
234impl<'a> OptionDecoder<'a> {
235 pub fn new(data: &'a [u8]) -> Self {
237 Self {
238 data,
239 pos: 0,
240 last_number: 0,
241 finished: false,
242 errored: false,
243 }
244 }
245
246 pub fn position(&self) -> usize {
252 self.pos
253 }
254
255 pub fn last_number(&self) -> u16 {
257 self.last_number
258 }
259
260 pub fn remainder(&self) -> &'a [u8] {
265 if self.finished {
266 &self.data[self.pos..]
267 } else {
268 &[]
269 }
270 }
271}
272
273impl<'a> Iterator for OptionDecoder<'a> {
274 type Item = Result<(u16, &'a [u8]), ParseError>;
275
276 fn next(&mut self) -> Option<Self::Item> {
277 if self.finished || self.errored {
278 return None;
279 }
280 if self.pos >= self.data.len() {
281 self.finished = true;
282 return None;
283 }
284
285 let first = self.data[self.pos];
286 if first == 0xFF {
287 self.pos += 1;
288 self.finished = true;
289 return None;
290 }
291
292 self.pos += 1;
293 let delta_nibble = first >> 4;
294 let len_nibble = first & 0x0F;
295 let (delta, delta_len) = match read_extended(&self.data[self.pos..], delta_nibble) {
296 Ok(value) => value,
297 Err(err) => {
298 self.errored = true;
299 return Some(Err(err));
300 }
301 };
302 self.pos += delta_len;
303 let (len, len_len) = match read_extended(&self.data[self.pos..], len_nibble) {
304 Ok(value) => value,
305 Err(err) => {
306 self.errored = true;
307 return Some(Err(err));
308 }
309 };
310 self.pos += len_len;
311
312 if self.pos + len as usize > self.data.len() {
313 self.errored = true;
314 return Some(Err(ParseError::Truncated));
315 }
316
317 let number = self
318 .last_number
319 .checked_add(delta)
320 .ok_or(ParseError::MalformedOption);
321 let number = match number {
322 Ok(value) => value,
323 Err(err) => {
324 self.errored = true;
325 return Some(Err(err));
326 }
327 };
328 let value = &self.data[self.pos..self.pos + len as usize];
329 self.pos += len as usize;
330 self.last_number = number;
331 Some(Ok((number, value)))
332 }
333}
334
335fn encoded_len(value: u16) -> usize {
336 match value {
337 0..=12 => 0,
338 13..=268 => 1,
339 _ => 2,
340 }
341}
342
343fn write_extended(buf: &mut [u8], value: u16) -> Result<u8, EncodeError> {
344 match value {
345 0..=12 => Ok(value as u8),
346 13..=268 => {
347 if buf.is_empty() {
348 return Err(EncodeError::BufferTooSmall);
349 }
350 buf[0] = (value - 13) as u8;
351 Ok(13)
352 }
353 _ => {
354 if buf.len() < 2 {
355 return Err(EncodeError::BufferTooSmall);
356 }
357 let extended = value - 269;
358 buf[..2].copy_from_slice(&extended.to_be_bytes());
359 Ok(14)
360 }
361 }
362}
363
364fn read_extended(data: &[u8], nibble: u8) -> Result<(u16, usize), ParseError> {
365 match nibble {
366 0..=12 => Ok((nibble as u16, 0)),
367 13 => {
368 if data.is_empty() {
369 return Err(ParseError::Truncated);
370 }
371 Ok((data[0] as u16 + 13, 1))
372 }
373 14 => {
374 if data.len() < 2 {
375 return Err(ParseError::Truncated);
376 }
377 let value = u16::from_be_bytes([data[0], data[1]])
378 .checked_add(269)
379 .ok_or(ParseError::InvalidOptionNibble)?;
380 Ok((value, 2))
381 }
382 _ => Err(ParseError::InvalidOptionNibble),
383 }
384}
385
386#[cfg(test)]
387mod tests {
388 use super::*;
389
390 #[test]
393 fn a_trace_signal_entry_is_negated_rssi_then_signed_centibels() {
394 assert_eq!(TraceSignalEntry::new(-91, 42).as_bytes(), [91, 42]);
395 assert_eq!(TraceSignalEntry::new(-120, -75).as_bytes(), [120, 0xB5]);
396 }
397
398 #[test]
399 fn a_reading_past_the_end_of_the_range_saturates() {
400 assert_eq!(TraceSignalEntry::new(-400, 0).as_bytes()[0], 255);
403 assert_eq!(TraceSignalEntry::new(-90, 500).as_bytes()[1], 127);
404 assert_eq!(TraceSignalEntry::new(-90, -500).as_bytes()[1], 0x80);
405 }
406
407 #[test]
408 fn a_radio_that_reports_one_field_still_contributes_it() {
409 let entry = TraceSignalEntry::from_measurements(Some(-91), None);
410 assert_eq!(entry.as_bytes()[0], 91);
411 assert_eq!(
412 entry.as_bytes()[1],
413 TraceSignalEntry::UNMEASURED.as_bytes()[1]
414 );
415
416 assert_eq!(
417 TraceSignalEntry::from_measurements(None, None),
418 TraceSignalEntry::UNMEASURED
419 );
420 }
421
422 #[test]
425 fn parse_be_u32_values() {
426 assert_eq!(parse_be_u32(&[]).unwrap(), 0);
427 assert_eq!(parse_be_u32(&[1]).unwrap(), 1);
428 assert_eq!(parse_be_u32(&[1, 0]).unwrap(), 256);
429 assert_eq!(parse_be_u32(&[1, 0, 0]).unwrap(), 65536);
430 assert_eq!(parse_be_u32(&[0, 1, 0]).unwrap(), 256); assert_eq!(parse_be_u32(&[0xFF, 0xFF, 0xFF, 0xFF]).unwrap(), u32::MAX);
432 assert!(parse_be_u32(&[0; 5]).is_err());
433 }
434
435 #[test]
438 fn parse_be_i32_values() {
439 assert_eq!(parse_be_i32(&[]).unwrap(), 0);
440 assert_eq!(parse_be_i32(&[0x7F]).unwrap(), 127);
441 assert_eq!(parse_be_i32(&[0x00, 0x80]).unwrap(), 128);
442 assert_eq!(parse_be_i32(&[0xFF]).unwrap(), -1);
443 assert_eq!(parse_be_i32(&[0x80]).unwrap(), -128);
444 assert_eq!(parse_be_i32(&[0xFF, 0x7F]).unwrap(), -129);
445 assert_eq!(parse_be_i32(&[0x80, 0x00, 0x00, 0x00]).unwrap(), i32::MIN);
446 assert_eq!(parse_be_i32(&[0x7F, 0xFF, 0xFF, 0xFF]).unwrap(), i32::MAX);
447 assert!(parse_be_i32(&[0; 5]).is_err());
448 }
449
450 #[test]
453 fn put_u32_round_trips() {
454 let cases: &[u32] = &[0, 1, 127, 128, 255, 256, u32::MAX];
455 for &v in cases {
456 let mut buf = [0u8; 16];
457 let mut enc = OptionEncoder::new(&mut buf);
458 enc.put_u32(1, v).unwrap();
459 let len = enc.finish();
460 let (_, value) = OptionDecoder::new(&buf[..len]).next().unwrap().unwrap();
461 assert_eq!(parse_be_u32(value).unwrap(), v, "failed for u32 {v}");
462 }
463 }
464
465 #[test]
466 fn put_i32_round_trips() {
467 let cases: &[i32] = &[0, 1, 127, 128, -1, -128, -129, i32::MIN, i32::MAX];
468 for &v in cases {
469 let mut buf = [0u8; 16];
470 let mut enc = OptionEncoder::new(&mut buf);
471 enc.put_i32(1, v).unwrap();
472 let len = enc.finish();
473 let (_, value) = OptionDecoder::new(&buf[..len]).next().unwrap().unwrap();
474 assert_eq!(parse_be_i32(value).unwrap(), v, "failed for i32 {v}");
475 }
476 }
477
478 #[test]
482 fn wire_inline_delta_and_length() {
483 let mut buf = [0u8; 8];
484 let mut enc = OptionEncoder::new(&mut buf);
485 enc.put(5, &[0xAB]).unwrap();
486 assert_eq!(enc.finish(), 2);
487 assert_eq!(&buf[..2], &[0x51, 0xAB]);
488 }
489
490 #[test]
492 fn wire_option_zero_empty_value() {
493 let mut buf = [0u8; 4];
494 let mut enc = OptionEncoder::new(&mut buf);
495 enc.put(0, &[]).unwrap();
496 assert_eq!(enc.finish(), 1);
497 assert_eq!(buf[0], 0x00);
498 }
499
500 #[test]
502 fn wire_extended_delta_1byte_boundary() {
503 let mut buf = [0u8; 8];
504 let mut enc = OptionEncoder::new(&mut buf);
505 enc.put(13, &[]).unwrap();
506 assert_eq!(enc.finish(), 2);
507 assert_eq!(&buf[..2], &[0xD0, 0x00]);
509 }
510
511 #[test]
513 fn wire_extended_delta_1byte_max() {
514 let mut buf = [0u8; 8];
515 let mut enc = OptionEncoder::new(&mut buf);
516 enc.put(268, &[]).unwrap();
517 assert_eq!(enc.finish(), 2);
518 assert_eq!(&buf[..2], &[0xD0, 0xFF]);
519 }
520
521 #[test]
523 fn wire_extended_delta_2byte_boundary() {
524 let mut buf = [0u8; 8];
525 let mut enc = OptionEncoder::new(&mut buf);
526 enc.put(269, &[]).unwrap();
527 assert_eq!(enc.finish(), 3);
528 assert_eq!(&buf[..3], &[0xE0, 0x00, 0x00]);
529 }
530
531 #[test]
533 fn wire_extended_length_1byte() {
534 let mut buf = [0u8; 32];
535 let value = [0u8; 13];
536 {
537 let mut enc = OptionEncoder::new(&mut buf);
538 enc.put(0, &value).unwrap();
539 assert_eq!(enc.finish(), 15);
540 }
541 assert_eq!(buf[0], 0x0D);
543 assert_eq!(buf[1], 0x00);
544 assert_eq!(&buf[2..15], &value);
545 }
546
547 #[test]
549 fn wire_end_marker() {
550 let mut buf = [0u8; 4];
551 let mut enc = OptionEncoder::new(&mut buf);
552 enc.put(1, &[0x01]).unwrap();
553 enc.end_marker().unwrap();
554 let len = enc.finish();
555 assert_eq!(buf[len - 1], 0xFF);
556 }
557
558 #[test]
561 fn encoder_multiple_options_sequential() {
562 let mut buf = [0u8; 16];
563 let mut enc = OptionEncoder::new(&mut buf);
564 enc.put(1, &[0x01]).unwrap();
565 enc.put(3, &[0x02]).unwrap(); enc.put(3, &[0x03]).unwrap(); let len = enc.finish();
568
569 let items: Vec<_> = OptionDecoder::new(&buf[..len])
570 .collect::<Result<_, _>>()
571 .unwrap();
572 assert_eq!(
573 items,
574 vec![(1, &[0x01u8][..]), (3, &[0x02][..]), (3, &[0x03][..])]
575 );
576 }
577
578 #[test]
579 fn encoder_with_last_number_continues_delta() {
580 let mut buf = [0u8; 8];
582 let mut enc = OptionEncoder::with_last_number(&mut buf, 10);
583 enc.put(12, &[0xBB]).unwrap();
584 let len = enc.finish();
585 assert_eq!(&buf[..len], &[0x21, 0xBB]);
587 }
588
589 #[test]
590 fn encoder_large_option_number_round_trip() {
591 let mut buf = [0u8; 16];
592 let mut enc = OptionEncoder::new(&mut buf);
593 enc.put(u16::MAX, &[0xCC]).unwrap();
594 let len = enc.finish();
595 let (num, val) = OptionDecoder::new(&buf[..len]).next().unwrap().unwrap();
596 assert_eq!(num, u16::MAX);
597 assert_eq!(val, &[0xCC]);
598 }
599
600 #[test]
603 fn encoder_out_of_order_returns_error() {
604 let mut buf = [0u8; 16];
605 let mut enc = OptionEncoder::new(&mut buf);
606 enc.put(5, &[]).unwrap();
607 assert_eq!(enc.put(3, &[]), Err(EncodeError::OptionOutOfOrder));
608 }
609
610 #[test]
611 fn encoder_buffer_too_small_returns_error() {
612 let mut buf = [0u8; 1]; let mut enc = OptionEncoder::new(&mut buf);
614 assert_eq!(enc.put(0, &[0x01]), Err(EncodeError::BufferTooSmall));
615 }
616
617 #[test]
618 fn encoder_end_marker_buffer_too_small() {
619 let mut buf = [0u8; 0];
620 let mut enc = OptionEncoder::new(&mut buf);
621 assert_eq!(enc.end_marker(), Err(EncodeError::BufferTooSmall));
622 }
623
624 #[test]
627 fn decoder_empty_input_yields_nothing() {
628 assert!(OptionDecoder::new(&[]).next().is_none());
629 }
630
631 #[test]
632 fn decoder_end_marker_only_yields_nothing() {
633 let mut dec = OptionDecoder::new(&[0xFF]);
634 assert!(dec.next().is_none());
635 assert_eq!(dec.remainder(), &[] as &[u8]);
636 }
637
638 #[test]
639 fn decoder_remainder_after_end_marker() {
640 let mut buf = [0u8; 16];
642 let mut enc = OptionEncoder::new(&mut buf);
643 enc.put(1, &[0xAA]).unwrap();
644 enc.end_marker().unwrap();
645 let opt_len = enc.finish();
646 buf[opt_len] = 0xDE;
647 buf[opt_len + 1] = 0xAD;
648
649 let mut dec = OptionDecoder::new(&buf[..opt_len + 2]);
650 let _ = dec.next().unwrap().unwrap(); assert!(dec.next().is_none()); assert_eq!(dec.remainder(), &[0xDE, 0xAD]);
653 }
654
655 #[test]
656 fn decoder_remainder_empty_without_end_marker() {
657 let mut buf = [0u8; 8];
658 let mut enc = OptionEncoder::new(&mut buf);
659 enc.put(1, &[0x01]).unwrap();
660 let len = enc.finish();
661
662 let mut dec = OptionDecoder::new(&buf[..len]);
663 let _ = dec.next().unwrap().unwrap();
664 assert!(dec.next().is_none());
665 assert_eq!(dec.remainder(), &[] as &[u8]);
667 }
668
669 #[test]
670 fn decoder_remainder_empty_before_exhausted() {
671 let mut buf = [0u8; 8];
673 let mut enc = OptionEncoder::new(&mut buf);
674 enc.put(1, &[0x01]).unwrap();
675 enc.end_marker().unwrap();
676 let len = enc.finish();
677
678 let dec = OptionDecoder::new(&buf[..len]);
679 assert_eq!(dec.remainder(), &[] as &[u8]);
681 }
682
683 #[test]
686 fn decoder_truncated_value_returns_error() {
687 let data = [0x03, 0xAB]; let mut dec = OptionDecoder::new(&data);
690 assert!(matches!(dec.next(), Some(Err(ParseError::Truncated))));
691 assert!(dec.next().is_none()); }
693
694 #[test]
695 fn decoder_truncated_extended_delta_returns_error() {
696 let data = [0xD0]; let mut dec = OptionDecoder::new(&data);
699 assert!(matches!(dec.next(), Some(Err(ParseError::Truncated))));
700 assert!(dec.next().is_none());
701 }
702
703 #[test]
704 fn decoder_invalid_nibble_returns_error() {
705 let data = [0xF0]; let mut dec = OptionDecoder::new(&data);
708 assert!(matches!(
709 dec.next(),
710 Some(Err(ParseError::InvalidOptionNibble))
711 ));
712 assert!(dec.next().is_none());
713 }
714
715 #[test]
716 fn decoder_option_number_overflow_returns_error() {
717 let mut buf = [0u8; 16];
719 let mut enc = OptionEncoder::new(&mut buf);
720 enc.put(u16::MAX, &[]).unwrap();
721 let len = enc.finish();
722
723 buf[len] = 0x10; let mut dec = OptionDecoder::new(&buf[..len + 1]);
726 let _ = dec.next().unwrap().unwrap(); assert!(matches!(dec.next(), Some(Err(ParseError::MalformedOption))));
728 assert!(dec.next().is_none());
729 }
730}