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