zerodds_foundation/
buffer.rs1#![allow(clippy::module_name_repetitions)]
18
19#[derive(Debug)]
31pub struct PoolBuffer<const CAP: usize> {
32 bytes: [u8; CAP],
33 len: u16,
34}
35
36impl<const CAP: usize> PoolBuffer<CAP> {
37 #[must_use]
42 pub const fn new() -> Self {
43 Self {
44 bytes: [0u8; CAP],
45 len: 0,
46 }
47 }
48
49 #[must_use]
51 pub const fn len(&self) -> usize {
52 self.len as usize
53 }
54
55 #[must_use]
57 pub const fn is_empty(&self) -> bool {
58 self.len == 0
59 }
60
61 #[must_use]
63 pub const fn capacity(&self) -> usize {
64 CAP
65 }
66
67 #[must_use]
69 pub fn as_slice(&self) -> &[u8] {
70 self.bytes.get(..self.len()).unwrap_or(&[])
73 }
74
75 #[must_use]
77 pub fn spare_capacity_mut(&mut self) -> &mut [u8] {
78 let start = self.len();
79 self.bytes.get_mut(start..).unwrap_or(&mut [])
80 }
81
82 pub fn clear(&mut self) {
84 self.len = 0;
85 }
86
87 pub fn extend_from_slice(&mut self, data: &[u8]) -> Result<(), PoolBufferError> {
93 if CAP > u16::MAX as usize {
94 return Err(PoolBufferError::CapacityTooLarge);
95 }
96 let needed = self
97 .len()
98 .checked_add(data.len())
99 .ok_or(PoolBufferError::Overflow)?;
100 if needed > CAP {
101 return Err(PoolBufferError::Overflow);
102 }
103 let start = self.len();
104 let dst = self
105 .bytes
106 .get_mut(start..needed)
107 .ok_or(PoolBufferError::Overflow)?;
108 dst.copy_from_slice(data);
109 self.len = needed as u16;
111 Ok(())
112 }
113
114 pub fn push(&mut self, byte: u8) -> Result<(), PoolBufferError> {
119 self.extend_from_slice(&[byte])
120 }
121
122 pub fn set_len(&mut self, new_len: usize) -> Result<(), PoolBufferError> {
128 if new_len > CAP || CAP > u16::MAX as usize {
129 return Err(PoolBufferError::Overflow);
130 }
131 self.len = new_len as u16;
133 Ok(())
134 }
135}
136
137impl<const CAP: usize> Default for PoolBuffer<CAP> {
138 fn default() -> Self {
139 Self::new()
140 }
141}
142
143impl<const CAP: usize> AsRef<[u8]> for PoolBuffer<CAP> {
144 fn as_ref(&self) -> &[u8] {
145 self.as_slice()
146 }
147}
148
149#[derive(Debug, Clone, Copy, PartialEq, Eq)]
155pub enum PoolBufferError {
156 Overflow,
158 CapacityTooLarge,
161}
162
163impl core::fmt::Display for PoolBufferError {
164 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
165 match self {
166 Self::Overflow => f.write_str("pool buffer overflow"),
167 Self::CapacityTooLarge => f.write_str("CAP exceeds u16::MAX"),
168 }
169 }
170}
171
172#[cfg(feature = "std")]
173impl std::error::Error for PoolBufferError {}
174
175#[cfg(test)]
181#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
182mod tests {
183 use super::*;
184
185 #[test]
186 fn empty_buffer_has_len_zero() {
187 let b: PoolBuffer<128> = PoolBuffer::new();
188 assert_eq!(b.len(), 0);
189 assert!(b.is_empty());
190 assert_eq!(b.capacity(), 128);
191 assert_eq!(b.as_slice(), &[]);
192 }
193
194 #[test]
195 fn extend_appends_and_tracks_len() {
196 let mut b: PoolBuffer<16> = PoolBuffer::new();
197 b.extend_from_slice(b"hello").unwrap();
198 assert_eq!(b.len(), 5);
199 assert_eq!(b.as_slice(), b"hello");
200 b.extend_from_slice(b" world").unwrap();
201 assert_eq!(b.as_slice(), b"hello world");
202 }
203
204 #[test]
205 fn extend_overflow_returns_error_no_partial_write() {
206 let mut b: PoolBuffer<8> = PoolBuffer::new();
207 b.extend_from_slice(b"1234").unwrap();
208 let err = b.extend_from_slice(b"56789").unwrap_err();
209 assert_eq!(err, PoolBufferError::Overflow);
210 assert_eq!(b.as_slice(), b"1234");
211 }
212
213 #[test]
214 fn push_byte_works() {
215 let mut b: PoolBuffer<4> = PoolBuffer::new();
216 b.push(0xCA).unwrap();
217 b.push(0xFE).unwrap();
218 assert_eq!(b.as_slice(), &[0xCA, 0xFE]);
219 }
220
221 #[test]
222 fn push_overflow_errors() {
223 let mut b: PoolBuffer<2> = PoolBuffer::new();
224 b.push(1).unwrap();
225 b.push(2).unwrap();
226 assert_eq!(b.push(3).unwrap_err(), PoolBufferError::Overflow);
227 }
228
229 #[test]
230 fn clear_resets_len_only() {
231 let mut b: PoolBuffer<16> = PoolBuffer::new();
232 b.extend_from_slice(b"abc").unwrap();
233 b.clear();
234 assert_eq!(b.len(), 0);
235 assert_eq!(b.as_slice(), &[]);
236 b.extend_from_slice(b"xyz").unwrap();
237 assert_eq!(b.as_slice(), b"xyz");
238 }
239
240 #[test]
241 fn spare_capacity_then_set_len() {
242 let mut b: PoolBuffer<32> = PoolBuffer::new();
243 let spare = b.spare_capacity_mut();
244 assert_eq!(spare.len(), 32);
245 spare[0..3].copy_from_slice(&[1, 2, 3]);
246 b.set_len(3).unwrap();
247 assert_eq!(b.as_slice(), &[1, 2, 3]);
248 }
249
250 #[test]
251 fn set_len_overflow_errors() {
252 let mut b: PoolBuffer<8> = PoolBuffer::new();
253 assert_eq!(b.set_len(9).unwrap_err(), PoolBufferError::Overflow);
254 }
255
256 #[test]
257 fn cap_above_u16_max_extend_errors() {
258 let mut b: PoolBuffer<{ u16::MAX as usize + 1 }> = PoolBuffer::new();
259 let err = b.extend_from_slice(&[0u8]).unwrap_err();
260 assert_eq!(err, PoolBufferError::CapacityTooLarge);
261 }
262
263 #[test]
264 fn error_display_strings() {
265 let s = std::format!("{}", PoolBufferError::Overflow);
266 assert!(s.contains("overflow"));
267 let s = std::format!("{}", PoolBufferError::CapacityTooLarge);
268 assert!(s.contains("u16"));
269 }
270}