commonware_codec/types/
tuple.rs

1//! Codec implementation for tuples.
2
3use crate::{EncodeSize, Error, Read, Write};
4use bytes::{Buf, BufMut};
5use paste::paste;
6
7// Tuple implementation
8// Each type must have the same configuration type for reading.
9macro_rules! impl_codec_for_tuple {
10    ($($index:literal),*) => {
11        paste! {
12            impl<$( [<T $index>]: EncodeSize ),*> EncodeSize for ( $( [<T $index>], )* ) {
13                #[inline]
14                fn encode_size(&self) -> usize {
15                    0 $( + self.$index.encode_size() )*
16                }
17            }
18
19            impl<$( [<T $index>]: Write ),*> Write for ( $( [<T $index>], )* ) {
20                #[inline]
21                fn write(&self, buf: &mut impl BufMut) {
22                    $( self.$index.write(buf); )*
23                }
24            }
25
26            impl <$( [<T $index>]: Read ),*> Read for ( $( [<T $index>], )* ) {
27                type Cfg = ( $( [<T $index>]::Cfg, )* );
28                #[inline]
29                fn read_cfg(buf: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
30                    Ok(( $( [<T $index>]::read_cfg(buf, &cfg.$index)?, )* ))
31                }
32            }
33        }
34    };
35}
36
37// Generate implementations for tuple sizes 1 through 12
38impl_codec_for_tuple!(0);
39impl_codec_for_tuple!(0, 1);
40impl_codec_for_tuple!(0, 1, 2);
41impl_codec_for_tuple!(0, 1, 2, 3);
42impl_codec_for_tuple!(0, 1, 2, 3, 4);
43impl_codec_for_tuple!(0, 1, 2, 3, 4, 5);
44impl_codec_for_tuple!(0, 1, 2, 3, 4, 5, 6);
45impl_codec_for_tuple!(0, 1, 2, 3, 4, 5, 6, 7);
46impl_codec_for_tuple!(0, 1, 2, 3, 4, 5, 6, 7, 8);
47impl_codec_for_tuple!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
48impl_codec_for_tuple!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
49impl_codec_for_tuple!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
50
51#[cfg(test)]
52mod tests {
53    use crate::{DecodeExt, Encode};
54
55    #[test]
56    fn test_tuple() {
57        let tuple_values = [(1u16, None), (1u16, Some(2u32))];
58        for value in tuple_values {
59            let encoded = value.encode();
60            let decoded = <(u16, Option<u32>)>::decode(encoded).unwrap();
61            assert_eq!(value, decoded);
62        }
63    }
64
65    #[test]
66    fn test_conformity() {
67        let t1 = (true, 0x42u8);
68        assert_eq!(t1.encode(), &[0x01, 0x42][..]);
69
70        let t2 = (0xABCDu16, false, 0xDEADBEEFu32);
71        assert_eq!(t2.encode(), &[0xAB, 0xCD, 0x00, 0xDE, 0xAD, 0xBE, 0xEF][..]);
72
73        let t3 = ((0x01u8, 0x02u8), 0x03u8); // Nested tuple
74        assert_eq!(t3.encode(), &[0x01, 0x02, 0x03][..]);
75
76        let t_option_some = (Some(0x1234u16), 0xFFu8);
77        // Some -> 0x01
78        // 0x1234u16 -> 0x12, 0x34
79        // 0xFFu8 -> 0xFF
80        assert_eq!(t_option_some.encode(), &[0x01, 0x12, 0x34, 0xFF][..]);
81
82        let t_option_none = (0xFFu8, Option::<u16>::None);
83        // 0xFFu8 -> 0xFF
84        // None -> 0x00
85        assert_eq!(t_option_none.encode(), &[0xFF, 0x00][..]);
86    }
87}