//! Codec implementation for [`Vec`]. //! //! For portability and consistency between architectures, //! the length of the vector must fit within a [u32]. use crate::{BufsMut, EncodeSize, Error, RangeCfg, Read, Write}; #[cfg(not(feature = "std"))] use alloc::vec::Vec; use bytes::{Buf, BufMut}; impl Write for Vec { #[inline] fn write(&self, buf: &mut impl BufMut) { self.as_slice().write(buf) } #[inline] fn write_bufs(&self, buf: &mut impl BufsMut) { self.as_slice().write_bufs(buf) } } impl EncodeSize for Vec { #[inline] fn encode_size(&self) -> usize { self.as_slice().encode_size() } #[inline] fn encode_inline_size(&self) -> usize { self.as_slice().encode_inline_size() } } impl Write for &[T] { #[inline] fn write(&self, buf: &mut impl BufMut) { self.len().write(buf); T::write_slice(self, buf); } #[inline] fn write_bufs(&self, buf: &mut impl BufsMut) { self.len().write(buf); T::write_slice_bufs(self, buf); } } impl EncodeSize for &[T] { #[inline] fn encode_size(&self) -> usize { self.len().encode_size() + T::encode_size_slice(self) } #[inline] fn encode_inline_size(&self) -> usize { self.len().encode_size() + T::encode_inline_size_slice(self) } } impl Read for Vec { type Cfg = (RangeCfg, T::Cfg); #[inline] fn read_cfg(buf: &mut impl Buf, (range, cfg): &Self::Cfg) -> Result { let len = usize::read_cfg(buf, range)?; T::read_vec(buf, len, cfg) } } #[cfg(test)] mod tests { use super::*; use crate::{ types::tests::{Byte, TrackingReadBuf, TrackingWriteBuf}, DecodeRangeExt, Encode, }; use bytes::{Bytes, BytesMut}; #[test] fn test_vec() { let vec_values = [vec![], vec![1u8], vec![1u8, 2u8, 3u8]]; for value in vec_values { let encoded = value.encode(); assert_eq!(encoded.len(), value.len() * core::mem::size_of::() + 1); // Valid decoding let len = value.len(); let decoded = Vec::::decode_range(encoded, len..=len).unwrap(); assert_eq!(value, decoded); // Failure for too long assert!(matches!( Vec::::decode_range(value.encode(), 0..len), Err(Error::InvalidLength(_)) )); // Failure for too short assert!(matches!( Vec::::decode_range(value.encode(), len + 1..), Err(Error::InvalidLength(_)) )); } // The length prefix advertises two payload bytes, but only one byte follows. assert!(matches!( Vec::::decode_range([0x02, 0x01].as_slice(), ..), Err(Error::EndOfBuffer) )); assert!(matches!( Vec::::decode_range([0x02, 0x01].as_slice(), ..), Err(Error::EndOfBuffer) )); // The length prefix advertises two payload bytes, and one extra byte remains after // those two payload bytes are consumed. assert!(matches!( Vec::::decode_range([0x02, 0x01, 0x02, 0x03].as_slice(), ..), Err(Error::ExtraData(1)) )); assert!(matches!( Vec::::decode_range([0x02, 0x01, 0x02, 0x03].as_slice(), ..), Err(Error::ExtraData(1)) )); } #[test] fn test_slice() { let slice_values: [&[u8]; 3] = [[].as_slice(), [1u8].as_slice(), [1u8, 2u8, 3u8].as_slice()]; for value in slice_values { let encoded = value.encode(); assert_eq!(encoded.len(), core::mem::size_of_val(value) + 1); // Valid decoding let len = value.len(); let decoded = Vec::::decode_range(encoded, len..=len).unwrap(); assert_eq!(value, decoded); // Failure for too long assert!(matches!( Vec::::decode_range(value.encode(), 0..len), Err(Error::InvalidLength(_)) )); // Failure for too short assert!(matches!( Vec::::decode_range(value.encode(), len + 1..), Err(Error::InvalidLength(_)) )); } } #[test] fn test_specialization_selection() { // `Vec` writes the length prefix, then the payload in one bulk write. let mut buf = TrackingWriteBuf::new(); vec![1u8, 2, 3].write(&mut buf); assert_eq!(buf.put_slice_calls, 1); assert_eq!(buf.put_u8_calls, 1); // Other one-byte element types keep the generic per-element path. let mut buf = TrackingWriteBuf::new(); vec![Byte(1), Byte(2), Byte(3)].write(&mut buf); assert_eq!(buf.put_slice_calls, 0); assert_eq!(buf.put_u8_calls, 4); // Slices use the same bulk payload path as vectors. let values = [1u8, 2, 3]; let mut buf = TrackingWriteBuf::new(); values.as_slice().write(&mut buf); assert_eq!(buf.put_slice_calls, 1); assert_eq!(buf.put_u8_calls, 1); // Non-`u8` slices keep the generic per-element path. let values = [Byte(1), Byte(2), Byte(3)]; let mut buf = TrackingWriteBuf::new(); values.as_slice().write(&mut buf); assert_eq!(buf.put_slice_calls, 0); assert_eq!(buf.put_u8_calls, 4); // `write_bufs` mirrors `write` for byte vectors. let mut buf = TrackingWriteBuf::new(); vec![1u8, 2, 3].write_bufs(&mut buf); assert_eq!(buf.put_slice_calls, 1); assert_eq!(buf.put_u8_calls, 1); // The `write_bufs` fallback remains element-by-element. let mut buf = TrackingWriteBuf::new(); vec![Byte(1), Byte(2), Byte(3)].write_bufs(&mut buf); assert_eq!(buf.put_slice_calls, 0); assert_eq!(buf.put_u8_calls, 4); // `Vec` reads the length prefix, then bulk-copies the payload. let mut buf = TrackingReadBuf::new(&[0x03, 0x01, 0x02, 0x03]); let value = Vec::::read_cfg(&mut buf, &((..).into(), ())).unwrap(); assert_eq!(value, vec![1, 2, 3]); assert_eq!(buf.copy_to_slice_calls, 1); assert_eq!(buf.get_u8_calls, 1); // Other element types still read one element at a time. let mut buf = TrackingReadBuf::new(&[0x03, 0x01, 0x02, 0x03]); let value = Vec::::read_cfg(&mut buf, &((..).into(), ())).unwrap(); assert_eq!(value, vec![Byte(1), Byte(2), Byte(3)]); assert_eq!(buf.copy_to_slice_calls, 0); assert_eq!(buf.get_u8_calls, 4); } #[test] fn test_write_bufs_equivalence() { fn assert_equivalent(value: &T) { let mut write = BytesMut::new(); value.write(&mut write); let mut write_bufs = TrackingWriteBuf::new(); value.write_bufs(&mut write_bufs); assert_eq!(write.freeze(), write_bufs.freeze()); } assert_equivalent(&vec![1u8, 2, 3]); assert_equivalent(&vec![0x0102u16, 0x0304, 0x0506]); assert_equivalent(&vec![Byte(1), Byte(2), Byte(3)]); assert_equivalent(&vec![ Bytes::from_static(&[1u8, 2, 3]), Bytes::from_static(&[4u8, 5, 6]), ]); let values = [1u8, 2, 3]; assert_equivalent(&values.as_slice()); let values = [0x0102u16, 0x0304, 0x0506]; assert_equivalent(&values.as_slice()); let values = [Byte(1), Byte(2), Byte(3)]; assert_equivalent(&values.as_slice()); let values = [ Bytes::from_static(&[1u8, 2, 3]), Bytes::from_static(&[4u8, 5, 6]), ]; assert_equivalent(&values.as_slice()); } #[test] fn test_conformity() { assert_eq!(Vec::::new().encode(), &[0x00][..]); assert_eq!( vec![0x01u8, 0x02u8, 0x03u8].encode(), &[0x03, 0x01, 0x02, 0x03][..] ); let v_u16: Vec = vec![0x1234, 0xABCD]; assert_eq!(v_u16.encode(), &[0x02, 0x12, 0x34, 0xAB, 0xCD][..]); let v_bool: Vec = vec![true, false, true]; assert_eq!(v_bool.encode(), &[0x03, 0x01, 0x00, 0x01][..]); let v_empty_u32: Vec = Vec::new(); assert_eq!(v_empty_u32.encode(), &[0x00][..]); // Test with a length that requires a multi-byte varint let v_long_u8: Vec = vec![0xCC; 200]; // 200 = 0xC8 = 0x80 + 0x48 -> 0xC8 0x01 let mut expected_long_u8 = vec![0xC8, 0x01]; expected_long_u8.extend_from_slice(&[0xCC; 200]); assert_eq!(v_long_u8.encode(), expected_long_u8.as_slice()); } #[cfg(feature = "arbitrary")] mod conformance { use crate::conformance::CodecConformance; commonware_conformance::conformance_tests! { CodecConformance>, CodecConformance>, CodecConformance>, } } }