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,
159 CapacityTooLarge,
162}
163
164impl core::fmt::Display for PoolBufferError {
165 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
166 match self {
167 Self::Overflow => f.write_str("pool buffer overflow"),
168 Self::CapacityTooLarge => f.write_str("CAP exceeds u16::MAX"),
169 }
170 }
171}
172
173#[cfg(feature = "std")]
174impl std::error::Error for PoolBufferError {}
175
176#[cfg(test)]
182#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
183mod tests {
184 use super::*;
185
186 #[test]
187 fn empty_buffer_has_len_zero() {
188 let b: PoolBuffer<128> = PoolBuffer::new();
189 assert_eq!(b.len(), 0);
190 assert!(b.is_empty());
191 assert_eq!(b.capacity(), 128);
192 assert_eq!(b.as_slice(), &[]);
193 }
194
195 #[test]
196 fn extend_appends_and_tracks_len() {
197 let mut b: PoolBuffer<16> = PoolBuffer::new();
198 b.extend_from_slice(b"hello").unwrap();
199 assert_eq!(b.len(), 5);
200 assert_eq!(b.as_slice(), b"hello");
201 b.extend_from_slice(b" world").unwrap();
202 assert_eq!(b.as_slice(), b"hello world");
203 }
204
205 #[test]
206 fn extend_overflow_returns_error_no_partial_write() {
207 let mut b: PoolBuffer<8> = PoolBuffer::new();
208 b.extend_from_slice(b"1234").unwrap();
209 let err = b.extend_from_slice(b"56789").unwrap_err();
210 assert_eq!(err, PoolBufferError::Overflow);
211 assert_eq!(b.as_slice(), b"1234");
212 }
213
214 #[test]
215 fn push_byte_works() {
216 let mut b: PoolBuffer<4> = PoolBuffer::new();
217 b.push(0xCA).unwrap();
218 b.push(0xFE).unwrap();
219 assert_eq!(b.as_slice(), &[0xCA, 0xFE]);
220 }
221
222 #[test]
223 fn push_overflow_errors() {
224 let mut b: PoolBuffer<2> = PoolBuffer::new();
225 b.push(1).unwrap();
226 b.push(2).unwrap();
227 assert_eq!(b.push(3).unwrap_err(), PoolBufferError::Overflow);
228 }
229
230 #[test]
231 fn clear_resets_len_only() {
232 let mut b: PoolBuffer<16> = PoolBuffer::new();
233 b.extend_from_slice(b"abc").unwrap();
234 b.clear();
235 assert_eq!(b.len(), 0);
236 assert_eq!(b.as_slice(), &[]);
237 b.extend_from_slice(b"xyz").unwrap();
238 assert_eq!(b.as_slice(), b"xyz");
239 }
240
241 #[test]
242 fn spare_capacity_then_set_len() {
243 let mut b: PoolBuffer<32> = PoolBuffer::new();
244 let spare = b.spare_capacity_mut();
245 assert_eq!(spare.len(), 32);
246 spare[0..3].copy_from_slice(&[1, 2, 3]);
247 b.set_len(3).unwrap();
248 assert_eq!(b.as_slice(), &[1, 2, 3]);
249 }
250
251 #[test]
252 fn set_len_overflow_errors() {
253 let mut b: PoolBuffer<8> = PoolBuffer::new();
254 assert_eq!(b.set_len(9).unwrap_err(), PoolBufferError::Overflow);
255 }
256
257 #[test]
258 fn cap_above_u16_max_extend_errors() {
259 let mut b: PoolBuffer<{ u16::MAX as usize + 1 }> = PoolBuffer::new();
260 let err = b.extend_from_slice(&[0u8]).unwrap_err();
261 assert_eq!(err, PoolBufferError::CapacityTooLarge);
262 }
263
264 #[test]
265 fn error_display_strings() {
266 let s = std::format!("{}", PoolBufferError::Overflow);
267 assert!(s.contains("overflow"));
268 let s = std::format!("{}", PoolBufferError::CapacityTooLarge);
269 assert!(s.contains("u16"));
270 }
271}