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 =
49 BufferWriter::new(writer.endianness()).with_max_alignment(writer.max_alignment());
50 body(&mut inner)?;
51 let bytes = inner.into_bytes();
52 let len = u32::try_from(bytes.len()).map_err(|_| EncodeError::ValueOutOfRange {
53 message: "appendable struct body exceeds u32::MAX",
54 })?;
55 writer.write_u32(len)?;
56 writer.write_bytes(&bytes)?;
57 Ok(())
58}
59
60pub fn decode_appendable<T, F>(reader: &mut BufferReader<'_>, body: F) -> Result<T, DecodeError>
69where
70 F: FnOnce(&mut BufferReader<'_>) -> Result<T, DecodeError>,
71{
72 let len = reader.read_u32()? as usize;
73 if len > reader.remaining() {
74 return Err(DecodeError::LengthExceeded {
75 announced: len,
76 remaining: reader.remaining(),
77 offset: reader.position(),
78 });
79 }
80 let body_bytes = reader.read_bytes(len)?;
81 let mut sub = BufferReader::new(body_bytes, reader.endianness())
84 .with_max_alignment(reader.max_alignment());
85 body(&mut sub)
86}
87
88#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
94#[repr(u8)]
95pub enum LengthCode {
96 Lc0 = 0,
98 Lc1 = 1,
100 Lc2 = 2,
102 Lc3 = 3,
104 Lc4 = 4,
106 Lc5 = 5,
108 Lc6 = 6,
110 Lc7 = 7,
112}
113
114impl LengthCode {
115 #[must_use]
117 pub fn body_len(self, nextint: u32) -> u64 {
118 match self {
119 Self::Lc0 => 1,
120 Self::Lc1 => 2,
121 Self::Lc2 => 4,
122 Self::Lc3 => 8,
123 Self::Lc4 | Self::Lc5 => u64::from(nextint),
124 Self::Lc6 => 4 * u64::from(nextint) + 4,
125 Self::Lc7 => 8 * u64::from(nextint) + 4,
126 }
127 }
128
129 #[must_use]
131 pub const fn has_nextint(self) -> bool {
132 matches!(self, Self::Lc4 | Self::Lc5 | Self::Lc6 | Self::Lc7)
133 }
134
135 #[must_use]
137 pub const fn from_wire(value: u8) -> Option<Self> {
138 match value {
139 0 => Some(Self::Lc0),
140 1 => Some(Self::Lc1),
141 2 => Some(Self::Lc2),
142 3 => Some(Self::Lc3),
143 4 => Some(Self::Lc4),
144 5 => Some(Self::Lc5),
145 6 => Some(Self::Lc6),
146 7 => Some(Self::Lc7),
147 _ => None,
148 }
149 }
150}
151
152pub fn encode_mutable_member<F>(
157 writer: &mut BufferWriter,
158 member_id: u32,
159 must_understand: bool,
160 body: F,
161) -> Result<(), EncodeError>
162where
163 F: FnOnce(&mut BufferWriter) -> Result<(), EncodeError>,
164{
165 encode_mutable_member_lc(writer, member_id, must_understand, LengthCode::Lc4, body)
166}
167
168pub fn encode_mutable_member_lc<F>(
174 writer: &mut BufferWriter,
175 member_id: u32,
176 must_understand: bool,
177 lc: LengthCode,
178 body: F,
179) -> Result<(), EncodeError>
180where
181 F: FnOnce(&mut BufferWriter) -> Result<(), EncodeError>,
182{
183 if member_id > 0x0FFF_FFFF {
184 return Err(EncodeError::ValueOutOfRange {
185 message: "EMHEADER member_id exceeds 28-bit field",
186 });
187 }
188 let mut inner =
191 BufferWriter::new(writer.endianness()).with_max_alignment(writer.max_alignment());
192 body(&mut inner)?;
193 let body_bytes = inner.into_bytes();
194 let body_len = body_bytes.len();
195
196 let nextint: Option<u32> = match lc {
197 LengthCode::Lc0 => {
198 if body_len != 1 {
199 return Err(EncodeError::ValueOutOfRange {
200 message: "LC0 requires exactly 1 byte body",
201 });
202 }
203 None
204 }
205 LengthCode::Lc1 => {
206 if body_len != 2 {
207 return Err(EncodeError::ValueOutOfRange {
208 message: "LC1 requires exactly 2 bytes body",
209 });
210 }
211 None
212 }
213 LengthCode::Lc2 => {
214 if body_len != 4 {
215 return Err(EncodeError::ValueOutOfRange {
216 message: "LC2 requires exactly 4 bytes body",
217 });
218 }
219 None
220 }
221 LengthCode::Lc3 => {
222 if body_len != 8 {
223 return Err(EncodeError::ValueOutOfRange {
224 message: "LC3 requires exactly 8 bytes body",
225 });
226 }
227 None
228 }
229 LengthCode::Lc4 | LengthCode::Lc5 => {
230 let n = u32::try_from(body_len).map_err(|_| EncodeError::ValueOutOfRange {
231 message: "LC4/LC5 body exceeds u32::MAX",
232 })?;
233 Some(n)
234 }
235 LengthCode::Lc6 => {
236 if body_len < 4 || body_len % 4 != 0 {
240 return Err(EncodeError::ValueOutOfRange {
241 message: "LC6 body must be DHEADER + 4n bytes",
242 });
243 }
244 let n =
245 u32::try_from((body_len - 4) / 4).map_err(|_| EncodeError::ValueOutOfRange {
246 message: "LC6 element count exceeds u32::MAX",
247 })?;
248 Some(n)
249 }
250 LengthCode::Lc7 => {
251 if body_len < 4 || body_len % 8 != 4 {
258 return Err(EncodeError::ValueOutOfRange {
259 message: "LC7 body must be DHEADER + 8n bytes",
260 });
261 }
262 let n =
263 u32::try_from((body_len - 4) / 8).map_err(|_| EncodeError::ValueOutOfRange {
264 message: "LC7 element count exceeds u32::MAX",
265 })?;
266 Some(n)
267 }
268 };
269
270 let m_bit = u32::from(must_understand) << 31;
271 let lc_bits = (lc as u32) << 28;
272 let emheader = m_bit + lc_bits + member_id;
278 writer.write_u32(emheader)?;
279 if let Some(ni) = nextint {
280 writer.write_u32(ni)?;
281 }
282 writer.write_bytes(&body_bytes)?;
283 Ok(())
284}
285
286pub struct MutableStructEncoder<'a> {
299 writer: &'a mut BufferWriter,
300 required_ids: Vec<u32>,
301 emitted_ids: Vec<u32>,
302}
303
304impl<'a> MutableStructEncoder<'a> {
305 pub fn new(writer: &'a mut BufferWriter, required_ids: Vec<u32>) -> Self {
309 Self {
310 writer,
311 required_ids,
312 emitted_ids: Vec::new(),
313 }
314 }
315
316 pub fn encode_member<F>(
322 &mut self,
323 member_id: u32,
324 must_understand: bool,
325 body: F,
326 ) -> Result<(), EncodeError>
327 where
328 F: FnOnce(&mut BufferWriter) -> Result<(), EncodeError>,
329 {
330 encode_mutable_member(self.writer, member_id, must_understand, body)?;
331 self.emitted_ids.push(member_id);
332 Ok(())
333 }
334
335 pub fn encode_member_lc<F>(
340 &mut self,
341 member_id: u32,
342 must_understand: bool,
343 lc: LengthCode,
344 body: F,
345 ) -> Result<(), EncodeError>
346 where
347 F: FnOnce(&mut BufferWriter) -> Result<(), EncodeError>,
348 {
349 encode_mutable_member_lc(self.writer, member_id, must_understand, lc, body)?;
350 self.emitted_ids.push(member_id);
351 Ok(())
352 }
353
354 pub fn finish(self) -> Result<(), EncodeError> {
361 for required in &self.required_ids {
362 if !self.emitted_ids.contains(required) {
363 return Err(EncodeError::MissingNonOptionalMember {
364 member_id: *required,
365 });
366 }
367 }
368 Ok(())
369 }
370}
371
372#[derive(Debug, Clone)]
374pub struct MutableMember<'a> {
375 pub member_id: u32,
377 pub must_understand: bool,
379 pub length_code: LengthCode,
381 pub body: &'a [u8],
383}
384
385pub fn read_mutable_member<'a>(
390 reader: &mut BufferReader<'a>,
391) -> Result<Option<MutableMember<'a>>, DecodeError> {
392 if reader.remaining() == 0 {
393 return Ok(None);
394 }
395 let emheader = reader.read_u32()?;
396 let must_understand = (emheader >> 31) & 1 == 1;
397 let lc_raw = ((emheader >> 28) & 0b0111) as u8;
398 let member_id = emheader & 0x0FFF_FFFF;
399 let length_code = LengthCode::from_wire(lc_raw).ok_or_else(|| DecodeError::LengthExceeded {
400 announced: usize::from(lc_raw),
401 remaining: 0,
402 offset: reader.position(),
403 })?;
404
405 let nextint = if length_code.has_nextint() {
406 reader.read_u32()?
407 } else {
408 0
409 };
410
411 let body_len_u64 = length_code.body_len(nextint);
412 let body_len = usize::try_from(body_len_u64).map_err(|_| DecodeError::LengthExceeded {
413 announced: usize::MAX,
414 remaining: reader.remaining(),
415 offset: reader.position(),
416 })?;
417 if body_len > reader.remaining() {
418 return Err(DecodeError::LengthExceeded {
419 announced: body_len,
420 remaining: reader.remaining(),
421 offset: reader.position(),
422 });
423 }
424 let body = reader.read_bytes(body_len)?;
425 Ok(Some(MutableMember {
426 member_id,
427 must_understand,
428 length_code,
429 body,
430 }))
431}
432
433pub fn read_all_mutable_members<'a>(
439 reader: &mut BufferReader<'a>,
440) -> Result<Vec<MutableMember<'a>>, DecodeError> {
441 let mut out = Vec::new();
442 while let Some(m) = read_mutable_member(reader)? {
443 out.push(m);
444 }
445 Ok(out)
446}
447
448pub fn encode_final<F>(writer: &mut BufferWriter, body: F) -> Result<(), EncodeError>
459where
460 F: FnOnce(&mut BufferWriter) -> Result<(), EncodeError>,
461{
462 body(writer)
463}
464
465pub fn decode_final<T, F>(reader: &mut BufferReader<'_>, body: F) -> Result<T, DecodeError>
470where
471 F: FnOnce(&mut BufferReader<'_>) -> Result<T, DecodeError>,
472{
473 body(reader)
474}
475
476#[cfg(test)]
477mod tests {
478 #![allow(clippy::expect_used, clippy::panic, clippy::unwrap_used)]
479 use super::*;
480 use crate::Endianness;
481 use crate::encode::{CdrDecode, CdrEncode};
482 use alloc::vec;
483
484 #[test]
487 fn final_struct_two_u32_members() {
488 let mut w = BufferWriter::new(Endianness::Little);
489 encode_final(&mut w, |w| {
490 42u32.encode(w)?;
491 100u32.encode(w)?;
492 Ok(())
493 })
494 .unwrap();
495 let bytes = w.into_bytes();
496 assert_eq!(bytes.len(), 8);
498
499 let mut r = BufferReader::new(&bytes, Endianness::Little);
500 let (a, b) = decode_final(&mut r, |r| {
501 Ok::<_, DecodeError>((u32::decode(r)?, u32::decode(r)?))
502 })
503 .unwrap();
504 assert_eq!((a, b), (42, 100));
505 }
506
507 #[test]
510 fn appendable_struct_writes_dheader() {
511 let mut w = BufferWriter::new(Endianness::Little);
512 encode_appendable(&mut w, |w| {
513 42u32.encode(w)?;
514 7u8.encode(w)?;
515 Ok(())
516 })
517 .unwrap();
518 let bytes = w.into_bytes();
519 assert_eq!(&bytes[0..4], &[5, 0, 0, 0]); assert_eq!(&bytes[4..8], &[42, 0, 0, 0]); assert_eq!(bytes[8], 7);
524 assert_eq!(bytes.len(), 9);
525 }
526
527 #[test]
528 fn appendable_struct_roundtrip() {
529 let mut w = BufferWriter::new(Endianness::Little);
530 encode_appendable(&mut w, |w| {
531 42u32.encode(w)?;
532 7u8.encode(w)?;
533 Ok(())
534 })
535 .unwrap();
536 let bytes = w.into_bytes();
537
538 let mut r = BufferReader::new(&bytes, Endianness::Little);
539 let (a, b) = decode_appendable(&mut r, |r| {
540 Ok::<_, DecodeError>((u32::decode(r)?, u8::decode(r)?))
541 })
542 .unwrap();
543 assert_eq!((a, b), (42, 7));
544 }
545
546 #[test]
547 fn appendable_decoder_skips_extra_trailing_bytes() {
548 let mut w = BufferWriter::new(Endianness::Little);
552 encode_appendable(&mut w, |w| {
553 42u32.encode(w)?;
554 99u8.encode(w)?;
555 Ok(())
556 })
557 .unwrap();
558 let bytes = w.into_bytes();
559
560 let mut r = BufferReader::new(&bytes, Endianness::Little);
561 let only_first = decode_appendable(&mut r, u32::decode).unwrap();
562 assert_eq!(only_first, 42);
563 assert_eq!(r.remaining(), 0);
565 }
566
567 #[test]
568 fn appendable_decoder_rejects_announced_overrun() {
569 let bytes = [0xFFu8, 0xFF, 0xFF, 0xFF, 1, 2, 3];
570 let mut r = BufferReader::new(&bytes, Endianness::Little);
571 let res = decode_appendable(&mut r, u32::decode);
572 assert!(matches!(res, Err(DecodeError::LengthExceeded { .. })));
573 }
574
575 #[test]
580 fn mutable_struct_encoder_succeeds_when_all_required_emitted() {
581 let mut w = BufferWriter::new(Endianness::Little);
582 let mut enc = MutableStructEncoder::new(&mut w, vec![1, 2, 3]);
583 enc.encode_member(1, false, |w| 42u32.encode(w)).unwrap();
584 enc.encode_member(2, false, |w| 7u8.encode(w)).unwrap();
585 enc.encode_member(3, false, |w| 99u16.encode(w)).unwrap();
586 enc.finish().unwrap();
587 }
588
589 #[test]
590 fn mutable_encode_omitting_non_optional_member_errors() {
591 let mut w = BufferWriter::new(Endianness::Little);
592 let mut enc = MutableStructEncoder::new(&mut w, vec![1, 2, 3]);
593 enc.encode_member(1, false, |w| 42u32.encode(w)).unwrap();
594 enc.encode_member(3, false, |w| 99u16.encode(w)).unwrap();
596 let err = enc.finish().unwrap_err();
597 assert_eq!(err, EncodeError::MissingNonOptionalMember { member_id: 2 });
598 }
599
600 #[test]
601 fn mutable_encode_first_missing_id_is_reported() {
602 let mut w = BufferWriter::new(Endianness::Little);
603 let mut enc = MutableStructEncoder::new(&mut w, vec![10, 20, 30]);
604 enc.encode_member(20, false, |w| 5u32.encode(w)).unwrap();
605 let err = enc.finish().unwrap_err();
607 assert_eq!(err, EncodeError::MissingNonOptionalMember { member_id: 10 });
608 }
609
610 #[test]
611 fn mutable_encode_optional_only_with_no_required_succeeds() {
612 let mut w = BufferWriter::new(Endianness::Little);
615 let enc = MutableStructEncoder::new(&mut w, vec![]);
616 enc.finish().unwrap();
617 }
618
619 #[test]
620 fn mutable_encode_extra_optional_emitted_does_not_break_finish() {
621 let mut w = BufferWriter::new(Endianness::Little);
623 let mut enc = MutableStructEncoder::new(&mut w, vec![1]);
624 enc.encode_member(1, false, |w| 42u32.encode(w)).unwrap();
625 enc.encode_member(99, false, |w| 0u8.encode(w)).unwrap();
626 enc.finish().unwrap();
627 }
628
629 #[test]
630 fn mutable_encode_with_lc_variant_tracks_id() {
631 let mut w = BufferWriter::new(Endianness::Little);
632 let mut enc = MutableStructEncoder::new(&mut w, vec![5]);
633 enc.encode_member_lc(5, false, LengthCode::Lc0, |w| 0x42u8.encode(w))
634 .unwrap();
635 enc.finish().unwrap();
636 }
637
638 #[test]
639 fn mutable_member_emheader_layout() {
640 let mut w = BufferWriter::new(Endianness::Little);
641 encode_mutable_member(&mut w, 0x1234, false, |w| 42u32.encode(w)).unwrap();
642 let bytes = w.into_bytes();
643 assert_eq!(&bytes[0..4], &[0x34, 0x12, 0x00, 0x40]);
646 assert_eq!(&bytes[4..8], &[4, 0, 0, 0]);
648 assert_eq!(&bytes[8..12], &[42, 0, 0, 0]);
650 }
651
652 #[test]
653 fn mutable_member_must_understand_sets_high_bit() {
654 let mut w = BufferWriter::new(Endianness::Little);
655 encode_mutable_member(&mut w, 1, true, |w| 0u8.encode(w)).unwrap();
656 let bytes = w.into_bytes();
657 assert_eq!(&bytes[0..4], &[0x01, 0x00, 0x00, 0xC0]);
659 }
660
661 #[test]
662 fn mutable_member_rejects_oversized_id() {
663 let mut w = BufferWriter::new(Endianness::Little);
664 let res = encode_mutable_member(&mut w, 0xFFFF_FFFF, false, |w| 0u8.encode(w));
665 assert!(matches!(res, Err(EncodeError::ValueOutOfRange { .. })));
666 }
667
668 #[test]
669 fn mutable_struct_roundtrip_two_members() {
670 let mut w = BufferWriter::new(Endianness::Little);
671 encode_mutable_member(&mut w, 1, false, |w| 42u32.encode(w)).unwrap();
672 encode_mutable_member(&mut w, 2, true, |w| 7u8.encode(w)).unwrap();
673 let bytes = w.into_bytes();
674
675 let mut r = BufferReader::new(&bytes, Endianness::Little);
676 let members = read_all_mutable_members(&mut r).unwrap();
677 assert_eq!(members.len(), 2);
678 assert_eq!(members[0].member_id, 1);
679 assert!(!members[0].must_understand);
680 assert_eq!(members[1].member_id, 2);
681 assert!(members[1].must_understand);
682
683 let mut sub = BufferReader::new(members[0].body, Endianness::Little);
684 assert_eq!(u32::decode(&mut sub).unwrap(), 42);
685 let mut sub = BufferReader::new(members[1].body, Endianness::Little);
686 assert_eq!(u8::decode(&mut sub).unwrap(), 7);
687 }
688
689 #[test]
690 fn mutable_member_reads_none_on_eof() {
691 let bytes: [u8; 0] = [];
692 let mut r = BufferReader::new(&bytes, Endianness::Little);
693 let res = read_mutable_member(&mut r).unwrap();
694 assert!(res.is_none());
695 }
696
697 #[test]
700 fn lc0_encode_decode_one_byte_body() {
701 let mut w = BufferWriter::new(Endianness::Little);
702 encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc0, |w| 0x42u8.encode(w)).unwrap();
703 let bytes = w.into_bytes();
704 assert_eq!(&bytes[0..4], &[0x01, 0x00, 0x00, 0x00]);
705 assert_eq!(bytes[4], 0x42);
706 assert_eq!(bytes.len(), 5);
707 let mut r = BufferReader::new(&bytes, Endianness::Little);
708 let m = read_mutable_member(&mut r).unwrap().unwrap();
709 assert_eq!(m.length_code, LengthCode::Lc0);
710 assert_eq!(m.body, &[0x42]);
711 }
712
713 #[test]
714 fn lc1_encode_decode_two_byte_body() {
715 let mut w = BufferWriter::new(Endianness::Little);
716 encode_mutable_member_lc(&mut w, 7, false, LengthCode::Lc1, |w| 0x1234u16.encode(w))
717 .unwrap();
718 let bytes = w.into_bytes();
719 assert_eq!(bytes.len(), 4 + 2);
720 let mut r = BufferReader::new(&bytes, Endianness::Little);
721 let m = read_mutable_member(&mut r).unwrap().unwrap();
722 assert_eq!(m.length_code, LengthCode::Lc1);
723 assert_eq!(m.body, &[0x34, 0x12]);
724 }
725
726 #[test]
727 fn lc2_encode_decode_four_byte_body() {
728 let mut w = BufferWriter::new(Endianness::Little);
729 encode_mutable_member_lc(&mut w, 9, true, LengthCode::Lc2, |w| 42u32.encode(w)).unwrap();
730 let bytes = w.into_bytes();
731 assert_eq!(&bytes[0..4], &[0x09, 0x00, 0x00, 0xA0]);
733 assert_eq!(bytes.len(), 4 + 4);
734 let mut r = BufferReader::new(&bytes, Endianness::Little);
735 let m = read_mutable_member(&mut r).unwrap().unwrap();
736 assert_eq!(m.length_code, LengthCode::Lc2);
737 assert!(m.must_understand);
738 }
739
740 #[test]
741 fn lc3_encode_decode_eight_byte_body() {
742 let mut w = BufferWriter::new(Endianness::Little);
743 encode_mutable_member_lc(&mut w, 11, false, LengthCode::Lc3, |w| {
744 0xDEADBEEF_CAFEBABEu64.encode(w)
745 })
746 .unwrap();
747 let bytes = w.into_bytes();
748 assert_eq!(bytes.len(), 4 + 8);
749 let mut r = BufferReader::new(&bytes, Endianness::Little);
750 let m = read_mutable_member(&mut r).unwrap().unwrap();
751 assert_eq!(m.length_code, LengthCode::Lc3);
752 assert_eq!(m.body.len(), 8);
753 }
754
755 #[test]
756 fn lc4_default_path_unchanged() {
757 let mut w = BufferWriter::new(Endianness::Little);
758 encode_mutable_member(&mut w, 1, false, |w| 42u32.encode(w)).unwrap();
759 let bytes = w.into_bytes();
760 assert_eq!(bytes.len(), 4 + 4 + 4);
761 let mut r = BufferReader::new(&bytes, Endianness::Little);
762 let m = read_mutable_member(&mut r).unwrap().unwrap();
763 assert_eq!(m.length_code, LengthCode::Lc4);
764 }
765
766 #[test]
767 fn lc5_aggregate_with_dheader() {
768 let mut w = BufferWriter::new(Endianness::Little);
769 encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc5, |w| {
770 8u32.encode(w)?;
771 42u32.encode(w)?;
772 7u32.encode(w)?;
773 Ok(())
774 })
775 .unwrap();
776 let bytes = w.into_bytes();
777 assert_eq!(bytes.len(), 20);
778 assert_eq!(&bytes[4..8], &[12, 0, 0, 0]);
779 let mut r = BufferReader::new(&bytes, Endianness::Little);
780 let m = read_mutable_member(&mut r).unwrap().unwrap();
781 assert_eq!(m.length_code, LengthCode::Lc5);
782 assert_eq!(m.body.len(), 12);
783 }
784
785 #[test]
786 fn lc6_array_of_4byte_primitives() {
787 let mut w = BufferWriter::new(Endianness::Little);
788 encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc6, |w| {
789 12u32.encode(w)?;
790 10u32.encode(w)?;
791 20u32.encode(w)?;
792 30u32.encode(w)?;
793 Ok(())
794 })
795 .unwrap();
796 let bytes = w.into_bytes();
797 assert_eq!(&bytes[4..8], &[3, 0, 0, 0]);
798 assert_eq!(bytes.len(), 4 + 4 + 16);
799 let mut r = BufferReader::new(&bytes, Endianness::Little);
800 let m = read_mutable_member(&mut r).unwrap().unwrap();
801 assert_eq!(m.length_code, LengthCode::Lc6);
802 assert_eq!(m.body.len(), 16);
803 }
804
805 #[test]
806 fn lc6_lc7_roundtrip_against_cyclone_sample() {
807 let mut w = BufferWriter::new(Endianness::Little);
815 encode_mutable_member_lc(&mut w, 0xABCD, false, LengthCode::Lc6, |w| {
818 400u32.encode(w)?;
820 for i in 0..100u32 {
821 i.encode(w)?;
822 }
823 Ok(())
824 })
825 .unwrap();
826 let bytes = w.into_bytes();
827
828 assert_eq!(&bytes[0..4], &[0xCD, 0xAB, 0x00, 0x60]);
831 assert_eq!(&bytes[4..8], &[100, 0, 0, 0]);
833 assert_eq!(bytes.len(), 8 + 404);
835
836 let mut r = BufferReader::new(&bytes, Endianness::Little);
838 let m = read_mutable_member(&mut r).unwrap().unwrap();
839 assert_eq!(m.length_code, LengthCode::Lc6);
840 assert_eq!(m.member_id, 0xABCD);
841 assert_eq!(m.body.len(), 404);
842 }
843
844 #[test]
845 fn lc6_with_many_elements_decodes_correctly() {
846 let mut w = BufferWriter::new(Endianness::Little);
850 encode_mutable_member_lc(&mut w, 5, false, LengthCode::Lc6, |w| {
851 280_000u32.encode(w)?;
853 for i in 0..70_000u32 {
854 i.encode(w)?;
855 }
856 Ok(())
857 })
858 .unwrap();
859 let bytes = w.into_bytes();
860 let nextint = u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]);
861 assert_eq!(nextint, 70_000);
862 let mut r = BufferReader::new(&bytes, Endianness::Little);
863 let m = read_mutable_member(&mut r).unwrap().unwrap();
864 assert_eq!(m.body.len(), 4 + 70_000 * 4);
866 }
867
868 #[test]
869 fn lc7_array_of_8byte_primitives() {
870 let mut w = BufferWriter::new(Endianness::Little);
871 encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc7, |w| {
872 16u32.encode(w)?;
873 w.write_bytes(&100u64.to_le_bytes())?;
874 w.write_bytes(&200u64.to_le_bytes())?;
875 Ok(())
876 })
877 .unwrap();
878 let bytes = w.into_bytes();
879 assert_eq!(&bytes[4..8], &[2, 0, 0, 0]);
880 assert_eq!(bytes.len(), 4 + 4 + 20);
881 let mut r = BufferReader::new(&bytes, Endianness::Little);
882 let m = read_mutable_member(&mut r).unwrap().unwrap();
883 assert_eq!(m.length_code, LengthCode::Lc7);
884 assert_eq!(m.body.len(), 20);
885 }
886
887 #[test]
888 fn lc0_rejects_wrong_body_size() {
889 let mut w = BufferWriter::new(Endianness::Little);
890 let res = encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc0, |w| 42u32.encode(w));
891 assert!(matches!(res, Err(EncodeError::ValueOutOfRange { .. })));
892 }
893
894 #[test]
895 fn lc6_rejects_misaligned_body() {
896 let mut w = BufferWriter::new(Endianness::Little);
897 let res = encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc6, |w| {
898 0u32.encode(w)?;
899 0u8.encode(w)?;
900 0u8.encode(w)?;
901 0u8.encode(w)?;
902 Ok(())
903 });
904 assert!(matches!(res, Err(EncodeError::ValueOutOfRange { .. })));
905 }
906
907 #[test]
908 fn length_code_body_len_calculation() {
909 assert_eq!(LengthCode::Lc0.body_len(0), 1);
910 assert_eq!(LengthCode::Lc1.body_len(0), 2);
911 assert_eq!(LengthCode::Lc2.body_len(0), 4);
912 assert_eq!(LengthCode::Lc3.body_len(0), 8);
913 assert_eq!(LengthCode::Lc4.body_len(100), 100);
914 assert_eq!(LengthCode::Lc5.body_len(20), 20);
915 assert_eq!(LengthCode::Lc6.body_len(3), 16);
916 assert_eq!(LengthCode::Lc7.body_len(2), 20);
917 }
918
919 #[test]
920 fn length_code_has_nextint_flag() {
921 assert!(!LengthCode::Lc0.has_nextint());
922 assert!(!LengthCode::Lc3.has_nextint());
923 assert!(LengthCode::Lc4.has_nextint());
924 assert!(LengthCode::Lc7.has_nextint());
925 }
926
927 #[test]
928 fn length_code_from_wire_roundtrip() {
929 for v in 0..=7u8 {
930 let lc = LengthCode::from_wire(v).expect("valid");
931 assert_eq!(lc as u8, v);
932 }
933 assert!(LengthCode::from_wire(8).is_none());
934 }
935
936 #[test]
939 fn appendable_in_mutable_member() {
940 let mut w = BufferWriter::new(Endianness::Little);
941 encode_mutable_member(&mut w, 5, false, |w| {
942 encode_appendable(w, |w| {
943 42u32.encode(w)?;
944 100u32.encode(w)?;
945 Ok(())
946 })
947 })
948 .unwrap();
949 let bytes = w.into_bytes();
950 let mut r = BufferReader::new(&bytes, Endianness::Little);
951 let m = read_mutable_member(&mut r).unwrap().unwrap();
952 assert_eq!(m.member_id, 5);
953 let mut sub = BufferReader::new(m.body, Endianness::Little);
954 let (a, b) = decode_appendable(&mut sub, |r| {
955 Ok::<_, DecodeError>((u32::decode(r)?, u32::decode(r)?))
956 })
957 .unwrap();
958 assert_eq!((a, b), (42, 100));
959 }
960
961 #[test]
966 fn mutable_member_id_at_28bit_max_accepted() {
967 let mut w = BufferWriter::new(Endianness::Little);
968 let res = encode_mutable_member_lc(&mut w, 0x0FFF_FFFF, false, LengthCode::Lc2, |inner| {
969 u32::encode(&0u32, inner)
970 });
971 assert!(
972 res.is_ok(),
973 "member_id=0x0FFFFFFF must succeed, got {res:?}"
974 );
975 }
976
977 #[test]
981 fn mutable_member_id_29bit_rejected() {
982 let mut w = BufferWriter::new(Endianness::Little);
983 let res = encode_mutable_member_lc(&mut w, 0x1000_0000, false, LengthCode::Lc2, |inner| {
984 u32::encode(&0u32, inner)
985 });
986 assert!(matches!(res, Err(EncodeError::ValueOutOfRange { .. })));
987 }
988
989 #[test]
992 fn lc6_body_len_less_than_4_rejected() {
993 for short_len in [0usize, 1, 2, 3] {
994 let mut w = BufferWriter::new(Endianness::Little);
995 let res = encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc6, |inner| {
996 inner.write_bytes(&vec![0u8; short_len])
997 });
998 assert!(
999 matches!(res, Err(EncodeError::ValueOutOfRange { .. })),
1000 "Lc6 with body_len={short_len} must error, got {res:?}"
1001 );
1002 }
1003 }
1004
1005 #[test]
1008 fn lc6_body_len_exactly_4_accepted() {
1009 let mut w = BufferWriter::new(Endianness::Little);
1010 let res = encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc6, |inner| {
1011 inner.write_bytes(&[0u8; 4])
1012 });
1013 assert!(res.is_ok(), "Lc6 body_len=4 must succeed, got {res:?}");
1014 }
1015
1016 #[test]
1020 fn lc6_nextint_value_is_minus_4_div_4() {
1021 let mut w = BufferWriter::new(Endianness::Little);
1022 encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc6, |inner| {
1023 inner.write_bytes(&[0u8; 12])
1024 })
1025 .unwrap();
1026 let bytes = w.into_bytes();
1027 assert_eq!(bytes.len(), 20);
1029 let mut ni = [0u8; 4];
1031 ni.copy_from_slice(&bytes[4..8]);
1032 let nextint = u32::from_le_bytes(ni);
1033 assert_eq!(nextint, 2, "nextint must be (12-4)/4=2, not (12+4)/4=4");
1034 }
1035
1036 #[test]
1039 fn lc7_body_len_less_than_4_rejected() {
1040 for short_len in [0usize, 1, 2, 3] {
1041 let mut w = BufferWriter::new(Endianness::Little);
1042 let res = encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc7, |inner| {
1043 inner.write_bytes(&vec![0u8; short_len])
1044 });
1045 assert!(
1046 matches!(res, Err(EncodeError::ValueOutOfRange { .. })),
1047 "Lc7 with body_len={short_len} must error"
1048 );
1049 }
1050 }
1051
1052 #[test]
1055 fn lc7_body_len_exactly_4_accepted() {
1056 let mut w = BufferWriter::new(Endianness::Little);
1057 let res = encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc7, |inner| {
1058 inner.write_bytes(&[0u8; 4])
1059 });
1060 assert!(res.is_ok());
1061 }
1062
1063 #[test]
1066 fn lc7_nextint_value_is_minus_4_div_8() {
1067 let mut w = BufferWriter::new(Endianness::Little);
1068 encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc7, |inner| {
1069 inner.write_bytes(&[0u8; 20])
1070 })
1071 .unwrap();
1072 let bytes = w.into_bytes();
1073 assert_eq!(bytes.len(), 28);
1075 let mut ni = [0u8; 4];
1076 ni.copy_from_slice(&bytes[4..8]);
1077 let nextint = u32::from_le_bytes(ni);
1078 assert_eq!(nextint, 2, "nextint must be (20-4)/8=2, not (20+4)/8=3");
1079 }
1080
1081 #[test]
1086 fn lc6_misaligned_body_len_rejected() {
1087 let mut w = BufferWriter::new(Endianness::Little);
1088 let res = encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc6, |inner| {
1089 inner.write_bytes(&[0u8; 6])
1090 });
1091 assert!(matches!(res, Err(EncodeError::ValueOutOfRange { .. })));
1092 }
1093
1094 #[test]
1097 fn lc7_misaligned_body_len_rejected() {
1098 let mut w = BufferWriter::new(Endianness::Little);
1099 let res = encode_mutable_member_lc(&mut w, 1, false, LengthCode::Lc7, |inner| {
1100 inner.write_bytes(&[0u8; 10])
1101 });
1102 assert!(matches!(res, Err(EncodeError::ValueOutOfRange { .. })));
1103 }
1104
1105 #[test]
1109 fn emheader_combines_must_understand_lc_and_member_id() {
1110 let mut w = BufferWriter::new(Endianness::Little);
1111 encode_mutable_member_lc(&mut w, 0x123_4567, true, LengthCode::Lc6, |inner| {
1112 inner.write_bytes(&[0u8; 4])
1113 })
1114 .unwrap();
1115 let bytes = w.into_bytes();
1116 let mut h = [0u8; 4];
1117 h.copy_from_slice(&bytes[..4]);
1118 let emheader = u32::from_le_bytes(h);
1119 assert_eq!(emheader, 0xE123_4567);
1124 }
1125}