Skip to main content

commonware_codec/types/
primitives.rs

1//! Codec implementations for Rust primitive types.
2//!
3//! # Fixed-size vs Variable-size
4//!
5//! Most primitives therefore have a compile-time constant `SIZE` and can be
6//! encoded/decoded without any configuration.
7//!
8//! `usize` is the lone exception: since most values refer to a length or size
9//! of an object in memory, values are biased towards smaller values. Therefore,
10//! it uses variable-length (varint) encoding to save space.  This means that
11//! it **does not implement [FixedSize]**.  When decoding a `usize`, callers
12//! must supply a [RangeCfg] to bound the allowable value — this protects
13//! against denial-of-service attacks that would allocate oversized buffers.
14//!
15//! ## Safety & portability
16//! * `usize` is restricted to values that fit in a `u32` to keep the on-wire
17//!   format identical across 32-bit and 64-bit architectures.
18//! * All fixed-size integers and floats are written big-endian to avoid host-
19//!   endian ambiguity.
20
21use crate::{
22    BufsMut, EncodeSize, Error, FixedSize, RangeCfg, Read, ReadExt, Write,
23    util::{at_least, at_least_items, read_fixed_vec},
24    varint::UInt,
25};
26#[cfg(not(feature = "std"))]
27use alloc::{vec, vec::Vec};
28use bytes::{Buf, BufMut};
29use core::num::{NonZeroU16, NonZeroU32, NonZeroU64};
30#[cfg(feature = "std")]
31use std::vec::Vec;
32
33// Numeric types implementation
34macro_rules! impl_numeric {
35    ($type:ty, $read_method:ident, $write_method:ident) => {
36        impl Write for $type {
37            #[inline]
38            fn write(&self, buf: &mut impl BufMut) {
39                buf.$write_method(*self);
40            }
41        }
42
43        impl Read for $type {
44            type Cfg = ();
45            #[inline]
46            fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, Error> {
47                at_least(buf, core::mem::size_of::<$type>())?;
48                Ok(buf.$read_method())
49            }
50
51            // Since the upfront size check guarantees the buffer contains every requested
52            // value, elements are read directly without per-element bounds checks.
53            #[inline]
54            fn read_vec(buf: &mut impl Buf, len: usize, _: &()) -> Result<Vec<Self>, Error> {
55                at_least_items(buf, len, Self::SIZE)?;
56                let mut values = Vec::with_capacity(len);
57                for _ in 0..len {
58                    values.push(buf.$read_method());
59                }
60                Ok(values)
61            }
62
63            #[inline]
64            fn read_array<const N: usize>(buf: &mut impl Buf, _: &()) -> Result<[Self; N], Error> {
65                at_least_items(buf, N, Self::SIZE)?;
66                Ok(core::array::from_fn(|_| buf.$read_method()))
67            }
68        }
69
70        impl FixedSize for $type {
71            const SIZE: usize = core::mem::size_of::<$type>();
72        }
73    };
74}
75
76impl_numeric!(u16, get_u16, put_u16);
77impl_numeric!(u32, get_u32, put_u32);
78impl_numeric!(u64, get_u64, put_u64);
79impl_numeric!(u128, get_u128, put_u128);
80impl_numeric!(i8, get_i8, put_i8);
81impl_numeric!(i16, get_i16, put_i16);
82impl_numeric!(i32, get_i32, put_i32);
83impl_numeric!(i64, get_i64, put_i64);
84impl_numeric!(i128, get_i128, put_i128);
85impl_numeric!(f32, get_f32, put_f32);
86impl_numeric!(f64, get_f64, put_f64);
87
88impl Write for u8 {
89    #[inline]
90    fn write(&self, buf: &mut impl BufMut) {
91        buf.put_u8(*self);
92    }
93
94    #[inline]
95    fn write_slice(values: &[Self], buf: &mut impl BufMut) {
96        buf.put_slice(values);
97    }
98
99    #[inline]
100    fn write_slice_bufs(values: &[Self], buf: &mut impl BufsMut) {
101        buf.put_slice(values);
102    }
103}
104
105impl Read for u8 {
106    type Cfg = ();
107
108    #[inline]
109    fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, Error> {
110        at_least(buf, 1)?;
111        Ok(buf.get_u8())
112    }
113
114    #[inline]
115    fn read_vec(buf: &mut impl Buf, len: usize, _: &()) -> Result<Vec<Self>, Error> {
116        at_least(buf, len)?;
117        let mut values = vec![0; len];
118        buf.copy_to_slice(&mut values);
119        Ok(values)
120    }
121
122    #[inline]
123    fn read_array<const N: usize>(buf: &mut impl Buf, _: &()) -> Result<[Self; N], Error> {
124        at_least(buf, N)?;
125        let mut values = [0; N];
126        buf.copy_to_slice(&mut values);
127        Ok(values)
128    }
129}
130
131impl FixedSize for u8 {
132    const SIZE: usize = 1;
133}
134
135macro_rules! impl_nonzero {
136    ($nz:ty, $inner:ty, $name:expr) => {
137        impl Write for $nz {
138            #[inline]
139            fn write(&self, buf: &mut impl BufMut) {
140                self.get().write(buf);
141            }
142        }
143
144        impl Read for $nz {
145            type Cfg = ();
146            #[inline]
147            fn read_cfg(buf: &mut impl Buf, cfg: &()) -> Result<Self, Error> {
148                let v = <$inner>::read_cfg(buf, cfg)?;
149                <$nz>::new(v).ok_or(Error::Invalid($name, "value must not be zero"))
150            }
151
152            #[inline]
153            fn read_vec(buf: &mut impl Buf, len: usize, cfg: &()) -> Result<Vec<Self>, Error> {
154                read_fixed_vec(buf, len, cfg)
155            }
156        }
157
158        impl FixedSize for $nz {
159            const SIZE: usize = <$inner as FixedSize>::SIZE;
160        }
161    };
162}
163
164impl_nonzero!(NonZeroU16, u16, "NonZeroU16");
165impl_nonzero!(NonZeroU32, u32, "NonZeroU32");
166impl_nonzero!(NonZeroU64, u64, "NonZeroU64");
167
168// Usize implementation
169impl Write for usize {
170    #[inline]
171    fn write(&self, buf: &mut impl BufMut) {
172        let self_as_u32 = u32::try_from(*self).expect("write: usize value is larger than u32");
173        UInt(self_as_u32).write(buf);
174    }
175}
176
177impl Read for usize {
178    type Cfg = RangeCfg<Self>;
179
180    #[inline]
181    fn read_cfg(buf: &mut impl Buf, range: &Self::Cfg) -> Result<Self, Error> {
182        let self_as_u32: u32 = UInt::read(buf)?.into();
183        let result = Self::try_from(self_as_u32).map_err(|_| Error::InvalidUsize)?;
184        if !range.contains(&result) {
185            return Err(Error::InvalidLength(result));
186        }
187        Ok(result)
188    }
189}
190
191impl EncodeSize for usize {
192    #[inline]
193    fn encode_size(&self) -> usize {
194        let self_as_u32 =
195            u32::try_from(*self).expect("encode_size: usize value is larger than u32");
196        UInt(self_as_u32).encode_size()
197    }
198}
199
200// Bool implementation
201impl Write for bool {
202    #[inline]
203    fn write(&self, buf: &mut impl BufMut) {
204        buf.put_u8(if *self { 1 } else { 0 });
205    }
206}
207
208impl Read for bool {
209    type Cfg = ();
210    #[inline]
211    fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, Error> {
212        match u8::read(buf)? {
213            0 => Ok(false),
214            1 => Ok(true),
215            _ => Err(Error::InvalidBool),
216        }
217    }
218}
219
220impl FixedSize for bool {
221    const SIZE: usize = 1;
222}
223
224// Arrays can always be written and read when their element can. This gives arrays
225// with variable-size elements `Write`, `Read`, and therefore `Decode`, but not
226// `Encode`. A generic `EncodeSize for [T; N]` would overlap with the blanket
227// `EncodeSize` implementation for all `FixedSize` types, so only arrays whose
228// elements are fixed-size become `FixedSize` and therefore `Encode`/`Codec`.
229impl<T: Write, const N: usize> Write for [T; N] {
230    #[inline]
231    fn write(&self, buf: &mut impl BufMut) {
232        T::write_slice(self, buf);
233    }
234
235    #[inline]
236    fn write_bufs(&self, buf: &mut impl BufsMut) {
237        T::write_slice_bufs(self, buf);
238    }
239}
240
241impl<T: Read, const N: usize> Read for [T; N] {
242    type Cfg = T::Cfg;
243
244    #[inline]
245    fn read_cfg(buf: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
246        T::read_array(buf, cfg)
247    }
248}
249
250impl<T: FixedSize, const N: usize> FixedSize for [T; N] {
251    const SIZE: usize = T::SIZE * N;
252}
253
254// Option implementation
255impl<T: Write> Write for Option<T> {
256    #[inline]
257    fn write(&self, buf: &mut impl BufMut) {
258        self.is_some().write(buf);
259        if let Some(inner) = self {
260            inner.write(buf);
261        }
262    }
263
264    #[inline]
265    fn write_bufs(&self, buf: &mut impl BufsMut) {
266        self.is_some().write(buf);
267        if let Some(inner) = self {
268            inner.write_bufs(buf);
269        }
270    }
271}
272
273impl<T: EncodeSize> EncodeSize for Option<T> {
274    #[inline]
275    fn encode_size(&self) -> usize {
276        self.as_ref().map_or(1, |inner| 1 + inner.encode_size())
277    }
278
279    #[inline]
280    fn encode_inline_size(&self) -> usize {
281        self.as_ref()
282            .map_or(1, |inner| 1 + inner.encode_inline_size())
283    }
284}
285
286impl<T: Read> Read for Option<T> {
287    type Cfg = T::Cfg;
288
289    #[inline]
290    fn read_cfg(buf: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
291        if bool::read(buf)? {
292            Ok(Some(T::read_cfg(buf, cfg)?))
293        } else {
294            Ok(None)
295        }
296    }
297}
298
299#[cfg(test)]
300mod tests {
301    use super::{
302        super::tests::{Byte, TrackingReadBuf, TrackingWriteBuf},
303        *,
304    };
305    use crate::{CodecFixed, Decode, DecodeExt, Encode, EncodeFixed};
306    use bytes::{Buf, Bytes, BytesMut};
307    use paste::paste;
308
309    // Float tests
310    macro_rules! impl_num_test {
311        ($type:ty, $size:expr) => {
312            paste! {
313                #[test]
314                fn [<test_ $type>]() {
315                    let expected_len = core::mem::size_of::<$type>();
316                    let values: [$type; 5] =
317                        [0 as $type, 1 as $type, 42 as $type, <$type>::MAX, <$type>::MIN];
318                    for value in values.iter() {
319                        let encoded = value.encode();
320                        assert_eq!(encoded.len(), expected_len);
321                        let decoded = <$type>::decode(encoded).unwrap();
322                        assert_eq!(*value, decoded);
323                        assert_eq!(value.encode_size(), expected_len);
324
325                        let fixed: [u8; $size] = value.encode_fixed();
326                        assert_eq!(fixed.len(), expected_len);
327                        let decoded = <$type>::decode(Bytes::copy_from_slice(&fixed)).unwrap();
328                        assert_eq!(*value, decoded);
329                    }
330                }
331            }
332        };
333    }
334    impl_num_test!(u8, 1);
335    impl_num_test!(u16, 2);
336    impl_num_test!(u32, 4);
337    impl_num_test!(u64, 8);
338    impl_num_test!(u128, 16);
339    impl_num_test!(i8, 1);
340    impl_num_test!(i16, 2);
341    impl_num_test!(i32, 4);
342    impl_num_test!(i64, 8);
343    impl_num_test!(i128, 16);
344    impl_num_test!(f32, 4);
345    impl_num_test!(f64, 8);
346
347    #[test]
348    fn test_endianness() {
349        // u16
350        let encoded = 0x0102u16.encode();
351        assert_eq!(encoded, Bytes::from_static(&[0x01, 0x02]));
352
353        // u32
354        let encoded = 0x01020304u32.encode();
355        assert_eq!(encoded, Bytes::from_static(&[0x01, 0x02, 0x03, 0x04]));
356
357        // f32
358        let encoded = 1.0f32.encode();
359        assert_eq!(encoded, Bytes::from_static(&[0x3F, 0x80, 0x00, 0x00])); // Big-endian IEEE 754
360    }
361
362    #[test]
363    fn test_numeric_read_vec_bounds() {
364        // A length whose byte size exceeds the buffer fails before decoding any elements.
365        let mut buf = [0u8; 8].as_slice();
366        assert!(matches!(
367            u64::read_vec(&mut buf, 2, &()),
368            Err(Error::EndOfBuffer)
369        ));
370        assert_eq!(buf.remaining(), 8);
371
372        // A length whose byte size overflows usize fails the same way.
373        let mut buf = [0u8; 8].as_slice();
374        assert!(matches!(
375            u64::read_vec(&mut buf, usize::MAX, &()),
376            Err(Error::EndOfBuffer)
377        ));
378
379        // A valid read decodes big-endian values and consumes the exact bytes.
380        let mut buf = [0x00, 0x01, 0x00, 0x02, 0x00, 0x03].as_slice();
381        assert_eq!(u16::read_vec(&mut buf, 2, &()).unwrap(), vec![1u16, 2]);
382        assert_eq!(buf.remaining(), 2);
383    }
384
385    #[test]
386    fn test_numeric_read_array_bounds() {
387        let mut buf = [0u8; 8].as_slice();
388        assert!(matches!(
389            u64::read_array::<2>(&mut buf, &()),
390            Err(Error::EndOfBuffer)
391        ));
392        assert_eq!(buf.remaining(), 8);
393
394        let mut buf = [0x00, 0x01, 0x00, 0x02].as_slice();
395        assert_eq!(u16::read_array::<2>(&mut buf, &()).unwrap(), [1u16, 2]);
396        assert_eq!(buf.remaining(), 0);
397    }
398
399    #[test]
400    fn test_nonzero_read_vec_bounds() {
401        // The upfront size check rejects a length larger than the buffer.
402        let mut buf = [0u8; 4].as_slice();
403        assert!(matches!(
404            NonZeroU32::read_vec(&mut buf, 2, &()),
405            Err(Error::EndOfBuffer)
406        ));
407        assert_eq!(buf.remaining(), 4);
408
409        // Per-element validation still runs after the size check.
410        let mut buf = [0u8; 4].as_slice();
411        assert!(matches!(
412            NonZeroU32::read_vec(&mut buf, 1, &()),
413            Err(Error::Invalid("NonZeroU32", _))
414        ));
415
416        // A valid read decodes all values.
417        let mut buf = [0, 0, 0, 1, 0, 0, 0, 2].as_slice();
418        assert_eq!(
419            NonZeroU32::read_vec(&mut buf, 2, &()).unwrap(),
420            vec![NonZeroU32::new(1).unwrap(), NonZeroU32::new(2).unwrap()]
421        );
422    }
423
424    #[test]
425    fn test_bool() {
426        let values = [true, false];
427        for value in values.iter() {
428            let encoded = value.encode();
429            assert_eq!(encoded.len(), 1);
430            let decoded = bool::decode(encoded).unwrap();
431            assert_eq!(*value, decoded);
432            assert_eq!(value.encode_size(), 1);
433        }
434    }
435
436    #[test]
437    fn test_usize() {
438        let values = [0usize, 1, 42, u32::MAX as usize];
439        for value in values.iter() {
440            let encoded = value.encode();
441            assert_eq!(value.encode_size(), UInt(*value as u32).encode_size());
442            let decoded = usize::decode_cfg(encoded, &(..).into()).unwrap();
443            assert_eq!(*value, decoded);
444        }
445    }
446
447    #[cfg(target_pointer_width = "64")]
448    #[test]
449    #[should_panic(expected = "encode_size: usize value is larger than u32")]
450    fn test_usize_encode_panic() {
451        let value: usize = usize::MAX;
452        let _ = value.encode();
453    }
454
455    #[test]
456    #[should_panic(expected = "write: usize value is larger than u32")]
457    fn test_usize_write_panic() {
458        let mut buf = &mut BytesMut::new();
459        let value: usize = usize::MAX;
460        value.write(&mut buf);
461    }
462
463    #[test]
464    fn test_array() {
465        // Arrays whose elements are fixed-size get the full `Codec` stack.
466        fn assert_codec_fixed<T: CodecFixed<Cfg = ()>>() {}
467        assert_codec_fixed::<[u8; 3]>();
468        assert_codec_fixed::<[u16; 3]>();
469
470        // `[u8; N]` encodes exactly N payload bytes, with no length prefix.
471        let bytes = [1u8, 2, 3];
472        let encoded = bytes.encode();
473        let decoded = <[u8; 3]>::decode(encoded).unwrap();
474        assert_eq!(bytes, decoded);
475        assert_eq!(<[u8; 3] as FixedSize>::SIZE, 3);
476
477        // Fixed-size array decoding must reject both truncated payloads and trailing data.
478        assert!(matches!(
479            <[u8; 3]>::decode([0x01, 0x02].as_slice()),
480            Err(Error::EndOfBuffer)
481        ));
482        assert!(matches!(
483            <[u8; 3]>::decode([0x01, 0x02, 0x03, 0x04].as_slice()),
484            Err(Error::ExtraData(1))
485        ));
486
487        // Larger fixed-size elements compose normally and preserve big-endian encoding.
488        let words = [0x0102u16, 0x0304u16, 0x0506u16];
489        let encoded = words.encode();
490        assert_eq!(encoded, &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06][..]);
491        let decoded = <[u16; 3]>::decode(encoded).unwrap();
492        assert_eq!(words, decoded);
493        assert_eq!(words.encode_size(), 6);
494        assert_eq!(<[u16; 3] as FixedSize>::SIZE, 6);
495
496        // Nested arrays inherit the same fixed-size encoding from their elements.
497        let nested = [[0x0102u16, 0x0304u16], [0x0506u16, 0x0708u16]];
498        let encoded = nested.encode();
499        assert_eq!(
500            encoded,
501            &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08][..]
502        );
503        let decoded = <[[u16; 2]; 2]>::decode(encoded).unwrap();
504        assert_eq!(nested, decoded);
505
506        // Arrays of configurable elements pass the element config through each read.
507        let decoded =
508            <[usize; 2]>::decode_cfg(Bytes::from_static(&[0x01, 0x02]), &(..).into()).unwrap();
509        assert_eq!(decoded, [1, 2]);
510
511        // Arrays with variable-size elements can still be written and read, even though
512        // they cannot use `Encode` because they do not have a generic `EncodeSize` impl.
513        let variable = [vec![1u8, 2], vec![3u8, 4, 5]];
514        let mut encoded = BytesMut::new();
515        variable.write(&mut encoded);
516        assert_eq!(encoded, &[0x02, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05][..]);
517
518        let mut encoded = encoded.freeze();
519        let decoded = <[Vec<u8>; 2]>::read_cfg(&mut encoded, &((..).into(), ())).unwrap();
520        assert_eq!(variable, decoded);
521        assert_eq!(encoded.remaining(), 0);
522    }
523
524    #[test]
525    fn test_array_specialization_selection() {
526        // `[u8; N]` has no length prefix, so the entire write is one bulk payload write.
527        let mut buf = TrackingWriteBuf::new();
528        [1u8, 2, 3].write(&mut buf);
529        assert_eq!(buf.put_slice_calls, 1);
530        assert_eq!(buf.put_u8_calls, 0);
531
532        // Other array element types keep the generic per-element write path.
533        let mut buf = TrackingWriteBuf::new();
534        [Byte(1), Byte(2), Byte(3)].write(&mut buf);
535        assert_eq!(buf.put_slice_calls, 0);
536        assert_eq!(buf.put_u8_calls, 3);
537
538        // `write_bufs` mirrors `write` for byte arrays.
539        let mut buf = TrackingWriteBuf::new();
540        [1u8, 2, 3].write_bufs(&mut buf);
541        assert_eq!(buf.put_slice_calls, 1);
542        assert_eq!(buf.put_u8_calls, 0);
543        assert_eq!(buf.push_calls, 0);
544
545        // Arrays delegate `write_bufs` to element implementations that push chunks.
546        let mut buf = TrackingWriteBuf::new();
547        [
548            Bytes::from_static(&[1u8, 2, 3]),
549            Bytes::from_static(&[4u8, 5, 6]),
550        ]
551        .write_bufs(&mut buf);
552        assert_eq!(buf.put_slice_calls, 0);
553        assert_eq!(buf.put_u8_calls, 2);
554        assert_eq!(buf.push_calls, 2);
555
556        // `[u8; N]` reads the fixed-size payload with one bulk copy.
557        let mut buf = TrackingReadBuf::new(&[0x01, 0x02, 0x03]);
558        let value = <[u8; 3]>::read_cfg(&mut buf, &()).unwrap();
559        assert_eq!(value, [1, 2, 3]);
560        assert_eq!(buf.copy_to_slice_calls, 1);
561        assert_eq!(buf.get_u8_calls, 0);
562
563        // Other array element types still read one element at a time.
564        let mut buf = TrackingReadBuf::new(&[0x01, 0x02, 0x03]);
565        let value = <[Byte; 3]>::read_cfg(&mut buf, &()).unwrap();
566        assert_eq!(value, [Byte(1), Byte(2), Byte(3)]);
567        assert_eq!(buf.copy_to_slice_calls, 0);
568        assert_eq!(buf.get_u8_calls, 3);
569    }
570
571    #[test]
572    fn test_array_write_bufs_equivalence() {
573        fn assert_equivalent<T: Write>(value: &T) {
574            let mut write = BytesMut::new();
575            value.write(&mut write);
576
577            let mut write_bufs = TrackingWriteBuf::new();
578            value.write_bufs(&mut write_bufs);
579
580            assert_eq!(write.freeze(), write_bufs.freeze());
581        }
582
583        assert_equivalent(&[1u8, 2, 3]);
584        assert_equivalent(&[0x0102u16, 0x0304, 0x0506]);
585        assert_equivalent(&[Byte(1), Byte(2), Byte(3)]);
586        assert_equivalent(&[
587            Bytes::from_static(&[1u8, 2, 3]),
588            Bytes::from_static(&[4u8, 5, 6]),
589        ]);
590    }
591
592    #[test]
593    fn test_option() {
594        let option_values = [Some(42u32), None];
595        for value in option_values {
596            let encoded = value.encode();
597            let decoded = Option::<u32>::decode(encoded).unwrap();
598            assert_eq!(value, decoded);
599        }
600    }
601
602    #[test]
603    fn test_option_length() {
604        let some = Some(42u32);
605        assert_eq!(some.encode_size(), 1 + 4);
606        assert_eq!(some.encode().len(), 1 + 4);
607        let none: Option<u32> = None;
608        assert_eq!(none.encode_size(), 1);
609        assert_eq!(none.encode().len(), 1);
610    }
611
612    #[test]
613    fn test_nonzero_u16() {
614        let values = [
615            NonZeroU16::new(1).unwrap(),
616            NonZeroU16::new(42).unwrap(),
617            NonZeroU16::new(u16::MAX).unwrap(),
618        ];
619        for value in values {
620            let encoded = value.encode();
621            assert_eq!(encoded.len(), 2);
622            let decoded = NonZeroU16::decode(encoded).unwrap();
623            assert_eq!(value, decoded);
624        }
625        assert!(NonZeroU16::decode(0u16.encode()).is_err());
626    }
627
628    #[test]
629    fn test_nonzero_u32() {
630        let values = [
631            NonZeroU32::new(1).unwrap(),
632            NonZeroU32::new(u32::MAX).unwrap(),
633        ];
634        for value in values {
635            let encoded = value.encode();
636            assert_eq!(encoded.len(), 4);
637            let decoded = NonZeroU32::decode(encoded).unwrap();
638            assert_eq!(value, decoded);
639        }
640        assert!(NonZeroU32::decode(0u32.encode()).is_err());
641    }
642
643    #[test]
644    fn test_nonzero_u64() {
645        let values = [
646            NonZeroU64::new(1).unwrap(),
647            NonZeroU64::new(u64::MAX).unwrap(),
648        ];
649        for value in values {
650            let encoded = value.encode();
651            assert_eq!(encoded.len(), 8);
652            let decoded = NonZeroU64::decode(encoded).unwrap();
653            assert_eq!(value, decoded);
654        }
655        assert!(NonZeroU64::decode(0u64.encode()).is_err());
656    }
657
658    #[test]
659    fn test_conformity() {
660        // Bool
661        assert_eq!(true.encode(), &[0x01][..]);
662        assert_eq!(false.encode(), &[0x00][..]);
663
664        // 8-bit integers
665        assert_eq!(0u8.encode(), &[0x00][..]);
666        assert_eq!(255u8.encode(), &[0xFF][..]);
667        assert_eq!(0i8.encode(), &[0x00][..]);
668        assert_eq!((-1i8).encode(), &[0xFF][..]);
669        assert_eq!(127i8.encode(), &[0x7F][..]);
670        assert_eq!((-128i8).encode(), &[0x80][..]);
671
672        // 16-bit integers
673        assert_eq!(0u16.encode(), &[0x00, 0x00][..]);
674        assert_eq!(0xABCDu16.encode(), &[0xAB, 0xCD][..]);
675        assert_eq!(u16::MAX.encode(), &[0xFF, 0xFF][..]);
676        assert_eq!(0i16.encode(), &[0x00, 0x00][..]);
677        assert_eq!((-1i16).encode(), &[0xFF, 0xFF][..]);
678        assert_eq!(0x1234i16.encode(), &[0x12, 0x34][..]);
679
680        // 32-bit integers
681        assert_eq!(0u32.encode(), &[0x00, 0x00, 0x00, 0x00][..]);
682        assert_eq!(0xABCDEF01u32.encode(), &[0xAB, 0xCD, 0xEF, 0x01][..]);
683        assert_eq!(u32::MAX.encode(), &[0xFF, 0xFF, 0xFF, 0xFF][..]);
684        assert_eq!(0i32.encode(), &[0x00, 0x00, 0x00, 0x00][..]);
685        assert_eq!((-1i32).encode(), &[0xFF, 0xFF, 0xFF, 0xFF][..]);
686        assert_eq!(0x12345678i32.encode(), &[0x12, 0x34, 0x56, 0x78][..]);
687
688        // 64-bit integers
689        assert_eq!(
690            0u64.encode(),
691            &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..]
692        );
693        assert_eq!(
694            0x0123456789ABCDEFu64.encode(),
695            &[0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF][..]
696        );
697        assert_eq!(
698            u64::MAX.encode(),
699            &[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF][..]
700        );
701        assert_eq!(
702            0i64.encode(),
703            &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..]
704        );
705        assert_eq!(
706            (-1i64).encode(),
707            &[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF][..]
708        );
709
710        // 128-bit integers
711        let u128_val = 0x0123456789ABCDEF0123456789ABCDEFu128;
712        let u128_bytes = [
713            0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB,
714            0xCD, 0xEF,
715        ];
716        assert_eq!(u128_val.encode(), &u128_bytes[..]);
717        assert_eq!(u128::MAX.encode(), &[0xFF; 16][..]);
718        assert_eq!((-1i128).encode(), &[0xFF; 16][..]);
719
720        assert_eq!(0.0f32.encode(), 0.0f32.to_be_bytes()[..]);
721        assert_eq!(1.0f32.encode(), 1.0f32.to_be_bytes()[..]);
722        assert_eq!((-1.0f32).encode(), (-1.0f32).to_be_bytes()[..]);
723        assert_eq!(f32::MAX.encode(), f32::MAX.to_be_bytes()[..]);
724        assert_eq!(f32::MIN.encode(), f32::MIN.to_be_bytes()[..]);
725        assert_eq!(f32::NAN.encode(), f32::NAN.to_be_bytes()[..]);
726        assert_eq!(f32::INFINITY.encode(), f32::INFINITY.to_be_bytes()[..]);
727        assert_eq!(
728            f32::NEG_INFINITY.encode(),
729            f32::NEG_INFINITY.to_be_bytes()[..]
730        );
731
732        // 32-bit floats
733        assert_eq!(1.0f32.encode(), &[0x3F, 0x80, 0x00, 0x00][..]);
734        assert_eq!((-1.0f32).encode(), &[0xBF, 0x80, 0x00, 0x00][..]);
735
736        // 64-bit floats
737        assert_eq!(0.0f64.encode(), 0.0f64.to_be_bytes()[..]);
738        assert_eq!(1.0f64.encode(), 1.0f64.to_be_bytes()[..]);
739        assert_eq!((-1.0f64).encode(), (-1.0f64).to_be_bytes()[..]);
740        assert_eq!(f64::MAX.encode(), f64::MAX.to_be_bytes()[..]);
741        assert_eq!(f64::MIN.encode(), f64::MIN.to_be_bytes()[..]);
742        assert_eq!(f64::NAN.encode(), f64::NAN.to_be_bytes()[..]);
743        assert_eq!(f64::INFINITY.encode(), f64::INFINITY.to_be_bytes()[..]);
744        assert_eq!(
745            f64::NEG_INFINITY.encode(),
746            f64::NEG_INFINITY.to_be_bytes()[..]
747        );
748        assert_eq!(
749            1.0f64.encode(),
750            &[0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..]
751        );
752        assert_eq!(
753            (-1.0f64).encode(),
754            &[0xBF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00][..]
755        );
756
757        // Fixed-size array
758        assert_eq!([1u8, 2, 3].encode(), &[0x01, 0x02, 0x03][..]);
759        assert_eq!([0u8; 0].encode(), &[][..]);
760
761        // Option
762        assert_eq!(Some(42u32).encode(), &[0x01, 0x00, 0x00, 0x00, 0x2A][..]);
763        assert_eq!(None::<u32>.encode(), &[0][..]);
764
765        // Usize
766        assert_eq!(0usize.encode(), &[0x00][..]);
767        assert_eq!(1usize.encode(), &[0x01][..]);
768        assert_eq!(127usize.encode(), &[0x7F][..]);
769        assert_eq!(128usize.encode(), &[0x80, 0x01][..]);
770        assert_eq!(
771            (u32::MAX as usize).encode(),
772            &[0xFF, 0xFF, 0xFF, 0xFF, 0x0F][..]
773        );
774    }
775
776    #[cfg(feature = "arbitrary")]
777    mod conformance {
778        use crate::conformance::CodecConformance;
779        use core::num::{NonZeroU16, NonZeroU32, NonZeroU64};
780
781        commonware_conformance::conformance_tests! {
782            CodecConformance<u8>,
783            CodecConformance<u16>,
784            CodecConformance<u32>,
785            CodecConformance<u64>,
786            CodecConformance<u128>,
787            CodecConformance<i8>,
788            CodecConformance<i16>,
789            CodecConformance<i32>,
790            CodecConformance<i64>,
791            CodecConformance<i128>,
792            CodecConformance<f32>,
793            CodecConformance<f64>,
794            CodecConformance<bool>,
795            CodecConformance<[u8; 32]>,
796            CodecConformance<Option<u64>>,
797            CodecConformance<NonZeroU16>,
798            CodecConformance<NonZeroU32>,
799            CodecConformance<NonZeroU64>,
800        }
801    }
802}