1use crate::{
4 CDR_LE_HEADER,
5 error::{DeserError, SerError},
6};
7
8pub struct CdrWriter<'a> {
15 buf: &'a mut [u8],
16 pos: usize,
17 origin: usize,
20}
21
22impl<'a> CdrWriter<'a> {
23 pub fn new(buf: &'a mut [u8]) -> Self {
25 Self {
26 buf,
27 pos: 0,
28 origin: 0,
29 }
30 }
31
32 pub fn new_at(buf: &'a mut [u8], pos: usize) -> Result<Self, SerError> {
38 if pos > buf.len() {
39 return Err(SerError::BufferTooSmall);
40 }
41 Ok(Self {
42 buf,
43 pos,
44 origin: 0,
45 })
46 }
47
48 pub fn new_with_header(buf: &'a mut [u8]) -> Result<Self, SerError> {
55 if buf.len() < 4 {
56 return Err(SerError::BufferTooSmall);
57 }
58 buf[0..4].copy_from_slice(&CDR_LE_HEADER);
59 Ok(Self {
60 buf,
61 pos: 4,
62 origin: 4,
63 })
64 }
65
66 #[inline]
68 pub fn position(&self) -> usize {
69 self.pos
70 }
71
72 #[inline]
74 pub fn remaining(&self) -> usize {
75 self.buf.len().saturating_sub(self.pos)
76 }
77
78 pub fn as_slice(&self) -> &[u8] {
80 &self.buf[..self.pos]
81 }
82
83 #[inline]
85 pub fn align(&mut self, alignment: usize) -> Result<(), SerError> {
86 let offset = self.pos - self.origin;
87 let padding = (alignment - (offset % alignment)) % alignment;
88 if self.remaining() < padding {
89 return Err(SerError::BufferTooSmall);
90 }
91 for i in 0..padding {
93 self.buf[self.pos + i] = 0;
94 }
95 self.pos += padding;
96 Ok(())
97 }
98
99 #[inline]
101 pub fn write_u8(&mut self, value: u8) -> Result<(), SerError> {
102 if self.remaining() < 1 {
103 return Err(SerError::BufferTooSmall);
104 }
105 self.buf[self.pos] = value;
106 self.pos += 1;
107 Ok(())
108 }
109
110 #[inline]
112 pub fn write_bool(&mut self, value: bool) -> Result<(), SerError> {
113 self.write_u8(value as u8)
114 }
115
116 #[inline]
118 pub fn write_i8(&mut self, value: i8) -> Result<(), SerError> {
119 self.write_u8(value as u8)
120 }
121
122 #[inline]
124 pub fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), SerError> {
125 if self.remaining() < bytes.len() {
126 return Err(SerError::BufferTooSmall);
127 }
128 self.buf[self.pos..self.pos + bytes.len()].copy_from_slice(bytes);
129 self.pos += bytes.len();
130 Ok(())
131 }
132
133 #[inline]
135 pub fn write_u16(&mut self, value: u16) -> Result<(), SerError> {
136 self.align(2)?;
137 if self.remaining() < 2 {
138 return Err(SerError::BufferTooSmall);
139 }
140 self.buf[self.pos..self.pos + 2].copy_from_slice(&value.to_le_bytes());
141 self.pos += 2;
142 Ok(())
143 }
144
145 #[inline]
147 pub fn write_u32(&mut self, value: u32) -> Result<(), SerError> {
148 self.align(4)?;
149 if self.remaining() < 4 {
150 return Err(SerError::BufferTooSmall);
151 }
152 self.buf[self.pos..self.pos + 4].copy_from_slice(&value.to_le_bytes());
153 self.pos += 4;
154 Ok(())
155 }
156
157 #[inline]
159 pub fn write_u64(&mut self, value: u64) -> Result<(), SerError> {
160 self.align(8)?;
161 if self.remaining() < 8 {
162 return Err(SerError::BufferTooSmall);
163 }
164 self.buf[self.pos..self.pos + 8].copy_from_slice(&value.to_le_bytes());
165 self.pos += 8;
166 Ok(())
167 }
168
169 #[inline]
171 pub fn write_i16(&mut self, value: i16) -> Result<(), SerError> {
172 self.write_u16(value as u16)
173 }
174
175 #[inline]
177 pub fn write_i32(&mut self, value: i32) -> Result<(), SerError> {
178 self.write_u32(value as u32)
179 }
180
181 #[inline]
183 pub fn write_i64(&mut self, value: i64) -> Result<(), SerError> {
184 self.write_u64(value as u64)
185 }
186
187 #[inline]
189 pub fn write_f32(&mut self, value: f32) -> Result<(), SerError> {
190 self.write_u32(value.to_bits())
191 }
192
193 #[inline]
195 pub fn write_f64(&mut self, value: f64) -> Result<(), SerError> {
196 self.write_u64(value.to_bits())
197 }
198
199 pub fn write_string(&mut self, s: &str) -> Result<(), SerError> {
201 let len = s.len() + 1; if len > u32::MAX as usize {
203 return Err(SerError::StringTooLong);
204 }
205 self.write_u32(len as u32)?;
206 self.write_bytes(s.as_bytes())?;
207 self.write_u8(0)?; Ok(())
209 }
210
211 #[inline]
213 pub fn write_sequence_len(&mut self, len: usize) -> Result<(), SerError> {
214 if len > u32::MAX as usize {
215 return Err(SerError::SequenceTooLong);
216 }
217 self.write_u32(len as u32)
218 }
219}
220
221pub struct CdrReader<'a> {
225 buf: &'a [u8],
226 pos: usize,
227 origin: usize,
228}
229
230impl<'a> CdrReader<'a> {
231 pub fn new(buf: &'a [u8]) -> Self {
233 Self {
234 buf,
235 pos: 0,
236 origin: 0,
237 }
238 }
239
240 pub fn new_at(buf: &'a [u8], pos: usize) -> Result<Self, DeserError> {
246 if pos > buf.len() {
247 return Err(DeserError::UnexpectedEof);
248 }
249 Ok(Self {
250 buf,
251 pos,
252 origin: 0,
253 })
254 }
255
256 pub fn new_with_header(buf: &'a [u8]) -> Result<Self, DeserError> {
260 if buf.len() < 4 {
261 return Err(DeserError::UnexpectedEof);
262 }
263 if buf[0] != 0x00 || (buf[1] != 0x00 && buf[1] != 0x01) {
265 return Err(DeserError::InvalidHeader);
266 }
267 Ok(Self {
268 buf,
269 pos: 4,
270 origin: 4,
271 })
272 }
273
274 #[inline]
276 pub fn position(&self) -> usize {
277 self.pos
278 }
279
280 #[inline]
282 pub fn remaining(&self) -> usize {
283 self.buf.len().saturating_sub(self.pos)
284 }
285
286 #[inline]
288 pub fn is_empty(&self) -> bool {
289 self.remaining() == 0
290 }
291
292 #[inline]
294 pub fn align(&mut self, alignment: usize) -> Result<(), DeserError> {
295 let offset = self.pos - self.origin;
296 let padding = (alignment - (offset % alignment)) % alignment;
297 if self.remaining() < padding {
298 return Err(DeserError::UnexpectedEof);
299 }
300 self.pos += padding;
301 Ok(())
302 }
303
304 #[inline]
306 pub fn read_u8(&mut self) -> Result<u8, DeserError> {
307 if self.remaining() < 1 {
308 return Err(DeserError::UnexpectedEof);
309 }
310 let value = self.buf[self.pos];
311 self.pos += 1;
312 Ok(value)
313 }
314
315 #[inline]
317 pub fn read_bool(&mut self) -> Result<bool, DeserError> {
318 Ok(self.read_u8()? != 0)
319 }
320
321 #[inline]
323 pub fn read_i8(&mut self) -> Result<i8, DeserError> {
324 Ok(self.read_u8()? as i8)
325 }
326
327 #[inline]
329 pub fn read_bytes(&mut self, len: usize) -> Result<&'a [u8], DeserError> {
330 if self.remaining() < len {
331 return Err(DeserError::UnexpectedEof);
332 }
333 let bytes = &self.buf[self.pos..self.pos + len];
334 self.pos += len;
335 Ok(bytes)
336 }
337
338 #[inline]
340 pub fn read_u16(&mut self) -> Result<u16, DeserError> {
341 self.align(2)?;
342 if self.remaining() < 2 {
343 return Err(DeserError::UnexpectedEof);
344 }
345 let value = u16::from_le_bytes([self.buf[self.pos], self.buf[self.pos + 1]]);
346 self.pos += 2;
347 Ok(value)
348 }
349
350 #[inline]
352 pub fn read_u32(&mut self) -> Result<u32, DeserError> {
353 self.align(4)?;
354 if self.remaining() < 4 {
355 return Err(DeserError::UnexpectedEof);
356 }
357 let value = u32::from_le_bytes([
358 self.buf[self.pos],
359 self.buf[self.pos + 1],
360 self.buf[self.pos + 2],
361 self.buf[self.pos + 3],
362 ]);
363 self.pos += 4;
364 Ok(value)
365 }
366
367 #[inline]
369 pub fn read_u64(&mut self) -> Result<u64, DeserError> {
370 self.align(8)?;
371 if self.remaining() < 8 {
372 return Err(DeserError::UnexpectedEof);
373 }
374 let value = u64::from_le_bytes([
375 self.buf[self.pos],
376 self.buf[self.pos + 1],
377 self.buf[self.pos + 2],
378 self.buf[self.pos + 3],
379 self.buf[self.pos + 4],
380 self.buf[self.pos + 5],
381 self.buf[self.pos + 6],
382 self.buf[self.pos + 7],
383 ]);
384 self.pos += 8;
385 Ok(value)
386 }
387
388 #[inline]
390 pub fn read_i16(&mut self) -> Result<i16, DeserError> {
391 Ok(self.read_u16()? as i16)
392 }
393
394 #[inline]
396 pub fn read_i32(&mut self) -> Result<i32, DeserError> {
397 Ok(self.read_u32()? as i32)
398 }
399
400 #[inline]
402 pub fn read_i64(&mut self) -> Result<i64, DeserError> {
403 Ok(self.read_u64()? as i64)
404 }
405
406 #[inline]
408 pub fn read_f32(&mut self) -> Result<f32, DeserError> {
409 Ok(f32::from_bits(self.read_u32()?))
410 }
411
412 #[inline]
414 pub fn read_f64(&mut self) -> Result<f64, DeserError> {
415 Ok(f64::from_bits(self.read_u64()?))
416 }
417
418 pub fn read_string(&mut self) -> Result<&'a str, DeserError> {
422 let len = self.read_u32()? as usize;
423 if len == 0 {
424 return Err(DeserError::InvalidData);
425 }
426 if self.remaining() < len {
427 return Err(DeserError::UnexpectedEof);
428 }
429 let bytes = &self.buf[self.pos..self.pos + len - 1];
431 self.pos += len;
432 core::str::from_utf8(bytes).map_err(|_| DeserError::InvalidUtf8)
433 }
434
435 #[inline]
437 pub fn read_sequence_len(&mut self) -> Result<usize, DeserError> {
438 Ok(self.read_u32()? as usize)
439 }
440
441 pub fn read_slice_u8(&mut self) -> Result<&'a [u8], DeserError> {
448 let len = self.read_u32()? as usize;
449 self.read_bytes(len)
450 }
451
452 pub fn read_slice_i8(&mut self) -> Result<&'a [u8], DeserError> {
454 self.read_slice_u8()
456 }
457
458 pub fn read_slice_bool(&mut self) -> Result<&'a [u8], DeserError> {
463 self.read_slice_u8()
464 }
465
466 pub fn read_slice_u16_raw(&mut self) -> Result<(&'a [u8], usize), DeserError> {
472 let len = self.read_u32()? as usize;
473 self.align(2)?;
474 let byte_len = len * 2;
475 let bytes = self.read_bytes(byte_len)?;
476 Ok((bytes, len))
477 }
478
479 pub fn read_slice_u32_raw(&mut self) -> Result<(&'a [u8], usize), DeserError> {
481 let len = self.read_u32()? as usize;
482 self.align(4)?;
483 let byte_len = len * 4;
484 let bytes = self.read_bytes(byte_len)?;
485 Ok((bytes, len))
486 }
487
488 pub fn read_slice_f32_raw(&mut self) -> Result<(&'a [u8], usize), DeserError> {
490 let len = self.read_u32()? as usize;
491 self.align(4)?;
492 let byte_len = len * 4;
493 let bytes = self.read_bytes(byte_len)?;
494 Ok((bytes, len))
495 }
496
497 pub fn read_slice_f64_raw(&mut self) -> Result<(&'a [u8], usize), DeserError> {
499 let len = self.read_u32()? as usize;
500 self.align(8)?;
501 let byte_len = len * 8;
502 let bytes = self.read_bytes(byte_len)?;
503 Ok((bytes, len))
504 }
505
506 pub fn read_slice_u64_raw(&mut self) -> Result<(&'a [u8], usize), DeserError> {
508 let len = self.read_u32()? as usize;
509 self.align(8)?;
510 let byte_len = len * 8;
511 let bytes = self.read_bytes(byte_len)?;
512 Ok((bytes, len))
513 }
514
515 pub fn read_le_slice<T: LeDecode>(&mut self) -> Result<LeSliceView<'a, T>, DeserError> {
525 let len = self.read_u32()? as usize;
526 self.align(T::SIZE)?;
527 let byte_len = len * T::SIZE;
528 let bytes = self.read_bytes(byte_len)?;
529 Ok(LeSliceView::new(bytes))
530 }
531}
532
533pub trait LeDecode: Sized + Copy {
538 const SIZE: usize;
540 fn from_le(bytes: &[u8]) -> Self;
542}
543
544macro_rules! impl_le_decode {
545 ($($t:ty),+ $(,)?) => {$(
546 impl LeDecode for $t {
547 const SIZE: usize = core::mem::size_of::<$t>();
548 #[inline]
549 fn from_le(bytes: &[u8]) -> Self {
550 let mut buf = [0u8; core::mem::size_of::<$t>()];
551 buf.copy_from_slice(bytes);
552 <$t>::from_le_bytes(buf)
553 }
554 }
555 )+};
556}
557impl_le_decode!(u16, i16, u32, i32, u64, i64, f32, f64);
558
559#[derive(Clone, Copy)]
565pub struct LeSliceView<'a, T> {
566 bytes: &'a [u8],
567 _marker: core::marker::PhantomData<fn() -> T>,
568}
569
570impl<'a, T: LeDecode> LeSliceView<'a, T> {
571 #[inline]
574 pub fn new(bytes: &'a [u8]) -> Self {
575 Self {
576 bytes,
577 _marker: core::marker::PhantomData,
578 }
579 }
580
581 #[inline]
583 pub fn len(&self) -> usize {
584 self.bytes.len() / T::SIZE
585 }
586
587 #[inline]
589 pub fn is_empty(&self) -> bool {
590 self.bytes.is_empty()
591 }
592
593 #[inline]
595 pub fn as_bytes(&self) -> &'a [u8] {
596 self.bytes
597 }
598
599 #[inline]
601 pub fn get(&self, index: usize) -> Option<T> {
602 let start = index.checked_mul(T::SIZE)?;
603 let end = start.checked_add(T::SIZE)?;
604 self.bytes.get(start..end).map(T::from_le)
605 }
606
607 #[inline]
609 pub fn iter(&self) -> impl Iterator<Item = T> + 'a {
610 let bytes = self.bytes;
611 (0..bytes.len() / T::SIZE).map(move |i| T::from_le(&bytes[i * T::SIZE..(i + 1) * T::SIZE]))
612 }
613}
614
615#[cfg(test)]
616mod tests {
617 use super::*;
618
619 #[test]
620 fn test_write_read_u8() {
621 let mut buf = [0u8; 16];
622 let mut writer = CdrWriter::new(&mut buf);
623 writer.write_u8(0x42).unwrap();
624 writer.write_u8(0xFF).unwrap();
625
626 let mut reader = CdrReader::new(&buf);
627 assert_eq!(reader.read_u8().unwrap(), 0x42);
628 assert_eq!(reader.read_u8().unwrap(), 0xFF);
629 }
630
631 #[test]
632 fn le_slice_view_decodes_unaligned_f32() {
633 let vals = [1.5f32, -2.25, 3.0e10, 0.0];
636 let mut backing = [0u8; 1 + 4 * 4];
637 backing[0] = 0xAA; for (i, v) in vals.iter().enumerate() {
639 backing[1 + i * 4..1 + i * 4 + 4].copy_from_slice(&v.to_le_bytes());
640 }
641 let view: LeSliceView<f32> = LeSliceView::new(&backing[1..]);
642 assert_eq!(view.len(), 4);
643 assert!(!view.is_empty());
644 for (i, v) in vals.iter().enumerate() {
645 assert_eq!(view.get(i).unwrap(), *v);
646 }
647 assert_eq!(view.get(4), None);
648 let collected: heapless::Vec<f32, 4> = view.iter().collect();
649 assert_eq!(&collected[..], &vals[..]);
650 }
651
652 #[test]
653 fn read_le_slice_roundtrips_through_cdr() {
654 let vals = [10u16, 4000, 65535, 1];
657 let mut buf = [0u8; 64];
658 let written = {
659 let mut w = CdrWriter::new_with_header(&mut buf).unwrap();
660 w.write_sequence_len(vals.len()).unwrap();
661 for v in &vals {
662 w.write_u16(*v).unwrap();
663 }
664 w.position()
665 };
666 let mut reader = CdrReader::new_with_header(&buf[..written]).unwrap();
667 let view = reader.read_le_slice::<u16>().unwrap();
668 assert_eq!(view.len(), vals.len());
669 for (i, v) in vals.iter().enumerate() {
670 assert_eq!(view.get(i).unwrap(), *v);
671 }
672 }
673
674 #[test]
675 fn test_write_read_u32_alignment() {
676 let mut buf = [0u8; 16];
677 let mut writer = CdrWriter::new(&mut buf);
678 writer.write_u8(0x01).unwrap(); writer.write_u32(0x12345678).unwrap(); assert_eq!(writer.position(), 8); let mut reader = CdrReader::new(&buf);
684 assert_eq!(reader.read_u8().unwrap(), 0x01);
685 assert_eq!(reader.read_u32().unwrap(), 0x12345678);
686 }
687
688 #[test]
689 fn test_write_read_string() {
690 let mut buf = [0u8; 32];
691 let mut writer = CdrWriter::new(&mut buf);
692 writer.write_string("Hello").unwrap();
693
694 let mut reader = CdrReader::new(&buf);
695 assert_eq!(reader.read_string().unwrap(), "Hello");
696 }
697
698 #[test]
699 fn test_encapsulation_header() {
700 let mut buf = [0u8; 32];
701 let mut writer = CdrWriter::new_with_header(&mut buf).unwrap();
702 writer.write_u32(42).unwrap();
703
704 assert_eq!(&buf[0..4], &CDR_LE_HEADER);
705
706 let mut reader = CdrReader::new_with_header(&buf).unwrap();
707 assert_eq!(reader.read_u32().unwrap(), 42);
708 }
709
710 #[test]
711 fn test_alignment_with_header() {
712 let mut buf = [0u8; 32];
713 let mut writer = CdrWriter::new_with_header(&mut buf).unwrap();
714 writer.write_u8(0x01).unwrap(); writer.write_u32(0xDEADBEEF).unwrap(); assert_eq!(writer.position(), 12); let mut reader = CdrReader::new_with_header(&buf).unwrap();
721 assert_eq!(reader.read_u8().unwrap(), 0x01);
722 assert_eq!(reader.read_u32().unwrap(), 0xDEADBEEF);
723 }
724}
725
726#[cfg(test)]
731mod ghost_checks {
732 use super::*;
733 use nros_ghost_types::CdrGhost;
734
735 fn ghost_from_writer(w: &CdrWriter) -> CdrGhost {
738 CdrGhost {
739 buf_len: w.buf.len(),
740 pos: w.pos,
741 origin: w.origin,
742 }
743 }
744
745 #[test]
746 fn ghost_new_state() {
747 let mut buf = [0u8; 64];
748 let writer = CdrWriter::new(&mut buf);
749 let ghost = ghost_from_writer(&writer);
750 assert_eq!(ghost.pos, 0);
751 assert_eq!(ghost.origin, 0);
752 assert_eq!(ghost.buf_len, 64);
753 }
754
755 #[test]
756 fn ghost_header_origin() {
757 let mut buf = [0u8; 64];
758 let writer = CdrWriter::new_with_header(&mut buf).unwrap();
759 let ghost = ghost_from_writer(&writer);
760 assert_eq!(ghost.pos, 4);
761 assert_eq!(ghost.origin, 4);
762 }
763
764 #[test]
765 fn ghost_position_invariant() {
766 let mut buf = [0u8; 64];
767 let mut writer = CdrWriter::new_with_header(&mut buf).unwrap();
768 writer.write_u32(42).unwrap();
769 let ghost = ghost_from_writer(&writer);
770 assert_eq!(ghost.pos + writer.remaining(), ghost.buf_len);
772 }
773
774 #[test]
775 fn test_read_slice_u8() {
776 let mut buf = [0u8; 64];
777 let mut writer = CdrWriter::new_with_header(&mut buf).unwrap();
778 writer.write_u32(3).unwrap(); writer.write_u8(0x10).unwrap();
781 writer.write_u8(0x20).unwrap();
782 writer.write_u8(0x30).unwrap();
783 let len = writer.position();
784
785 let mut reader = CdrReader::new_with_header(&buf[..len]).unwrap();
786 let slice = reader.read_slice_u8().unwrap();
787 assert_eq!(slice, &[0x10, 0x20, 0x30]);
788 }
789
790 #[test]
791 fn test_read_slice_u8_empty() {
792 let mut buf = [0u8; 64];
793 let mut writer = CdrWriter::new_with_header(&mut buf).unwrap();
794 writer.write_u32(0).unwrap(); let len = writer.position();
796
797 let mut reader = CdrReader::new_with_header(&buf[..len]).unwrap();
798 let slice = reader.read_slice_u8().unwrap();
799 assert!(slice.is_empty());
800 }
801
802 #[test]
803 fn test_read_slice_f32_raw() {
804 let mut buf = [0u8; 64];
805 let mut writer = CdrWriter::new_with_header(&mut buf).unwrap();
806 writer.write_u32(2).unwrap(); writer.write_f32(1.0).unwrap();
809 writer.write_f32(2.5).unwrap();
810 let len = writer.position();
811
812 let mut reader = CdrReader::new_with_header(&buf[..len]).unwrap();
813 let (bytes, count) = reader.read_slice_f32_raw().unwrap();
814 assert_eq!(count, 2);
815 assert_eq!(bytes.len(), 8); assert_eq!(
818 f32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]),
819 1.0
820 );
821 }
822}
823
824#[cfg(kani)]
829mod verification {
830 use super::*;
831
832 #[kani::proof]
835 #[kani::unwind(5)]
836 fn cdr_write_u8_no_panic() {
837 let mut buf = [0u8; 8];
838 let mut writer = CdrWriter::new(&mut buf);
839 let val: u8 = kani::any();
840 let _ = writer.write_u8(val);
841 }
842
843 #[kani::proof]
844 #[kani::unwind(5)]
845 fn cdr_write_bool_no_panic() {
846 let mut buf = [0u8; 8];
847 let mut writer = CdrWriter::new(&mut buf);
848 let val: bool = kani::any();
849 let _ = writer.write_bool(val);
850 }
851
852 #[kani::proof]
853 #[kani::unwind(5)]
854 fn cdr_write_i16_no_panic() {
855 let mut buf = [0u8; 16];
856 let mut writer = CdrWriter::new(&mut buf);
857 let val: i16 = kani::any();
858 let _ = writer.write_i16(val);
859 }
860
861 #[kani::proof]
862 #[kani::unwind(5)]
863 fn cdr_write_i32_no_panic() {
864 let mut buf = [0u8; 16];
865 let mut writer = CdrWriter::new(&mut buf);
866 let val: i32 = kani::any();
867 let _ = writer.write_i32(val);
868 }
869
870 #[kani::proof]
871 #[kani::unwind(5)]
872 fn cdr_write_i64_no_panic() {
873 let mut buf = [0u8; 16];
874 let mut writer = CdrWriter::new(&mut buf);
875 let val: i64 = kani::any();
876 let _ = writer.write_i64(val);
877 }
878
879 #[kani::proof]
880 #[kani::unwind(5)]
881 fn cdr_write_f32_no_panic() {
882 let mut buf = [0u8; 16];
883 let mut writer = CdrWriter::new(&mut buf);
884 let val: f32 = kani::any();
885 let _ = writer.write_f32(val);
886 }
887
888 #[kani::proof]
889 #[kani::unwind(5)]
890 fn cdr_write_f64_no_panic() {
891 let mut buf = [0u8; 16];
892 let mut writer = CdrWriter::new(&mut buf);
893 let val: f64 = kani::any();
894 let _ = writer.write_f64(val);
895 }
896
897 #[kani::proof]
900 #[kani::unwind(5)]
901 fn cdr_roundtrip_u8() {
902 let mut buf = [0u8; 8];
903 let val: u8 = kani::any();
904 let len = {
905 let mut writer = CdrWriter::new(&mut buf);
906 writer.write_u8(val).unwrap();
907 writer.position()
908 };
909 let mut reader = CdrReader::new(&buf[..len]);
910 assert_eq!(reader.read_u8().unwrap(), val);
911 }
912
913 #[kani::proof]
914 #[kani::unwind(5)]
915 fn cdr_roundtrip_bool() {
916 let mut buf = [0u8; 8];
917 let val: bool = kani::any();
918 let len = {
919 let mut writer = CdrWriter::new(&mut buf);
920 writer.write_bool(val).unwrap();
921 writer.position()
922 };
923 let mut reader = CdrReader::new(&buf[..len]);
924 assert_eq!(reader.read_bool().unwrap(), val);
925 }
926
927 #[kani::proof]
928 #[kani::unwind(5)]
929 fn cdr_roundtrip_i16() {
930 let mut buf = [0u8; 16];
931 let val: i16 = kani::any();
932 let len = {
933 let mut writer = CdrWriter::new(&mut buf);
934 writer.write_i16(val).unwrap();
935 writer.position()
936 };
937 let mut reader = CdrReader::new(&buf[..len]);
938 assert_eq!(reader.read_i16().unwrap(), val);
939 }
940
941 #[kani::proof]
942 #[kani::unwind(5)]
943 fn cdr_roundtrip_i32() {
944 let mut buf = [0u8; 16];
945 let val: i32 = kani::any();
946 let len = {
947 let mut writer = CdrWriter::new(&mut buf);
948 writer.write_i32(val).unwrap();
949 writer.position()
950 };
951 let mut reader = CdrReader::new(&buf[..len]);
952 assert_eq!(reader.read_i32().unwrap(), val);
953 }
954
955 #[kani::proof]
956 #[kani::unwind(5)]
957 fn cdr_roundtrip_i64() {
958 let mut buf = [0u8; 16];
959 let val: i64 = kani::any();
960 let len = {
961 let mut writer = CdrWriter::new(&mut buf);
962 writer.write_i64(val).unwrap();
963 writer.position()
964 };
965 let mut reader = CdrReader::new(&buf[..len]);
966 assert_eq!(reader.read_i64().unwrap(), val);
967 }
968
969 #[kani::proof]
970 #[kani::unwind(5)]
971 fn cdr_roundtrip_f32() {
972 let mut buf = [0u8; 16];
973 let val: f32 = kani::any();
974 let len = {
975 let mut writer = CdrWriter::new(&mut buf);
976 writer.write_f32(val).unwrap();
977 writer.position()
978 };
979 let mut reader = CdrReader::new(&buf[..len]);
980 let result = reader.read_f32().unwrap();
981 assert_eq!(val.to_bits(), result.to_bits());
982 }
983
984 #[kani::proof]
985 #[kani::unwind(5)]
986 fn cdr_roundtrip_f64() {
987 let mut buf = [0u8; 16];
988 let val: f64 = kani::any();
989 let len = {
990 let mut writer = CdrWriter::new(&mut buf);
991 writer.write_f64(val).unwrap();
992 writer.position()
993 };
994 let mut reader = CdrReader::new(&buf[..len]);
995 let result = reader.read_f64().unwrap();
996 assert_eq!(val.to_bits(), result.to_bits());
997 }
998
999 #[kani::proof]
1002 #[kani::unwind(5)]
1003 fn cdr_roundtrip_with_header_i32() {
1004 let mut buf = [0u8; 16];
1005 let val: i32 = kani::any();
1006 let len = {
1007 let mut writer = CdrWriter::new_with_header(&mut buf).unwrap();
1008 writer.write_i32(val).unwrap();
1009 writer.position()
1010 };
1011 let mut reader = CdrReader::new_with_header(&buf[..len]).unwrap();
1012 assert_eq!(reader.read_i32().unwrap(), val);
1013 }
1014
1015 #[kani::proof]
1018 #[kani::unwind(5)]
1019 fn cdr_write_buffer_exhaustion_u32() {
1020 let mut buf = [0u8; 3]; let mut writer = CdrWriter::new(&mut buf);
1022 let val: u32 = kani::any();
1023 let result = writer.write_u32(val);
1024 assert!(result.is_err());
1025 }
1026
1027 #[kani::proof]
1028 #[kani::unwind(5)]
1029 fn cdr_write_header_buffer_too_small() {
1030 let mut buf = [0u8; 3]; let result = CdrWriter::new_with_header(&mut buf);
1032 assert!(result.is_err());
1033 }
1034
1035 #[kani::proof]
1038 #[kani::unwind(5)]
1039 fn cdr_deserialize_arbitrary_bytes_i32() {
1040 let mut buf = [0u8; 8];
1041 buf[0] = kani::any();
1042 buf[1] = kani::any();
1043 buf[2] = kani::any();
1044 buf[3] = kani::any();
1045 buf[4] = kani::any();
1046 buf[5] = kani::any();
1047 buf[6] = kani::any();
1048 buf[7] = kani::any();
1049 let result = CdrReader::new_with_header(&buf);
1050 if let Ok(mut reader) = result {
1051 let _ = reader.read_i32(); }
1053 }
1054
1055 #[kani::proof]
1056 #[kani::unwind(5)]
1057 fn cdr_deserialize_empty_buffer() {
1058 let buf = [0u8; 0];
1059 let mut reader = CdrReader::new(&buf);
1060 assert!(reader.read_u8().is_err());
1061 assert!(reader.read_u32().is_err());
1062 }
1063
1064 #[kani::proof]
1067 fn cdr_alignment_no_overflow() {
1068 let offset: usize = kani::any();
1069 let alignment: usize = kani::any();
1070 kani::assume(alignment > 0 && alignment <= 8);
1071 kani::assume(offset <= 1024); let padding = (alignment - (offset % alignment)) % alignment;
1073 let aligned = offset + padding;
1074 assert!(aligned % alignment == 0);
1075 assert!(aligned >= offset);
1076 assert!(aligned < offset + alignment);
1077 }
1078
1079 #[kani::proof]
1082 #[kani::unwind(5)]
1083 fn cdr_writer_position_monotonic() {
1084 let mut buf = [0u8; 32];
1085 let mut writer = CdrWriter::new(&mut buf);
1086 let pos0 = writer.position();
1087
1088 let val: u8 = kani::any();
1089 if writer.write_u8(val).is_ok() {
1090 assert!(writer.position() > pos0);
1091 }
1092 }
1093
1094 #[kani::proof]
1095 #[kani::unwind(5)]
1096 fn cdr_writer_remaining_consistent() {
1097 const BUF_LEN: usize = 32;
1098 let mut buf = [0u8; BUF_LEN];
1099 let mut writer = CdrWriter::new(&mut buf);
1100 assert_eq!(writer.position() + writer.remaining(), BUF_LEN);
1101
1102 let val: u32 = kani::any();
1103 let _ = writer.write_u32(val);
1104 assert_eq!(writer.position() + writer.remaining(), BUF_LEN);
1105 }
1106}