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