Skip to main content

commonware_codec/types/
vec.rs

1//! Codec implementation for [`Vec<T>`].
2//!
3//! For portability and consistency between architectures,
4//! the length of the vector must fit within a [u32].
5
6use crate::{BufsMut, EncodeSize, Error, RangeCfg, Read, Write};
7#[cfg(not(feature = "std"))]
8use alloc::vec::Vec;
9use bytes::{Buf, BufMut};
10
11impl<T: Write> Write for Vec<T> {
12    #[inline]
13    fn write(&self, buf: &mut impl BufMut) {
14        self.as_slice().write(buf)
15    }
16
17    #[inline]
18    fn write_bufs(&self, buf: &mut impl BufsMut) {
19        self.as_slice().write_bufs(buf)
20    }
21}
22
23impl<T: EncodeSize> EncodeSize for Vec<T> {
24    #[inline]
25    fn encode_size(&self) -> usize {
26        self.as_slice().encode_size()
27    }
28
29    #[inline]
30    fn encode_inline_size(&self) -> usize {
31        self.as_slice().encode_inline_size()
32    }
33}
34
35impl<T: Write> Write for &[T] {
36    #[inline]
37    fn write(&self, buf: &mut impl BufMut) {
38        self.len().write(buf);
39        T::write_slice(self, buf);
40    }
41
42    #[inline]
43    fn write_bufs(&self, buf: &mut impl BufsMut) {
44        self.len().write(buf);
45        T::write_slice_bufs(self, buf);
46    }
47}
48
49impl<T: EncodeSize> EncodeSize for &[T] {
50    #[inline]
51    fn encode_size(&self) -> usize {
52        self.len().encode_size() + T::encode_size_slice(self)
53    }
54
55    #[inline]
56    fn encode_inline_size(&self) -> usize {
57        self.len().encode_size() + T::encode_inline_size_slice(self)
58    }
59}
60
61impl<T: Read> Read for Vec<T> {
62    type Cfg = (RangeCfg<usize>, T::Cfg);
63
64    #[inline]
65    fn read_cfg(buf: &mut impl Buf, (range, cfg): &Self::Cfg) -> Result<Self, Error> {
66        let len = usize::read_cfg(buf, range)?;
67        T::read_vec(buf, len, cfg)
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74    use crate::{
75        types::tests::{Byte, TrackingReadBuf, TrackingWriteBuf},
76        DecodeRangeExt, Encode,
77    };
78    use bytes::{Bytes, BytesMut};
79
80    #[test]
81    fn test_vec() {
82        let vec_values = [vec![], vec![1u8], vec![1u8, 2u8, 3u8]];
83        for value in vec_values {
84            let encoded = value.encode();
85            assert_eq!(encoded.len(), value.len() * core::mem::size_of::<u8>() + 1);
86
87            // Valid decoding
88            let len = value.len();
89            let decoded = Vec::<u8>::decode_range(encoded, len..=len).unwrap();
90            assert_eq!(value, decoded);
91
92            // Failure for too long
93            assert!(matches!(
94                Vec::<u8>::decode_range(value.encode(), 0..len),
95                Err(Error::InvalidLength(_))
96            ));
97
98            // Failure for too short
99            assert!(matches!(
100                Vec::<u8>::decode_range(value.encode(), len + 1..),
101                Err(Error::InvalidLength(_))
102            ));
103        }
104
105        // The length prefix advertises two payload bytes, but only one byte follows.
106        assert!(matches!(
107            Vec::<u8>::decode_range([0x02, 0x01].as_slice(), ..),
108            Err(Error::EndOfBuffer)
109        ));
110        assert!(matches!(
111            Vec::<Byte>::decode_range([0x02, 0x01].as_slice(), ..),
112            Err(Error::EndOfBuffer)
113        ));
114
115        // The length prefix advertises two payload bytes, and one extra byte remains after
116        // those two payload bytes are consumed.
117        assert!(matches!(
118            Vec::<u8>::decode_range([0x02, 0x01, 0x02, 0x03].as_slice(), ..),
119            Err(Error::ExtraData(1))
120        ));
121        assert!(matches!(
122            Vec::<Byte>::decode_range([0x02, 0x01, 0x02, 0x03].as_slice(), ..),
123            Err(Error::ExtraData(1))
124        ));
125    }
126
127    #[test]
128    fn test_slice() {
129        let slice_values: [&[u8]; 3] =
130            [[].as_slice(), [1u8].as_slice(), [1u8, 2u8, 3u8].as_slice()];
131        for value in slice_values {
132            let encoded = value.encode();
133            assert_eq!(encoded.len(), core::mem::size_of_val(value) + 1);
134
135            // Valid decoding
136            let len = value.len();
137            let decoded = Vec::<u8>::decode_range(encoded, len..=len).unwrap();
138            assert_eq!(value, decoded);
139
140            // Failure for too long
141            assert!(matches!(
142                Vec::<u8>::decode_range(value.encode(), 0..len),
143                Err(Error::InvalidLength(_))
144            ));
145
146            // Failure for too short
147            assert!(matches!(
148                Vec::<u8>::decode_range(value.encode(), len + 1..),
149                Err(Error::InvalidLength(_))
150            ));
151        }
152    }
153
154    #[test]
155    fn test_specialization_selection() {
156        // `Vec<u8>` writes the length prefix, then the payload in one bulk write.
157        let mut buf = TrackingWriteBuf::new();
158        vec![1u8, 2, 3].write(&mut buf);
159        assert_eq!(buf.put_slice_calls, 1);
160        assert_eq!(buf.put_u8_calls, 1);
161
162        // Other one-byte element types keep the generic per-element path.
163        let mut buf = TrackingWriteBuf::new();
164        vec![Byte(1), Byte(2), Byte(3)].write(&mut buf);
165        assert_eq!(buf.put_slice_calls, 0);
166        assert_eq!(buf.put_u8_calls, 4);
167
168        // Slices use the same bulk payload path as vectors.
169        let values = [1u8, 2, 3];
170        let mut buf = TrackingWriteBuf::new();
171        values.as_slice().write(&mut buf);
172        assert_eq!(buf.put_slice_calls, 1);
173        assert_eq!(buf.put_u8_calls, 1);
174
175        // Non-`u8` slices keep the generic per-element path.
176        let values = [Byte(1), Byte(2), Byte(3)];
177        let mut buf = TrackingWriteBuf::new();
178        values.as_slice().write(&mut buf);
179        assert_eq!(buf.put_slice_calls, 0);
180        assert_eq!(buf.put_u8_calls, 4);
181
182        // `write_bufs` mirrors `write` for byte vectors.
183        let mut buf = TrackingWriteBuf::new();
184        vec![1u8, 2, 3].write_bufs(&mut buf);
185        assert_eq!(buf.put_slice_calls, 1);
186        assert_eq!(buf.put_u8_calls, 1);
187
188        // The `write_bufs` fallback remains element-by-element.
189        let mut buf = TrackingWriteBuf::new();
190        vec![Byte(1), Byte(2), Byte(3)].write_bufs(&mut buf);
191        assert_eq!(buf.put_slice_calls, 0);
192        assert_eq!(buf.put_u8_calls, 4);
193
194        // `Vec<u8>` reads the length prefix, then bulk-copies the payload.
195        let mut buf = TrackingReadBuf::new(&[0x03, 0x01, 0x02, 0x03]);
196        let value = Vec::<u8>::read_cfg(&mut buf, &((..).into(), ())).unwrap();
197        assert_eq!(value, vec![1, 2, 3]);
198        assert_eq!(buf.copy_to_slice_calls, 1);
199        assert_eq!(buf.get_u8_calls, 1);
200
201        // Other element types still read one element at a time.
202        let mut buf = TrackingReadBuf::new(&[0x03, 0x01, 0x02, 0x03]);
203        let value = Vec::<Byte>::read_cfg(&mut buf, &((..).into(), ())).unwrap();
204        assert_eq!(value, vec![Byte(1), Byte(2), Byte(3)]);
205        assert_eq!(buf.copy_to_slice_calls, 0);
206        assert_eq!(buf.get_u8_calls, 4);
207    }
208
209    #[test]
210    fn test_write_bufs_equivalence() {
211        fn assert_equivalent<T: Write>(value: &T) {
212            let mut write = BytesMut::new();
213            value.write(&mut write);
214
215            let mut write_bufs = TrackingWriteBuf::new();
216            value.write_bufs(&mut write_bufs);
217
218            assert_eq!(write.freeze(), write_bufs.freeze());
219        }
220
221        assert_equivalent(&vec![1u8, 2, 3]);
222        assert_equivalent(&vec![0x0102u16, 0x0304, 0x0506]);
223        assert_equivalent(&vec![Byte(1), Byte(2), Byte(3)]);
224        assert_equivalent(&vec![
225            Bytes::from_static(&[1u8, 2, 3]),
226            Bytes::from_static(&[4u8, 5, 6]),
227        ]);
228
229        let values = [1u8, 2, 3];
230        assert_equivalent(&values.as_slice());
231
232        let values = [0x0102u16, 0x0304, 0x0506];
233        assert_equivalent(&values.as_slice());
234
235        let values = [Byte(1), Byte(2), Byte(3)];
236        assert_equivalent(&values.as_slice());
237
238        let values = [
239            Bytes::from_static(&[1u8, 2, 3]),
240            Bytes::from_static(&[4u8, 5, 6]),
241        ];
242        assert_equivalent(&values.as_slice());
243    }
244
245    #[test]
246    fn test_conformity() {
247        assert_eq!(Vec::<u8>::new().encode(), &[0x00][..]);
248        assert_eq!(
249            vec![0x01u8, 0x02u8, 0x03u8].encode(),
250            &[0x03, 0x01, 0x02, 0x03][..]
251        );
252
253        let v_u16: Vec<u16> = vec![0x1234, 0xABCD];
254        assert_eq!(v_u16.encode(), &[0x02, 0x12, 0x34, 0xAB, 0xCD][..]);
255
256        let v_bool: Vec<bool> = vec![true, false, true];
257        assert_eq!(v_bool.encode(), &[0x03, 0x01, 0x00, 0x01][..]);
258
259        let v_empty_u32: Vec<u32> = Vec::new();
260        assert_eq!(v_empty_u32.encode(), &[0x00][..]);
261
262        // Test with a length that requires a multi-byte varint
263        let v_long_u8: Vec<u8> = vec![0xCC; 200]; // 200 = 0xC8 = 0x80 + 0x48 -> 0xC8 0x01
264        let mut expected_long_u8 = vec![0xC8, 0x01];
265        expected_long_u8.extend_from_slice(&[0xCC; 200]);
266        assert_eq!(v_long_u8.encode(), expected_long_u8.as_slice());
267    }
268
269    #[cfg(feature = "arbitrary")]
270    mod conformance {
271        use crate::conformance::CodecConformance;
272
273        commonware_conformance::conformance_tests! {
274            CodecConformance<Vec<u8>>,
275            CodecConformance<Vec<u16>>,
276            CodecConformance<Vec<u32>>,
277        }
278    }
279}