Skip to main content

commonware_codec/types/
vec.rs

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