Skip to main content

commonware_codec/types/
tuple.rs

1//! Codec implementation for tuples.
2
3use crate::{Buf, BufsMut, EncodeSize, Error, MaxEncodeSize, Read, Write};
4use bytes::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                #[inline]
19                fn encode_inline_size(&self) -> usize {
20                    0 $( + self.$index.encode_inline_size() )*
21                }
22            }
23
24            impl<$( [<T $index>]: Write ),*> Write for ( $( [<T $index>], )* ) {
25                #[inline]
26                fn write(&self, buf: &mut impl BufMut) {
27                    $( self.$index.write(buf); )*
28                }
29
30                #[inline]
31                fn write_bufs(&self, buf: &mut impl BufsMut) {
32                    $( self.$index.write_bufs(buf); )*
33                }
34            }
35
36            impl<$( [<T $index>]: MaxEncodeSize ),*> MaxEncodeSize for ( $( [<T $index>], )* ) {
37                const MAX_ENCODE_SIZE: usize = 0 $( + [<T $index>]::MAX_ENCODE_SIZE )*;
38            }
39
40            impl <$( [<T $index>]: Read ),*> Read for ( $( [<T $index>], )* ) {
41                type Cfg = ( $( [<T $index>]::Cfg, )* );
42                #[inline]
43                fn read_cfg(buf: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
44                    Ok(( $( [<T $index>]::read_cfg(buf, &cfg.$index)?, )* ))
45                }
46            }
47        }
48    };
49}
50
51// Generate implementations for tuple sizes 1 through 12
52impl_codec_for_tuple!(0);
53impl_codec_for_tuple!(0, 1);
54impl_codec_for_tuple!(0, 1, 2);
55impl_codec_for_tuple!(0, 1, 2, 3);
56impl_codec_for_tuple!(0, 1, 2, 3, 4);
57impl_codec_for_tuple!(0, 1, 2, 3, 4, 5);
58impl_codec_for_tuple!(0, 1, 2, 3, 4, 5, 6);
59impl_codec_for_tuple!(0, 1, 2, 3, 4, 5, 6, 7);
60impl_codec_for_tuple!(0, 1, 2, 3, 4, 5, 6, 7, 8);
61impl_codec_for_tuple!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
62impl_codec_for_tuple!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
63impl_codec_for_tuple!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
64
65#[cfg(test)]
66mod tests {
67    use crate::{DecodeExt, Encode, MaxEncodeSize};
68
69    #[test]
70    fn test_tuple() {
71        let tuple_values = [(1u16, None), (1u16, Some(2u32))];
72        for value in tuple_values {
73            let encoded = value.encode();
74            let decoded = <(u16, Option<u32>)>::decode(encoded).unwrap();
75            assert_eq!(value, decoded);
76        }
77        assert_eq!(
78            <(u16, Option<u32>)>::MAX_ENCODE_SIZE,
79            (1u16, Some(2u32)).encode().len()
80        );
81    }
82
83    #[test]
84    fn test_conformity() {
85        let t1 = (true, 0x42u8);
86        assert_eq!(t1.encode(), &[0x01, 0x42][..]);
87
88        let t2 = (0xABCDu16, false, 0xDEADBEEFu32);
89        assert_eq!(t2.encode(), &[0xAB, 0xCD, 0x00, 0xDE, 0xAD, 0xBE, 0xEF][..]);
90
91        let t3 = ((0x01u8, 0x02u8), 0x03u8); // Nested tuple
92        assert_eq!(t3.encode(), &[0x01, 0x02, 0x03][..]);
93
94        let t_option_some = (Some(0x1234u16), 0xFFu8);
95        // Some -> 0x01
96        // 0x1234u16 -> 0x12, 0x34
97        // 0xFFu8 -> 0xFF
98        assert_eq!(t_option_some.encode(), &[0x01, 0x12, 0x34, 0xFF][..]);
99
100        let t_option_none = (0xFFu8, Option::<u16>::None);
101        // 0xFFu8 -> 0xFF
102        // None -> 0x00
103        assert_eq!(t_option_none.encode(), &[0xFF, 0x00][..]);
104    }
105
106    #[cfg(feature = "arbitrary")]
107    mod conformance {
108        use crate::conformance::CodecConformance;
109
110        commonware_conformance::conformance_tests! {
111            CodecConformance<(u32, u32)>,
112            CodecConformance<(u32, u32, u32)>,
113            CodecConformance<(u32, u32, u32, u32)>,
114            CodecConformance<(u32, u32, u32, u32, u32)>,
115            CodecConformance<(u32, u32, u32, u32, u32, u32)>,
116        }
117    }
118}