1extern crate alloc;
27use alloc::vec::Vec;
28
29use crate::buffer::{BufferReader, BufferWriter};
30use crate::error::{DecodeError, EncodeError};
31
32pub fn encode_appendable<F>(writer: &mut BufferWriter, body: F) -> Result<(), EncodeError>
43where
44 F: FnOnce(&mut BufferWriter) -> Result<(), EncodeError>,
45{
46 let mut inner = BufferWriter::new(writer.endianness());
47 body(&mut inner)?;
48 let bytes = inner.into_bytes();
49 let len = u32::try_from(bytes.len()).map_err(|_| EncodeError::ValueOutOfRange {
50 message: "appendable struct body exceeds u32::MAX",
51 })?;
52 writer.write_u32(len)?;
53 writer.write_bytes(&bytes)?;
54 Ok(())
55}
56
57pub fn decode_appendable<T, F>(reader: &mut BufferReader<'_>, body: F) -> Result<T, DecodeError>
66where
67 F: FnOnce(&mut BufferReader<'_>) -> Result<T, DecodeError>,
68{
69 let len = reader.read_u32()? as usize;
70 if len > reader.remaining() {
71 return Err(DecodeError::LengthExceeded {
72 announced: len,
73 remaining: reader.remaining(),
74 offset: reader.position(),
75 });
76 }
77 let body_bytes = reader.read_bytes(len)?;
78 let mut sub = BufferReader::new(body_bytes, reader.endianness());
79 body(&mut sub)
80}
81
82#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
88#[repr(u8)]
89pub enum LengthCode {
90 Lc0 = 0,
92 Lc1 = 1,
94 Lc2 = 2,
96 Lc3 = 3,
98 Lc4 = 4,
100 Lc5 = 5,
102 Lc6 = 6,
104 Lc7 = 7,
106}
107
108impl LengthCode {
109 #[must_use]
111 pub fn body_len(self, nextint: u32) -> u64 {
112 match self {
113 Self::Lc0 => 1,
114 Self::Lc1 => 2,
115 Self::Lc2 => 4,
116 Self::Lc3 => 8,
117 Self::Lc4 | Self::Lc5 => u64::from(nextint),
118 Self::Lc6 => 4 * u64::from(nextint) + 4,
119 Self::Lc7 => 8 * u64::from(nextint) + 4,
120 }
121 }
122
123 #[must_use]
125 pub const fn has_nextint(self) -> bool {
126 matches!(self, Self::Lc4 | Self::Lc5 | Self::Lc6 | Self::Lc7)
127 }
128
129 #[must_use]
131 pub const fn from_wire(value: u8) -> Option<Self> {
132 match value {
133 0 => Some(Self::Lc0),
134 1 => Some(Self::Lc1),
135 2 => Some(Self::Lc2),
136 3 => Some(Self::Lc3),
137 4 => Some(Self::Lc4),
138 5 => Some(Self::Lc5),
139 6 => Some(Self::Lc6),
140 7 => Some(Self::Lc7),
141 _ => None,
142 }
143 }
144}
145
146pub fn encode_mutable_member<F>(
151 writer: &mut BufferWriter,
152 member_id: u32,
153 must_understand: bool,
154 body: F,
155) -> Result<(), EncodeError>
156where
157 F: FnOnce(&mut BufferWriter) -> Result<(), EncodeError>,
158{
159 encode_mutable_member_lc(writer, member_id, must_understand, LengthCode::Lc4, body)
160}
161
162pub fn encode_mutable_member_lc<F>(
168 writer: &mut BufferWriter,
169 member_id: u32,
170 must_understand: bool,
171 lc: LengthCode,
172 body: F,
173) -> Result<(), EncodeError>
174where
175 F: FnOnce(&mut BufferWriter) -> Result<(), EncodeError>,
176{
177 if member_id > 0x0FFF_FFFF {
178 return Err(EncodeError::ValueOutOfRange {
179 message: "EMHEADER member_id exceeds 28-bit field",
180 });
181 }
182 let mut inner = BufferWriter::new(writer.endianness());
183 body(&mut inner)?;
184 let body_bytes = inner.into_bytes();
185 let body_len = body_bytes.len();
186
187 let nextint: Option<u32> = match lc {
188 LengthCode::Lc0 => {
189 if body_len != 1 {
190 return Err(EncodeError::ValueOutOfRange {
191 message: "LC0 requires exactly 1 byte body",
192 });
193 }
194 None
195 }
196 LengthCode::Lc1 => {
197 if body_len != 2 {
198 return Err(EncodeError::ValueOutOfRange {
199 message: "LC1 requires exactly 2 bytes body",
200 });
201 }
202 None
203 }
204 LengthCode::Lc2 => {
205 if body_len != 4 {
206 return Err(EncodeError::ValueOutOfRange {
207 message: "LC2 requires exactly 4 bytes body",
208 });
209 }
210 None
211 }
212 LengthCode::Lc3 => {
213 if body_len != 8 {
214 return Err(EncodeError::ValueOutOfRange {
215 message: "LC3 requires exactly 8 bytes body",
216 });
217 }
218 None
219 }
220 LengthCode::Lc4 | LengthCode::Lc5 => {
221 let n = u32::try_from(body_len).map_err(|_| EncodeError::ValueOutOfRange {
222 message: "LC4/LC5 body exceeds u32::MAX",
223 })?;
224 Some(n)
225 }
226 LengthCode::Lc6 => {
227 if body_len < 4 || body_len % 4 != 0 {
231 return Err(EncodeError::ValueOutOfRange {
232 message: "LC6 body must be DHEADER + 4n bytes",
233 });
234 }
235 let n =
236 u32::try_from((body_len - 4) / 4).map_err(|_| EncodeError::ValueOutOfRange {
237 message: "LC6 element count exceeds u32::MAX",
238 })?;
239 Some(n)
240 }
241 LengthCode::Lc7 => {
242 if body_len < 4 || body_len % 8 != 4 {
249 return Err(EncodeError::ValueOutOfRange {
250 message: "LC7 body must be DHEADER + 8n bytes",
251 });
252 }
253 let n =
254 u32::try_from((body_len - 4) / 8).map_err(|_| EncodeError::ValueOutOfRange {
255 message: "LC7 element count exceeds u32::MAX",
256 })?;
257 Some(n)
258 }
259 };
260
261 let m_bit = u32::from(must_understand) << 31;
262 let lc_bits = (lc as u32) << 28;
263 let emheader = m_bit + lc_bits + member_id;
269 writer.write_u32(emheader)?;
270 if let Some(ni) = nextint {
271 writer.write_u32(ni)?;
272 }
273 writer.write_bytes(&body_bytes)?;
274 Ok(())
275}
276
277pub struct MutableStructEncoder<'a> {
290 writer: &'a mut BufferWriter,
291 required_ids: Vec<u32>,
292 emitted_ids: Vec<u32>,
293}
294
295impl<'a> MutableStructEncoder<'a> {
296 pub fn new(writer: &'a mut BufferWriter, required_ids: Vec<u32>) -> Self {
300 Self {
301 writer,
302 required_ids,
303 emitted_ids: Vec::new(),
304 }
305 }
306
307 pub fn encode_member<F>(
313 &mut self,
314 member_id: u32,
315 must_understand: bool,
316 body: F,
317 ) -> Result<(), EncodeError>
318 where
319 F: FnOnce(&mut BufferWriter) -> Result<(), EncodeError>,
320 {
321 encode_mutable_member(self.writer, member_id, must_understand, body)?;
322 self.emitted_ids.push(member_id);
323 Ok(())
324 }
325
326 pub fn encode_member_lc<F>(
331 &mut self,
332 member_id: u32,
333 must_understand: bool,
334 lc: LengthCode,
335 body: F,
336 ) -> Result<(), EncodeError>
337 where
338 F: FnOnce(&mut BufferWriter) -> Result<(), EncodeError>,
339 {
340 encode_mutable_member_lc(self.writer, member_id, must_understand, lc, body)?;
341 self.emitted_ids.push(member_id);
342 Ok(())
343 }
344
345 pub fn finish(self) -> Result<(), EncodeError> {
353 for required in &self.required_ids {
354 if !self.emitted_ids.contains(required) {
355 return Err(EncodeError::MissingNonOptionalMember {
356 member_id: *required,
357 });
358 }
359 }
360 Ok(())
361 }
362}
363
364#[derive(Debug, Clone)]
366pub struct MutableMember<'a> {
367 pub member_id: u32,
369 pub must_understand: bool,
371 pub length_code: LengthCode,
373 pub body: &'a [u8],
375}
376
377pub fn read_mutable_member<'a>(
382 reader: &mut BufferReader<'a>,
383) -> Result<Option<MutableMember<'a>>, DecodeError> {
384 if reader.remaining() == 0 {
385 return Ok(None);
386 }
387 let emheader = reader.read_u32()?;
388 let must_understand = (emheader >> 31) & 1 == 1;
389 let lc_raw = ((emheader >> 28) & 0b0111) as u8;
390 let member_id = emheader & 0x0FFF_FFFF;
391 let length_code = LengthCode::from_wire(lc_raw).ok_or_else(|| DecodeError::LengthExceeded {
392 announced: usize::from(lc_raw),
393 remaining: 0,
394 offset: reader.position(),
395 })?;
396
397 let nextint = if length_code.has_nextint() {
398 reader.read_u32()?
399 } else {
400 0
401 };
402
403 let body_len_u64 = length_code.body_len(nextint);
404 let body_len = usize::try_from(body_len_u64).map_err(|_| DecodeError::LengthExceeded {
405 announced: usize::MAX,
406 remaining: reader.remaining(),
407 offset: reader.position(),
408 })?;
409 if body_len > reader.remaining() {
410 return Err(DecodeError::LengthExceeded {
411 announced: body_len,
412 remaining: reader.remaining(),
413 offset: reader.position(),
414 });
415 }
416 let body = reader.read_bytes(body_len)?;
417 Ok(Some(MutableMember {
418 member_id,
419 must_understand,
420 length_code,
421 body,
422 }))
423}
424
425pub fn read_all_mutable_members<'a>(
431 reader: &mut BufferReader<'a>,
432) -> Result<Vec<MutableMember<'a>>, DecodeError> {
433 let mut out = Vec::new();
434 while let Some(m) = read_mutable_member(reader)? {
435 out.push(m);
436 }
437 Ok(out)
438}
439
440pub fn encode_final<F>(writer: &mut BufferWriter, body: F) -> Result<(), EncodeError>
451where
452 F: FnOnce(&mut BufferWriter) -> Result<(), EncodeError>,
453{
454 body(writer)
455}
456
457pub fn decode_final<T, F>(reader: &mut BufferReader<'_>, body: F) -> Result<T, DecodeError>
462where
463 F: FnOnce(&mut BufferReader<'_>) -> Result<T, DecodeError>,
464{
465 body(reader)
466}
467
468#[cfg(test)]
469mod tests {
470 #![allow(clippy::expect_used, clippy::panic, clippy::unwrap_used)]
471 use super::*;
472 use crate::Endianness;
473 use crate::encode::{CdrDecode, CdrEncode};
474 use alloc::vec;
475
476 #[test]
479 fn final_struct_two_u32_members() {
480 let mut w = BufferWriter::new(Endianness::Little);
481 encode_final(&mut w, |w| {
482 42u32.encode(w)?;
483 100u32.encode(w)?;
484 Ok(())
485 })
486 .unwrap();
487 let bytes = w.into_bytes();
488 assert_eq!(bytes.len(), 8);
490
491 let mut r = BufferReader::new(&bytes, Endianness::Little);
492 let (a, b) = decode_final(&mut r, |r| {
493 Ok::<_, DecodeError>((u32::decode(r)?, u32::decode(r)?))
494 })
495 .unwrap();
496 assert_eq!((a, b), (42, 100));
497 }
498
499 #[test]
502 fn appendable_struct_writes_dheader() {
503 let mut w = BufferWriter::new(Endianness::Little);
504 encode_appendable(&mut w, |w| {
505 42u32.encode(w)?;
506 7u8.encode(w)?;
507 Ok(())
508 })
509 .unwrap();
510 let bytes = w.into_bytes();
511 assert_eq!(&bytes[0..4], &[5, 0, 0, 0]); assert_eq!(&bytes[4..8], &[42, 0, 0, 0]); assert_eq!(bytes[8], 7);
516 assert_eq!(bytes.len(), 9);
517 }
518
519 #[test]
520 fn appendable_struct_roundtrip() {
521 let mut w = BufferWriter::new(Endianness::Little);
522 encode_appendable(&mut w, |w| {
523 42u32.encode(w)?;
524 7u8.encode(w)?;
525 Ok(())
526 })
527 .unwrap();
528 let bytes = w.into_bytes();
529
530 let mut r = BufferReader::new(&bytes, Endianness::Little);
531 let (a, b) = decode_appendable(&mut r, |r| {
532 Ok::<_, DecodeError>((u32::decode(r)?, u8::decode(r)?))
533 })
534 .unwrap();
535 assert_eq!((a, b), (42, 7));
536 }
537
538 #[test]
539 fn appendable_decoder_skips_extra_trailing_bytes() {
540 let mut w = BufferWriter::new(Endianness::Little);
544 encode_appendable(&mut w, |w| {
545 42u32.encode(w)?;
546 99u8.encode(w)?;
547 Ok(())
548 })
549 .unwrap();
550 let bytes = w.into_bytes();
551
552 let mut r = BufferReader::new(&bytes, Endianness::Little);
553 let only_first = decode_appendable(&mut r, u32::decode).unwrap();
554 assert_eq!(only_first, 42);
555 assert_eq!(r.remaining(), 0);
557 }
558
559 #[test]
560 fn appendable_decoder_rejects_announced_overrun() {
561 let bytes = [0xFFu8, 0xFF, 0xFF, 0xFF, 1, 2, 3];
562 let mut r = BufferReader::new(&bytes, Endianness::Little);
563 let res = decode_appendable(&mut r, u32::decode);
564 assert!(matches!(res, Err(DecodeError::LengthExceeded { .. })));
565 }
566
567 #[test]
572 fn mutable_struct_encoder_succeeds_when_all_required_emitted() {
573 let mut w = BufferWriter::new(Endianness::Little);
574 let mut enc = MutableStructEncoder::new(&mut w, vec![1, 2, 3]);
575 enc.encode_member(1, false, |w| 42u32.encode(w)).unwrap();
576 enc.encode_member(2, false, |w| 7u8.encode(w)).unwrap();
577 enc.encode_member(3, false, |w| 99u16.encode(w)).unwrap();
578 enc.finish().unwrap();
579 }
580
581 #[test]
582 fn mutable_encode_omitting_non_optional_member_errors() {
583 let mut w = BufferWriter::new(Endianness::Little);
584 let mut enc = MutableStructEncoder::new(&mut w, vec![1, 2, 3]);
585 enc.encode_member(1, false, |w| 42u32.encode(w)).unwrap();
586 enc.encode_member(3, false, |w| 99u16.encode(w)).unwrap();
588 let err = enc.finish().unwrap_err();
589 assert_eq!(err, EncodeError::MissingNonOptionalMember { member_id: 2 });
590 }
591
592 #[test]
593 fn mutable_encode_first_missing_id_is_reported() {
594 let mut w = BufferWriter::new(Endianness::Little);
595 let mut enc = MutableStructEncoder::new(&mut w, vec![10, 20, 30]);
596 enc.encode_member(20, false, |w| 5u32.encode(w)).unwrap();
597 let err = enc.finish().unwrap_err();
599 assert_eq!(err, EncodeError::MissingNonOptionalMember { member_id: 10 });
600 }
601
602 #[test]
603 fn mutable_encode_optional_only_with_no_required_succeeds() {
604 let mut w = BufferWriter::new(Endianness::Little);
607 let enc = MutableStructEncoder::new(&mut w, vec![]);
608 enc.finish().unwrap();
609 }
610
611 #[test]
612 fn mutable_encode_extra_optional_emitted_does_not_break_finish() {
613 let mut w = BufferWriter::new(Endianness::Little);
615 let mut enc = MutableStructEncoder::new(&mut w, vec![1]);
616 enc.encode_member(1, false, |w| 42u32.encode(w)).unwrap();
617 enc.encode_member(99, false, |w| 0u8.encode(w)).unwrap();
618 enc.finish().unwrap();
619 }
620
621 #[test]
622 fn mutable_encode_with_lc_variant_tracks_id() {
623 let mut w = BufferWriter::new(Endianness::Little);
624 let mut enc = MutableStructEncoder::new(&mut w, vec![5]);
625 enc.encode_member_lc(5, false, LengthCode::Lc0, |w| 0x42u8.encode(w))
626 .unwrap();
627 enc.finish().unwrap();
628 }
629
630 #[test]
631 fn mutable_member_emheader_layout() {
632 let mut w = BufferWriter::new(Endianness::Little);
633 encode_mutable_member(&mut w, 0x1234, false, |w| 42u32.encode(w)).unwrap();
634 let bytes = w.into_bytes();
635 assert_eq!(&bytes[0..4], &[0x34, 0x12, 0x00, 0x40]);
638 assert_eq!(&bytes[4..8], &[4, 0, 0, 0]);
640 assert_eq!(&bytes[8..12], &[42, 0, 0, 0]);
642 }
643
644 #[test]
645 fn mutable_member_must_understand_sets_high_bit() {
646 let mut w = BufferWriter::new(Endianness::Little);
647 encode_mutable_member(&mut w, 1, true, |w| 0u8.encode(w)).unwrap();
648 let bytes = w.into_bytes();
649 assert_eq!(&bytes[0..4], &[0x01, 0x00, 0x00, 0xC0]);
651 }
652
653 #[test]
654 fn mutable_member_rejects_oversized_id() {
655 let mut w = BufferWriter::new(Endianness::Little);
656 let res = encode_mutable_member(&mut w, 0xFFFF_FFFF, false, |w| 0u8.encode(w));
657 assert!(matches!(res, Err(EncodeError::ValueOutOfRange { .. })));
658 }
659
660 #[test]
661 fn mutable_struct_roundtrip_two_members() {
662 let mut w = BufferWriter::new(Endianness::Little);
663 encode_mutable_member(&mut w, 1, false, |w| 42u32.encode(w)).unwrap();
664 encode_mutable_member(&mut w, 2, true, |w| 7u8.encode(w)).unwrap();
665 let bytes = w.into_bytes();
666
667 let mut r = BufferReader::new(&bytes, Endianness::Little);
668 let members = read_all_mutable_members(&mut r).unwrap();
669 assert_eq!(members.len(), 2);
670 assert_eq!(members[0].member_id, 1);
671 assert!(!members[0].must_understand);
672 assert_eq!(members[1].member_id, 2);
673 assert!(members[1].must_understand);
674
675 let mut sub = BufferReader::new(members[0].body, Endianness::Little);
676 assert_eq!(u32::decode(&mut sub).unwrap(), 42);
677 let mut sub = BufferReader::new(members[1].body, Endianness::Little);
678 assert_eq!(u8::decode(&mut sub).unwrap(), 7);
679 }
680
681 #[test]
682 fn mutable_member_reads_none_on_eof() {
683 let bytes: [u8; 0] = [];
684 let mut r = BufferReader::new(&bytes, Endianness::Little);
685 let res = read_mutable_member(&mut r).unwrap();
686 assert!(res.is_none());
687 }
688
689 #[test]
692 fn lc0_encode_decode_one_byte_body() {
693 let mut w = BufferWriter::new(Endianness::Little);
694 encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc0, |w| 0x42u8.encode(w)).unwrap();
695 let bytes = w.into_bytes();
696 assert_eq!(&bytes[0..4], &[0x01, 0x00, 0x00, 0x00]);
697 assert_eq!(bytes[4], 0x42);
698 assert_eq!(bytes.len(), 5);
699 let mut r = BufferReader::new(&bytes, Endianness::Little);
700 let m = read_mutable_member(&mut r).unwrap().unwrap();
701 assert_eq!(m.length_code, LengthCode::Lc0);
702 assert_eq!(m.body, &[0x42]);
703 }
704
705 #[test]
706 fn lc1_encode_decode_two_byte_body() {
707 let mut w = BufferWriter::new(Endianness::Little);
708 encode_mutable_member_lc(&mut w, 7, false, LengthCode::Lc1, |w| 0x1234u16.encode(w))
709 .unwrap();
710 let bytes = w.into_bytes();
711 assert_eq!(bytes.len(), 4 + 2);
712 let mut r = BufferReader::new(&bytes, Endianness::Little);
713 let m = read_mutable_member(&mut r).unwrap().unwrap();
714 assert_eq!(m.length_code, LengthCode::Lc1);
715 assert_eq!(m.body, &[0x34, 0x12]);
716 }
717
718 #[test]
719 fn lc2_encode_decode_four_byte_body() {
720 let mut w = BufferWriter::new(Endianness::Little);
721 encode_mutable_member_lc(&mut w, 9, true, LengthCode::Lc2, |w| 42u32.encode(w)).unwrap();
722 let bytes = w.into_bytes();
723 assert_eq!(&bytes[0..4], &[0x09, 0x00, 0x00, 0xA0]);
725 assert_eq!(bytes.len(), 4 + 4);
726 let mut r = BufferReader::new(&bytes, Endianness::Little);
727 let m = read_mutable_member(&mut r).unwrap().unwrap();
728 assert_eq!(m.length_code, LengthCode::Lc2);
729 assert!(m.must_understand);
730 }
731
732 #[test]
733 fn lc3_encode_decode_eight_byte_body() {
734 let mut w = BufferWriter::new(Endianness::Little);
735 encode_mutable_member_lc(&mut w, 11, false, LengthCode::Lc3, |w| {
736 0xDEADBEEF_CAFEBABEu64.encode(w)
737 })
738 .unwrap();
739 let bytes = w.into_bytes();
740 assert_eq!(bytes.len(), 4 + 8);
741 let mut r = BufferReader::new(&bytes, Endianness::Little);
742 let m = read_mutable_member(&mut r).unwrap().unwrap();
743 assert_eq!(m.length_code, LengthCode::Lc3);
744 assert_eq!(m.body.len(), 8);
745 }
746
747 #[test]
748 fn lc4_default_path_unchanged() {
749 let mut w = BufferWriter::new(Endianness::Little);
750 encode_mutable_member(&mut w, 1, false, |w| 42u32.encode(w)).unwrap();
751 let bytes = w.into_bytes();
752 assert_eq!(bytes.len(), 4 + 4 + 4);
753 let mut r = BufferReader::new(&bytes, Endianness::Little);
754 let m = read_mutable_member(&mut r).unwrap().unwrap();
755 assert_eq!(m.length_code, LengthCode::Lc4);
756 }
757
758 #[test]
759 fn lc5_aggregate_with_dheader() {
760 let mut w = BufferWriter::new(Endianness::Little);
761 encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc5, |w| {
762 8u32.encode(w)?;
763 42u32.encode(w)?;
764 7u32.encode(w)?;
765 Ok(())
766 })
767 .unwrap();
768 let bytes = w.into_bytes();
769 assert_eq!(bytes.len(), 20);
770 assert_eq!(&bytes[4..8], &[12, 0, 0, 0]);
771 let mut r = BufferReader::new(&bytes, Endianness::Little);
772 let m = read_mutable_member(&mut r).unwrap().unwrap();
773 assert_eq!(m.length_code, LengthCode::Lc5);
774 assert_eq!(m.body.len(), 12);
775 }
776
777 #[test]
778 fn lc6_array_of_4byte_primitives() {
779 let mut w = BufferWriter::new(Endianness::Little);
780 encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc6, |w| {
781 12u32.encode(w)?;
782 10u32.encode(w)?;
783 20u32.encode(w)?;
784 30u32.encode(w)?;
785 Ok(())
786 })
787 .unwrap();
788 let bytes = w.into_bytes();
789 assert_eq!(&bytes[4..8], &[3, 0, 0, 0]);
790 assert_eq!(bytes.len(), 4 + 4 + 16);
791 let mut r = BufferReader::new(&bytes, Endianness::Little);
792 let m = read_mutable_member(&mut r).unwrap().unwrap();
793 assert_eq!(m.length_code, LengthCode::Lc6);
794 assert_eq!(m.body.len(), 16);
795 }
796
797 #[test]
798 fn lc6_lc7_roundtrip_against_cyclone_sample() {
799 let mut w = BufferWriter::new(Endianness::Little);
807 encode_mutable_member_lc(&mut w, 0xABCD, false, LengthCode::Lc6, |w| {
810 400u32.encode(w)?;
812 for i in 0..100u32 {
813 i.encode(w)?;
814 }
815 Ok(())
816 })
817 .unwrap();
818 let bytes = w.into_bytes();
819
820 assert_eq!(&bytes[0..4], &[0xCD, 0xAB, 0x00, 0x60]);
823 assert_eq!(&bytes[4..8], &[100, 0, 0, 0]);
825 assert_eq!(bytes.len(), 8 + 404);
827
828 let mut r = BufferReader::new(&bytes, Endianness::Little);
830 let m = read_mutable_member(&mut r).unwrap().unwrap();
831 assert_eq!(m.length_code, LengthCode::Lc6);
832 assert_eq!(m.member_id, 0xABCD);
833 assert_eq!(m.body.len(), 404);
834 }
835
836 #[test]
837 fn lc6_with_many_elements_decodes_correctly() {
838 let mut w = BufferWriter::new(Endianness::Little);
842 encode_mutable_member_lc(&mut w, 5, false, LengthCode::Lc6, |w| {
843 280_000u32.encode(w)?;
845 for i in 0..70_000u32 {
846 i.encode(w)?;
847 }
848 Ok(())
849 })
850 .unwrap();
851 let bytes = w.into_bytes();
852 let nextint = u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]);
853 assert_eq!(nextint, 70_000);
854 let mut r = BufferReader::new(&bytes, Endianness::Little);
855 let m = read_mutable_member(&mut r).unwrap().unwrap();
856 assert_eq!(m.body.len(), 4 + 70_000 * 4);
858 }
859
860 #[test]
861 fn lc7_array_of_8byte_primitives() {
862 let mut w = BufferWriter::new(Endianness::Little);
863 encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc7, |w| {
864 16u32.encode(w)?;
865 w.write_bytes(&100u64.to_le_bytes())?;
866 w.write_bytes(&200u64.to_le_bytes())?;
867 Ok(())
868 })
869 .unwrap();
870 let bytes = w.into_bytes();
871 assert_eq!(&bytes[4..8], &[2, 0, 0, 0]);
872 assert_eq!(bytes.len(), 4 + 4 + 20);
873 let mut r = BufferReader::new(&bytes, Endianness::Little);
874 let m = read_mutable_member(&mut r).unwrap().unwrap();
875 assert_eq!(m.length_code, LengthCode::Lc7);
876 assert_eq!(m.body.len(), 20);
877 }
878
879 #[test]
880 fn lc0_rejects_wrong_body_size() {
881 let mut w = BufferWriter::new(Endianness::Little);
882 let res = encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc0, |w| 42u32.encode(w));
883 assert!(matches!(res, Err(EncodeError::ValueOutOfRange { .. })));
884 }
885
886 #[test]
887 fn lc6_rejects_misaligned_body() {
888 let mut w = BufferWriter::new(Endianness::Little);
889 let res = encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc6, |w| {
890 0u32.encode(w)?;
891 0u8.encode(w)?;
892 0u8.encode(w)?;
893 0u8.encode(w)?;
894 Ok(())
895 });
896 assert!(matches!(res, Err(EncodeError::ValueOutOfRange { .. })));
897 }
898
899 #[test]
900 fn length_code_body_len_calculation() {
901 assert_eq!(LengthCode::Lc0.body_len(0), 1);
902 assert_eq!(LengthCode::Lc1.body_len(0), 2);
903 assert_eq!(LengthCode::Lc2.body_len(0), 4);
904 assert_eq!(LengthCode::Lc3.body_len(0), 8);
905 assert_eq!(LengthCode::Lc4.body_len(100), 100);
906 assert_eq!(LengthCode::Lc5.body_len(20), 20);
907 assert_eq!(LengthCode::Lc6.body_len(3), 16);
908 assert_eq!(LengthCode::Lc7.body_len(2), 20);
909 }
910
911 #[test]
912 fn length_code_has_nextint_flag() {
913 assert!(!LengthCode::Lc0.has_nextint());
914 assert!(!LengthCode::Lc3.has_nextint());
915 assert!(LengthCode::Lc4.has_nextint());
916 assert!(LengthCode::Lc7.has_nextint());
917 }
918
919 #[test]
920 fn length_code_from_wire_roundtrip() {
921 for v in 0..=7u8 {
922 let lc = LengthCode::from_wire(v).expect("valid");
923 assert_eq!(lc as u8, v);
924 }
925 assert!(LengthCode::from_wire(8).is_none());
926 }
927
928 #[test]
931 fn appendable_in_mutable_member() {
932 let mut w = BufferWriter::new(Endianness::Little);
933 encode_mutable_member(&mut w, 5, false, |w| {
934 encode_appendable(w, |w| {
935 42u32.encode(w)?;
936 100u32.encode(w)?;
937 Ok(())
938 })
939 })
940 .unwrap();
941 let bytes = w.into_bytes();
942 let mut r = BufferReader::new(&bytes, Endianness::Little);
943 let m = read_mutable_member(&mut r).unwrap().unwrap();
944 assert_eq!(m.member_id, 5);
945 let mut sub = BufferReader::new(m.body, Endianness::Little);
946 let (a, b) = decode_appendable(&mut sub, |r| {
947 Ok::<_, DecodeError>((u32::decode(r)?, u32::decode(r)?))
948 })
949 .unwrap();
950 assert_eq!((a, b), (42, 100));
951 }
952
953 #[test]
958 fn mutable_member_id_at_28bit_max_accepted() {
959 let mut w = BufferWriter::new(Endianness::Little);
960 let res = encode_mutable_member_lc(&mut w, 0x0FFF_FFFF, false, LengthCode::Lc2, |inner| {
961 u32::encode(&0u32, inner)
962 });
963 assert!(
964 res.is_ok(),
965 "member_id=0x0FFFFFFF must succeed, got {res:?}"
966 );
967 }
968
969 #[test]
973 fn mutable_member_id_29bit_rejected() {
974 let mut w = BufferWriter::new(Endianness::Little);
975 let res = encode_mutable_member_lc(&mut w, 0x1000_0000, false, LengthCode::Lc2, |inner| {
976 u32::encode(&0u32, inner)
977 });
978 assert!(matches!(res, Err(EncodeError::ValueOutOfRange { .. })));
979 }
980
981 #[test]
984 fn lc6_body_len_less_than_4_rejected() {
985 for short_len in [0usize, 1, 2, 3] {
986 let mut w = BufferWriter::new(Endianness::Little);
987 let res = encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc6, |inner| {
988 inner.write_bytes(&vec![0u8; short_len])
989 });
990 assert!(
991 matches!(res, Err(EncodeError::ValueOutOfRange { .. })),
992 "Lc6 with body_len={short_len} must error, got {res:?}"
993 );
994 }
995 }
996
997 #[test]
1000 fn lc6_body_len_exactly_4_accepted() {
1001 let mut w = BufferWriter::new(Endianness::Little);
1002 let res = encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc6, |inner| {
1003 inner.write_bytes(&[0u8; 4])
1004 });
1005 assert!(res.is_ok(), "Lc6 body_len=4 must succeed, got {res:?}");
1006 }
1007
1008 #[test]
1012 fn lc6_nextint_value_is_minus_4_div_4() {
1013 let mut w = BufferWriter::new(Endianness::Little);
1014 encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc6, |inner| {
1015 inner.write_bytes(&[0u8; 12])
1016 })
1017 .unwrap();
1018 let bytes = w.into_bytes();
1019 assert_eq!(bytes.len(), 20);
1021 let mut ni = [0u8; 4];
1023 ni.copy_from_slice(&bytes[4..8]);
1024 let nextint = u32::from_le_bytes(ni);
1025 assert_eq!(nextint, 2, "nextint must be (12-4)/4=2, not (12+4)/4=4");
1026 }
1027
1028 #[test]
1031 fn lc7_body_len_less_than_4_rejected() {
1032 for short_len in [0usize, 1, 2, 3] {
1033 let mut w = BufferWriter::new(Endianness::Little);
1034 let res = encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc7, |inner| {
1035 inner.write_bytes(&vec![0u8; short_len])
1036 });
1037 assert!(
1038 matches!(res, Err(EncodeError::ValueOutOfRange { .. })),
1039 "Lc7 with body_len={short_len} must error"
1040 );
1041 }
1042 }
1043
1044 #[test]
1047 fn lc7_body_len_exactly_4_accepted() {
1048 let mut w = BufferWriter::new(Endianness::Little);
1049 let res = encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc7, |inner| {
1050 inner.write_bytes(&[0u8; 4])
1051 });
1052 assert!(res.is_ok());
1053 }
1054
1055 #[test]
1058 fn lc7_nextint_value_is_minus_4_div_8() {
1059 let mut w = BufferWriter::new(Endianness::Little);
1060 encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc7, |inner| {
1061 inner.write_bytes(&[0u8; 20])
1062 })
1063 .unwrap();
1064 let bytes = w.into_bytes();
1065 assert_eq!(bytes.len(), 28);
1067 let mut ni = [0u8; 4];
1068 ni.copy_from_slice(&bytes[4..8]);
1069 let nextint = u32::from_le_bytes(ni);
1070 assert_eq!(nextint, 2, "nextint must be (20-4)/8=2, not (20+4)/8=3");
1071 }
1072
1073 #[test]
1078 fn lc6_misaligned_body_len_rejected() {
1079 let mut w = BufferWriter::new(Endianness::Little);
1080 let res = encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc6, |inner| {
1081 inner.write_bytes(&[0u8; 6])
1082 });
1083 assert!(matches!(res, Err(EncodeError::ValueOutOfRange { .. })));
1084 }
1085
1086 #[test]
1089 fn lc7_misaligned_body_len_rejected() {
1090 let mut w = BufferWriter::new(Endianness::Little);
1091 let res = encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc7, |inner| {
1092 inner.write_bytes(&[0u8; 10])
1093 });
1094 assert!(matches!(res, Err(EncodeError::ValueOutOfRange { .. })));
1095 }
1096
1097 #[test]
1101 fn emheader_combines_must_understand_lc_and_member_id() {
1102 let mut w = BufferWriter::new(Endianness::Little);
1103 encode_mutable_member_lc(&mut w, 0x123_4567, true, LengthCode::Lc6, |inner| {
1104 inner.write_bytes(&[0u8; 4])
1105 })
1106 .unwrap();
1107 let bytes = w.into_bytes();
1108 let mut h = [0u8; 4];
1109 h.copy_from_slice(&bytes[..4]);
1110 let emheader = u32::from_le_bytes(h);
1111 assert_eq!(emheader, 0xE123_4567);
1116 }
1117}