1use crate::{Buf, Error, FixedSize, MaxEncodeSize, Read, varint::UInt};
4#[cfg(not(feature = "std"))]
5use alloc::vec::Vec;
6#[cfg(feature = "std")]
7use std::vec::Vec;
8
9#[inline]
11pub fn at_least<B: Buf>(buf: &mut B, len: usize) -> Result<(), Error> {
12 let rem = buf.remaining();
13 if rem < len {
14 return Err(Error::EndOfBuffer);
15 }
16 Ok(())
17}
18
19#[inline]
22pub fn at_least_items<B: Buf>(buf: &mut B, len: usize, item_size: usize) -> Result<(), Error> {
23 at_least(buf, len.checked_mul(item_size).ok_or(Error::EndOfBuffer)?)
24}
25
26#[inline]
34pub fn max_items_size(len: usize, item_size: usize) -> usize {
35 u32::try_from(len).expect("len must fit the u32 length prefix");
36 len * item_size + UInt::<u32>::MAX_ENCODE_SIZE
37}
38
39#[inline]
45pub fn read_fixed_vec<T: Read + FixedSize>(
46 buf: &mut impl Buf,
47 len: usize,
48 cfg: &T::Cfg,
49) -> Result<Vec<T>, Error> {
50 at_least_items(buf, len, T::SIZE)?;
51 let mut values = Vec::with_capacity(len);
52 for _ in 0..len {
53 values.push(T::read_cfg(buf, cfg)?);
54 }
55 Ok(values)
56}
57
58#[inline]
61pub fn ensure_zeros<B: Buf>(buf: &mut B, size: usize) -> Result<(), Error> {
62 at_least(buf, size)?;
63 let mut remaining = size;
64 while remaining > 0 {
65 let chunk = buf.chunk();
68 let len = chunk.len().min(remaining);
69 if chunk[..len].iter().any(|&b| b != 0) {
70 return Err(Error::Invalid("codec", "non-zero bytes"));
71 }
72 buf.advance(len);
73 remaining -= len;
74 }
75 Ok(())
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81 use crate::{Copying, EncodeSize, varint::MAX_U32_VARINT_SIZE};
82 use bytes::Buf as _;
83
84 #[test]
85 fn test_max_items_size() {
86 for (len, expected) in [(0, 5), (1, 9), (127, 513), (128, 517)] {
89 let items = vec![[0u8; 4]; len];
90 let size = max_items_size(len, 4);
91 assert_eq!(size, expected);
92 assert!(items.encode_size() <= size);
93 }
94
95 const LARGEST: usize = u32::MAX as usize;
97 assert_eq!(max_items_size(LARGEST, 1), LARGEST + MAX_U32_VARINT_SIZE);
98 }
99
100 #[test]
101 #[should_panic(expected = "len must fit the u32 length prefix")]
102 fn test_max_items_size_beyond_prefix() {
103 max_items_size(u32::MAX as usize + 1, 0);
104 }
105
106 #[test]
107 fn test_ensure_zeros() {
108 let mut buf = Copying(&[0u8, 0, 0, 0, 7]);
110 ensure_zeros(&mut buf, 4).unwrap();
111 assert_eq!(buf.remaining(), 1);
112
113 let mut buf = Copying(&[]);
115 ensure_zeros(&mut buf, 0).unwrap();
116
117 let mut buf = Copying(&[0u8, 0]);
119 assert!(matches!(ensure_zeros(&mut buf, 3), Err(Error::EndOfBuffer)));
120
121 for i in 0..4 {
123 let mut bytes = [0u8; 4];
124 bytes[i] = 1;
125 let mut buf = Copying(&bytes);
126 assert!(matches!(
127 ensure_zeros(&mut buf, 4),
128 Err(Error::Invalid(_, _))
129 ));
130 }
131 }
132
133 #[test]
134 fn test_ensure_zeros_across_chunks() {
135 let mut buf = Copying(&[0u8, 0]).chain(Copying(&[0u8, 0, 0]));
137 ensure_zeros(&mut buf, 5).unwrap();
138 assert_eq!(buf.remaining(), 0);
139
140 let mut buf = Copying(&[0u8, 0]).chain(Copying(&[0u8, 2]));
142 assert!(matches!(
143 ensure_zeros(&mut buf, 4),
144 Err(Error::Invalid(_, _))
145 ));
146 }
147}