basalt_types/
byte_array.rs1use crate::{Decode, Encode, EncodedSize, Error, Result, VarInt};
2
3impl Encode for Vec<u8> {
11 fn encode(&self, buf: &mut Vec<u8>) -> Result<()> {
13 VarInt(self.len() as i32).encode(buf)?;
14 buf.extend_from_slice(self);
15 Ok(())
16 }
17}
18
19impl Decode for Vec<u8> {
25 fn decode(buf: &mut &[u8]) -> Result<Self> {
30 let raw_len = VarInt::decode(buf)?.0;
31 if raw_len < 0 {
32 return Err(Error::InvalidData(format!(
33 "negative byte array length: {raw_len}"
34 )));
35 }
36 let len = raw_len as usize;
37 if buf.len() < len {
38 return Err(Error::BufferUnderflow {
39 needed: len,
40 available: buf.len(),
41 });
42 }
43 let (bytes, rest) = buf.split_at(len);
44 let value = bytes.to_vec();
45 *buf = rest;
46 Ok(value)
47 }
48}
49
50impl EncodedSize for Vec<u8> {
55 fn encoded_size(&self) -> usize {
57 VarInt(self.len() as i32).encoded_size() + self.len()
58 }
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64
65 fn roundtrip(data: &[u8]) {
66 let original = data.to_vec();
67 let mut buf = Vec::with_capacity(original.encoded_size());
68 original.encode(&mut buf).unwrap();
69 assert_eq!(buf.len(), original.encoded_size());
70
71 let mut cursor = buf.as_slice();
72 let decoded = Vec::<u8>::decode(&mut cursor).unwrap();
73 assert!(cursor.is_empty());
74 assert_eq!(decoded, original);
75 }
76
77 #[test]
78 fn empty() {
79 roundtrip(&[]);
80 }
81
82 #[test]
83 fn small() {
84 roundtrip(&[0x01, 0x02, 0x03]);
85 }
86
87 #[test]
88 fn large() {
89 roundtrip(&vec![0xAB; 1024]);
90 }
91
92 #[test]
93 fn truncated_buffer() {
94 let mut buf = Vec::new();
95 VarInt(10).encode(&mut buf).unwrap();
96 buf.extend_from_slice(&[0x01; 5]);
97
98 let mut cursor = buf.as_slice();
99 assert!(matches!(
100 Vec::<u8>::decode(&mut cursor),
101 Err(Error::BufferUnderflow { .. })
102 ));
103 }
104
105 #[test]
106 fn encoded_size_accounts_for_varint_prefix() {
107 assert_eq!(Vec::<u8>::new().encoded_size(), 1);
108 assert_eq!(vec![0u8; 3].encoded_size(), 4);
109 }
110
111 mod proptests {
112 use super::*;
113 use proptest::prelude::*;
114
115 proptest! {
116 #[test]
117 fn byte_array_roundtrip(data in proptest::collection::vec(any::<u8>(), 0..1000)) {
118 roundtrip(&data);
119 }
120 }
121 }
122}