1use alloc::vec::Vec;
16
17use broadcast_common::{Parse, Serialize};
18
19use crate::error::{Error, Result};
20use crate::header::HeaderExtension;
21
22pub const ONE_BYTE_PROFILE_ID: u16 = 0xBEDE;
29
30const TWO_BYTE_PROFILE_ID_MASK: u16 = 0xFFF0;
34const TWO_BYTE_PROFILE_ID_PREFIX: u16 = 0x1000;
37
38const ONE_BYTE_STOP_ID: u8 = 15;
41const PADDING_BYTE: u8 = 0x00;
44
45const ONE_BYTE_ID_MIN: u8 = 1;
48const ONE_BYTE_ID_MAX: u8 = 14;
50const ONE_BYTE_DATA_MIN: usize = 1;
54const ONE_BYTE_DATA_MAX: usize = 16;
57
58const TWO_BYTE_ID_MIN: u8 = 1;
63const TWO_BYTE_DATA_MAX: usize = u8::MAX as usize;
67
68const EXT_ALIGN: usize = 4;
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
81#[cfg_attr(feature = "serde", derive(serde::Serialize))]
82#[cfg_attr(feature = "serde", serde(transparent))]
83pub struct OneByteId(u8);
84
85impl OneByteId {
86 pub fn new(id: u8) -> Result<Self> {
90 if (ONE_BYTE_ID_MIN..=ONE_BYTE_ID_MAX).contains(&id) {
91 Ok(Self(id))
92 } else {
93 Err(Error::InvalidOneByteExtensionId(id))
94 }
95 }
96
97 #[must_use]
99 pub fn get(self) -> u8 {
100 self.0
101 }
102}
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
109#[cfg_attr(feature = "serde", derive(serde::Serialize))]
110#[cfg_attr(feature = "serde", serde(transparent))]
111pub struct TwoByteId(u8);
112
113impl TwoByteId {
114 pub fn new(id: u8) -> Result<Self> {
117 if id >= TWO_BYTE_ID_MIN {
118 Ok(Self(id))
119 } else {
120 Err(Error::InvalidTwoByteExtensionId)
121 }
122 }
123
124 #[must_use]
126 pub fn get(self) -> u8 {
127 self.0
128 }
129}
130
131#[derive(Debug, Clone, Copy, PartialEq, Eq)]
138#[cfg_attr(feature = "serde", derive(serde::Serialize))]
139pub struct OneByteElement<'a> {
140 pub id: OneByteId,
142 pub data: &'a [u8],
145}
146
147#[derive(Debug, Clone, PartialEq, Eq, Default)]
152#[cfg_attr(feature = "serde", derive(serde::Serialize))]
153pub struct OneByteElements<'a>(pub Vec<OneByteElement<'a>>);
154
155impl<'a> OneByteElements<'a> {
156 #[must_use]
158 pub fn elements(&self) -> &[OneByteElement<'a>] {
159 &self.0
160 }
161}
162
163impl<'a> IntoIterator for OneByteElements<'a> {
164 type Item = OneByteElement<'a>;
165 type IntoIter = alloc::vec::IntoIter<OneByteElement<'a>>;
166
167 fn into_iter(self) -> Self::IntoIter {
168 self.0.into_iter()
169 }
170}
171
172impl<'a> Parse<'a> for OneByteElements<'a> {
173 type Error = Error;
174
175 fn parse(bytes: &'a [u8]) -> Result<Self> {
176 let mut elements = Vec::new();
177 let mut pos = 0;
178 while pos < bytes.len() {
179 let b = bytes[pos];
180 if b == PADDING_BYTE {
181 pos += 1;
183 continue;
184 }
185 let id_nibble = b >> 4;
186 if id_nibble == ONE_BYTE_STOP_ID || id_nibble == 0 {
187 break;
193 }
194 let len = usize::from(b & 0x0F) + 1; let data_start = pos + 1;
196 let data_end = data_start + len;
197 if bytes.len() < data_end {
198 return Err(Error::BufferTooShort {
199 need: data_end,
200 have: bytes.len(),
201 what: "RFC 8285 one-byte extension element data",
202 });
203 }
204 let id = OneByteId(id_nibble);
208 elements.push(OneByteElement {
209 id,
210 data: &bytes[data_start..data_end],
211 });
212 pos = data_end;
213 }
214 Ok(Self(elements))
215 }
216}
217
218impl Serialize for OneByteElements<'_> {
219 type Error = Error;
220
221 fn serialized_len(&self) -> usize {
222 let raw: usize = self.0.iter().map(|e| 1 + e.data.len()).sum();
223 raw.div_ceil(EXT_ALIGN) * EXT_ALIGN
224 }
225
226 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
227 let len = self.serialized_len();
228 if buf.len() < len {
229 return Err(Error::BufferTooShort {
230 need: len,
231 have: buf.len(),
232 what: "RFC 8285 one-byte extension elements serialize output",
233 });
234 }
235 let mut pos = 0;
236 for e in &self.0 {
237 if !(ONE_BYTE_DATA_MIN..=ONE_BYTE_DATA_MAX).contains(&e.data.len()) {
238 return Err(Error::InvalidValue {
239 field: "OneByteElement::data.len()",
240 value: e.data.len() as u64,
241 reason: "must be 1..=16 bytes (RFC 8285 §4.2: len nibble = data.len() - 1)",
242 });
243 }
244 let len_nibble = (e.data.len() - 1) as u8;
245 buf[pos] = (e.id.get() << 4) | len_nibble;
246 pos += 1;
247 buf[pos..pos + e.data.len()].copy_from_slice(e.data);
248 pos += e.data.len();
249 }
250 for b in &mut buf[pos..len] {
251 *b = PADDING_BYTE;
252 }
253 Ok(len)
254 }
255}
256
257#[derive(Debug, Clone, Copy, PartialEq, Eq)]
265#[cfg_attr(feature = "serde", derive(serde::Serialize))]
266pub struct TwoByteElement<'a> {
267 pub id: TwoByteId,
269 pub data: &'a [u8],
272}
273
274#[derive(Debug, Clone, PartialEq, Eq, Default)]
278#[cfg_attr(feature = "serde", derive(serde::Serialize))]
279pub struct TwoByteElements<'a>(pub Vec<TwoByteElement<'a>>);
280
281impl<'a> TwoByteElements<'a> {
282 #[must_use]
284 pub fn elements(&self) -> &[TwoByteElement<'a>] {
285 &self.0
286 }
287}
288
289impl<'a> IntoIterator for TwoByteElements<'a> {
290 type Item = TwoByteElement<'a>;
291 type IntoIter = alloc::vec::IntoIter<TwoByteElement<'a>>;
292
293 fn into_iter(self) -> Self::IntoIter {
294 self.0.into_iter()
295 }
296}
297
298impl<'a> Parse<'a> for TwoByteElements<'a> {
299 type Error = Error;
300
301 fn parse(bytes: &'a [u8]) -> Result<Self> {
302 let mut elements = Vec::new();
303 let mut pos = 0;
304 while pos < bytes.len() {
305 let id_byte = bytes[pos];
306 if id_byte == PADDING_BYTE {
307 pos += 1;
311 continue;
312 }
313 let len_pos = pos + 1;
314 if bytes.len() <= len_pos {
315 return Err(Error::BufferTooShort {
316 need: len_pos + 1,
317 have: bytes.len(),
318 what: "RFC 8285 two-byte extension element length byte",
319 });
320 }
321 let len = usize::from(bytes[len_pos]);
322 let data_start = len_pos + 1;
323 let data_end = data_start + len;
324 if bytes.len() < data_end {
325 return Err(Error::BufferTooShort {
326 need: data_end,
327 have: bytes.len(),
328 what: "RFC 8285 two-byte extension element data",
329 });
330 }
331 let id = TwoByteId(id_byte);
335 elements.push(TwoByteElement {
336 id,
337 data: &bytes[data_start..data_end],
338 });
339 pos = data_end;
340 }
341 Ok(Self(elements))
342 }
343}
344
345impl Serialize for TwoByteElements<'_> {
346 type Error = Error;
347
348 fn serialized_len(&self) -> usize {
349 let raw: usize = self.0.iter().map(|e| 2 + e.data.len()).sum();
350 raw.div_ceil(EXT_ALIGN) * EXT_ALIGN
351 }
352
353 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
354 let len = self.serialized_len();
355 if buf.len() < len {
356 return Err(Error::BufferTooShort {
357 need: len,
358 have: buf.len(),
359 what: "RFC 8285 two-byte extension elements serialize output",
360 });
361 }
362 let mut pos = 0;
363 for e in &self.0 {
364 if e.data.len() > TWO_BYTE_DATA_MAX {
365 return Err(Error::InvalidValue {
366 field: "TwoByteElement::data.len()",
367 value: e.data.len() as u64,
368 reason: "exceeds the 8-bit length field maximum (255)",
369 });
370 }
371 buf[pos] = e.id.get();
372 buf[pos + 1] = e.data.len() as u8;
373 pos += 2;
374 buf[pos..pos + e.data.len()].copy_from_slice(e.data);
375 pos += e.data.len();
376 }
377 for b in &mut buf[pos..len] {
378 *b = PADDING_BYTE;
379 }
380 Ok(len)
381 }
382}
383
384#[derive(Debug, Clone, PartialEq, Eq)]
394#[cfg_attr(feature = "serde", derive(serde::Serialize))]
395#[non_exhaustive]
396pub enum ExtensionElements<'a> {
397 OneByte(OneByteElements<'a>),
399 TwoByte(TwoByteElements<'a>),
401}
402
403impl Serialize for ExtensionElements<'_> {
404 type Error = Error;
405
406 fn serialized_len(&self) -> usize {
407 match self {
408 Self::OneByte(e) => e.serialized_len(),
409 Self::TwoByte(e) => e.serialized_len(),
410 }
411 }
412
413 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
414 match self {
415 Self::OneByte(e) => e.serialize_into(buf),
416 Self::TwoByte(e) => e.serialize_into(buf),
417 }
418 }
419}
420
421pub fn parse_extensions<'a>(ext: &HeaderExtension<'a>) -> Result<ExtensionElements<'a>> {
430 if ext.profile_id == ONE_BYTE_PROFILE_ID {
431 Ok(ExtensionElements::OneByte(OneByteElements::parse(
432 ext.data,
433 )?))
434 } else if ext.profile_id & TWO_BYTE_PROFILE_ID_MASK == TWO_BYTE_PROFILE_ID_PREFIX {
435 Ok(ExtensionElements::TwoByte(TwoByteElements::parse(
436 ext.data,
437 )?))
438 } else {
439 Err(Error::NotRfc8285Extension {
440 profile_id: ext.profile_id,
441 })
442 }
443}
444
445#[cfg(test)]
446mod tests {
447 use super::*;
448 use alloc::vec;
449
450 #[test]
453 fn one_byte_id_rejects_padding_and_stop() {
454 assert!(matches!(
455 OneByteId::new(0),
456 Err(Error::InvalidOneByteExtensionId(0))
457 ));
458 assert!(matches!(
459 OneByteId::new(15),
460 Err(Error::InvalidOneByteExtensionId(15))
461 ));
462 assert!(OneByteId::new(1).is_ok());
463 assert!(OneByteId::new(14).is_ok());
464 }
465
466 #[test]
467 fn two_byte_id_rejects_zero() {
468 assert!(matches!(
469 TwoByteId::new(0),
470 Err(Error::InvalidTwoByteExtensionId)
471 ));
472 assert!(TwoByteId::new(1).is_ok());
473 assert!(TwoByteId::new(255).is_ok());
474 }
475
476 #[test]
479 fn one_byte_round_trip_single_element() {
480 let elements = OneByteElements(vec![OneByteElement {
481 id: OneByteId::new(3).unwrap(),
482 data: &[0xAA, 0xBB],
483 }]);
484 let mut out = vec![0u8; elements.serialized_len()];
485 elements.serialize_into(&mut out).unwrap();
486 assert_eq!(out[0], (3 << 4) | 1);
488 assert_eq!(&out[1..3], &[0xAA, 0xBB]);
489 assert_eq!(out.len(), 4);
491 assert_eq!(out[3], 0x00);
492 let reparsed = OneByteElements::parse(&out).unwrap();
493 assert_eq!(reparsed, elements);
494 }
495
496 #[test]
497 fn one_byte_spec_worked_example_structure() {
498 let elements = OneByteElements(vec![
508 OneByteElement {
509 id: OneByteId::new(1).unwrap(),
510 data: &[0x11],
511 },
512 OneByteElement {
513 id: OneByteId::new(2).unwrap(),
514 data: &[0x22, 0x33],
515 },
516 OneByteElement {
517 id: OneByteId::new(3).unwrap(),
518 data: &[0x44, 0x55, 0x66, 0x77],
519 },
520 ]);
521 let mut out = vec![0u8; elements.serialized_len()];
522 elements.serialize_into(&mut out).unwrap();
523 let expected = [
524 1 << 4, 0x11,
526 (2 << 4) | 1, 0x22,
528 0x33,
529 (3 << 4) | 3, 0x44,
531 0x55,
532 0x66,
533 0x77,
534 0x00,
535 0x00, ];
537 assert_eq!(out, expected);
538 assert_eq!(
539 out.len(),
540 12,
541 "3 words, matching length=3 in the RFC diagram"
542 );
543 let reparsed = OneByteElements::parse(&out).unwrap();
544 assert_eq!(reparsed, elements);
545 }
546
547 #[test]
548 fn one_byte_reparses_interspersed_padding_to_the_same_elements() {
549 #[rustfmt::skip]
556 let interspersed: [u8; 12] = [
557 1 << 4, 0x11,
558 (2 << 4) | 1, 0x22, 0x33,
559 0x00, 0x00, (3 << 4) | 3, 0x44, 0x55, 0x66, 0x77,
561 ];
562 let parsed = OneByteElements::parse(&interspersed).unwrap();
563 let expected_elements = OneByteElements(vec![
564 OneByteElement {
565 id: OneByteId::new(1).unwrap(),
566 data: &[0x11],
567 },
568 OneByteElement {
569 id: OneByteId::new(2).unwrap(),
570 data: &[0x22, 0x33],
571 },
572 OneByteElement {
573 id: OneByteId::new(3).unwrap(),
574 data: &[0x44, 0x55, 0x66, 0x77],
575 },
576 ]);
577 assert_eq!(parsed, expected_elements, "decoded elements are identical");
578
579 let mut out = vec![0u8; parsed.serialized_len()];
583 parsed.serialize_into(&mut out).unwrap();
584 assert_ne!(
585 out, interspersed,
586 "padding position is canonicalized, not preserved verbatim"
587 );
588 assert_eq!(OneByteElements::parse(&out).unwrap(), expected_elements);
589 }
590
591 #[test]
592 fn one_byte_stop_marker_halts_parsing() {
593 let bytes = [1 << 4, 0xAA, (15 << 4) | 5, 0xFF];
597 let parsed = OneByteElements::parse(&bytes).unwrap();
598 assert_eq!(parsed.elements().len(), 1);
599 assert_eq!(parsed.elements()[0].id.get(), 1);
600 assert_eq!(parsed.elements()[0].data, &[0xAA]);
601 }
602
603 #[test]
604 fn one_byte_malformed_id_zero_with_length_halts_parsing() {
605 let bytes = [1 << 4, 0xAA, 0x05, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
610 let parsed = OneByteElements::parse(&bytes).unwrap();
611 assert_eq!(parsed.elements().len(), 1);
612 assert_eq!(parsed.elements()[0].data, &[0xAA]);
613 }
614
615 #[test]
616 fn one_byte_pure_padding_byte_is_skipped_not_terminal() {
617 let bytes = [
620 1 << 4,
621 0xAA,
622 0x00, 2 << 4,
624 0xBB,
625 ];
626 let parsed = OneByteElements::parse(&bytes).unwrap();
627 assert_eq!(parsed.elements().len(), 2);
628 assert_eq!(parsed.elements()[1].id.get(), 2);
629 assert_eq!(parsed.elements()[1].data, &[0xBB]);
630 }
631
632 #[test]
633 fn one_byte_rejects_data_len_out_of_range() {
634 let elements = OneByteElements(vec![OneByteElement {
635 id: OneByteId::new(1).unwrap(),
636 data: &[],
637 }]);
638 let mut out = vec![0u8; 4];
639 assert!(matches!(
640 elements.serialize_into(&mut out),
641 Err(Error::InvalidValue {
642 field: "OneByteElement::data.len()",
643 ..
644 })
645 ));
646 }
647
648 #[test]
649 fn one_byte_truncated_element_data_is_buffer_too_short() {
650 let bytes = [(1 << 4) | 3, 0xAA, 0xBB];
652 assert!(matches!(
653 OneByteElements::parse(&bytes),
654 Err(Error::BufferTooShort { .. })
655 ));
656 }
657
658 #[test]
659 fn one_byte_empty_is_valid() {
660 let elements = OneByteElements::default();
661 assert_eq!(elements.serialized_len(), 0);
662 let mut out: [u8; 0] = [];
663 elements.serialize_into(&mut out).unwrap();
664 let reparsed = OneByteElements::parse(&[]).unwrap();
665 assert_eq!(reparsed, elements);
666 }
667
668 #[test]
671 fn two_byte_round_trip_single_element() {
672 let elements = TwoByteElements(vec![TwoByteElement {
673 id: TwoByteId::new(200).unwrap(),
674 data: &[0x01, 0x02, 0x03],
675 }]);
676 let mut out = vec![0u8; elements.serialized_len()];
677 elements.serialize_into(&mut out).unwrap();
678 assert_eq!(out[0], 200);
679 assert_eq!(out[1], 3);
680 assert_eq!(&out[2..5], &[0x01, 0x02, 0x03]);
681 assert_eq!(out.len(), 8, "5 bytes of content padded to 8");
682 let reparsed = TwoByteElements::parse(&out).unwrap();
683 assert_eq!(reparsed, elements);
684 }
685
686 #[test]
687 fn two_byte_spec_worked_example_structure() {
688 let elements = TwoByteElements(vec![
693 TwoByteElement {
694 id: TwoByteId::new(10).unwrap(),
695 data: &[],
696 },
697 TwoByteElement {
698 id: TwoByteId::new(20).unwrap(),
699 data: &[0x99],
700 },
701 TwoByteElement {
702 id: TwoByteId::new(30).unwrap(),
703 data: &[0x01, 0x02, 0x03, 0x04],
704 },
705 ]);
706 let mut out = vec![0u8; elements.serialized_len()];
707 elements.serialize_into(&mut out).unwrap();
708 let expected = [
709 10, 0, 20, 1, 0x99, 30, 4, 0x01, 0x02, 0x03, 0x04, 0x00, ];
714 assert_eq!(out, expected);
715 assert_eq!(
716 out.len(),
717 12,
718 "3 words, matching length=3 in the RFC diagram"
719 );
720 let reparsed = TwoByteElements::parse(&out).unwrap();
721 assert_eq!(reparsed, elements);
722 }
723
724 #[test]
725 fn two_byte_reparses_interspersed_padding_to_the_same_elements() {
726 #[rustfmt::skip]
732 let interspersed: [u8; 12] = [
733 10, 0,
734 20, 1, 0x99,
735 0x00, 30, 4, 0x01, 0x02, 0x03, 0x04,
737 ];
738 let parsed = TwoByteElements::parse(&interspersed).unwrap();
739 let expected_elements = TwoByteElements(vec![
740 TwoByteElement {
741 id: TwoByteId::new(10).unwrap(),
742 data: &[],
743 },
744 TwoByteElement {
745 id: TwoByteId::new(20).unwrap(),
746 data: &[0x99],
747 },
748 TwoByteElement {
749 id: TwoByteId::new(30).unwrap(),
750 data: &[0x01, 0x02, 0x03, 0x04],
751 },
752 ]);
753 assert_eq!(parsed, expected_elements, "decoded elements are identical");
754
755 let mut out = vec![0u8; parsed.serialized_len()];
756 parsed.serialize_into(&mut out).unwrap();
757 assert_ne!(
758 out, interspersed,
759 "padding position is canonicalized, not preserved verbatim"
760 );
761 assert_eq!(TwoByteElements::parse(&out).unwrap(), expected_elements);
762 }
763
764 #[test]
765 fn two_byte_zero_id_byte_is_padding_not_an_element() {
766 let bytes = [10u8, 0, 0x00, 20, 1, 0x77];
770 let parsed = TwoByteElements::parse(&bytes).unwrap();
771 assert_eq!(parsed.elements().len(), 2);
772 assert_eq!(parsed.elements()[0].id.get(), 10);
773 assert_eq!(parsed.elements()[0].data, &[] as &[u8]);
774 assert_eq!(parsed.elements()[1].id.get(), 20);
775 assert_eq!(parsed.elements()[1].data, &[0x77]);
776 }
777
778 #[test]
779 fn two_byte_truncated_length_byte_is_buffer_too_short() {
780 let bytes = [10u8]; assert!(matches!(
782 TwoByteElements::parse(&bytes),
783 Err(Error::BufferTooShort { .. })
784 ));
785 }
786
787 #[test]
788 fn two_byte_truncated_element_data_is_buffer_too_short() {
789 let bytes = [10u8, 4, 0x01, 0x02]; assert!(matches!(
791 TwoByteElements::parse(&bytes),
792 Err(Error::BufferTooShort { .. })
793 ));
794 }
795
796 #[test]
797 fn two_byte_empty_is_valid() {
798 let elements = TwoByteElements::default();
799 assert_eq!(elements.serialized_len(), 0);
800 let reparsed = TwoByteElements::parse(&[]).unwrap();
801 assert_eq!(reparsed, elements);
802 }
803
804 #[test]
807 fn parse_extensions_dispatches_one_byte() {
808 let data = [1 << 4, 0xAA, 0x00, 0x00];
809 let ext = HeaderExtension {
810 profile_id: ONE_BYTE_PROFILE_ID,
811 data: &data,
812 };
813 let parsed = parse_extensions(&ext).unwrap();
814 assert!(matches!(parsed, ExtensionElements::OneByte(_)));
815 }
816
817 #[test]
818 fn parse_extensions_dispatches_two_byte() {
819 let data = [10u8, 1, 0xAA, 0x00];
820 let ext = HeaderExtension {
821 profile_id: 0x1005, data: &data,
823 };
824 let parsed = parse_extensions(&ext).unwrap();
825 assert!(matches!(parsed, ExtensionElements::TwoByte(_)));
826 }
827
828 #[test]
829 fn parse_extensions_rejects_unknown_profile() {
830 let data: [u8; 0] = [];
831 let ext = HeaderExtension {
832 profile_id: 0x1234,
833 data: &data,
834 };
835 assert!(matches!(
836 parse_extensions(&ext),
837 Err(Error::NotRfc8285Extension { profile_id: 0x1234 })
838 ));
839 }
840
841 #[test]
842 fn extension_elements_serialize_round_trip_via_dispatch() {
843 let data = [(5 << 4) | 1, 0x01, 0x02, 0x00];
844 let ext = HeaderExtension {
845 profile_id: ONE_BYTE_PROFILE_ID,
846 data: &data,
847 };
848 let elements = parse_extensions(&ext).unwrap();
849 let mut out = vec![0u8; elements.serialized_len()];
850 elements.serialize_into(&mut out).unwrap();
851 assert_eq!(out, data);
852 }
853}