irox_tools/buf/
fixed_u8.rs1#![allow(clippy::indexing_slicing)]
6#![allow(clippy::unwrap_used)]
7use crate::buf::Buffer;
8use crate::iterators::LendingIterator;
9use core::ops::{Index, IndexMut};
10use core::str::Utf8Error;
11use irox_bits::{Bits, BitsErrorKind, Error, MutBits, ReadFromBEBits, WriteToBEBits};
12
13pub type StrBuf<const N: usize> = FixedU8Buf<N>;
14
15#[derive(Clone)]
18pub struct FixedU8Buf<const N: usize> {
19 buf: [u8; N],
20 len: usize,
21}
22impl<const N: usize> FixedU8Buf<N> {
23 pub const fn new() -> Self {
24 Self {
25 buf: [0u8; N],
26 len: 0,
27 }
28 }
29
30 pub fn take(self) -> [u8; N] {
33 self.buf
34 }
35
36 pub fn as_buf_default(&mut self) -> [u8; N] {
39 let out = core::mem::replace(&mut self.buf, [0u8; N]);
40 self.clear();
41 out
42 }
43
44 pub fn iter(&self) -> FixedU8BufIter<N> {
47 FixedU8BufIter { buf: self, idx: 0 }
48 }
49
50 pub const fn len(&self) -> usize {
53 self.len
54 }
55
56 pub const fn is_empty(&self) -> bool {
59 self.len == 0
60 }
61
62 pub fn as_ref_used(&self) -> &[u8] {
65 self.as_ref()
66 }
67
68 pub fn as_mut_full(&mut self) -> &mut [u8] {
73 self.as_mut()
74 }
75
76 pub fn as_mut_used(&mut self) -> &mut [u8] {
79 &mut self.buf[0..self.len]
80 }
81
82 pub fn update_length(&mut self, new_len: usize) -> Result<(), Error> {
86 if new_len > N {
87 return Err(BitsErrorKind::OutOfMemory.into());
88 }
89 self.len = new_len;
90 Ok(())
91 }
92
93 pub fn push_char(&mut self, c: char) -> Result<(), Error> {
96 let mut buf = [0u8; 4];
97 let used = c.encode_utf8(&mut buf).len();
98 if self.len + used > N {
99 return Err(BitsErrorKind::OutOfMemory.into());
100 }
101
102 Ok(())
103 }
104
105 pub fn append(&mut self, buf: &[u8]) -> Result<(), Error> {
108 if self.len + buf.len() > N {
109 return Err(BitsErrorKind::OutOfMemory.into());
110 }
111 for b in buf {
112 let _ = self.push_back(*b);
113 }
114 Ok(())
115 }
116
117 pub fn as_str(&self) -> Result<&str, Utf8Error> {
120 core::str::from_utf8(self.as_ref_used())
121 }
122 pub fn as_str_mut(&mut self) -> Result<&mut str, Utf8Error> {
125 core::str::from_utf8_mut(self.as_mut_used())
126 }
127
128 pub fn reverse(&mut self) {
131 let mut i = 0;
132 let mut j = self.len - 1;
133 while i < j {
134 self.buf.swap(i, j);
135 i += 1;
136 j -= 1;
137 }
138 }
139}
140impl<const N: usize> WriteToBEBits for FixedU8Buf<N> {
141 fn write_be_to<T: MutBits + ?Sized>(&self, bits: &mut T) -> Result<usize, Error> {
142 bits.write_be_u32_blob(self.as_ref_used())?;
143 Ok(self.len + 4)
144 }
145}
146impl<const N: usize> ReadFromBEBits for FixedU8Buf<N> {
147 fn read_from_be_bits<T: Bits>(inp: &mut T) -> Result<Self, Error> {
148 let mut out = Self::new();
149 inp.read_u32_blob_into(&mut out)?;
150 Ok(out)
151 }
152}
153
154impl<const N: usize> AsRef<[u8]> for FixedU8Buf<N> {
155 #[allow(clippy::indexing_slicing)]
156 fn as_ref(&self) -> &[u8] {
157 &self.buf[..self.len]
158 }
159}
160impl<const N: usize> AsMut<[u8]> for FixedU8Buf<N> {
161 fn as_mut(&mut self) -> &mut [u8] {
162 &mut self.buf
163 }
164}
165impl<const N: usize> Default for FixedU8Buf<N> {
166 fn default() -> Self {
167 Self::new()
168 }
169}
170
171impl<const N: usize> core::fmt::Write for FixedU8Buf<N> {
172 fn write_str(&mut self, s: &str) -> core::fmt::Result {
173 self.append(s.as_bytes()).map_err(|_| core::fmt::Error)?;
174 Ok(())
175 }
176}
177
178impl<const N: usize> Buffer<u8> for FixedU8Buf<N> {
179 fn get(&self, index: usize) -> Option<&u8> {
180 if index >= N || index >= self.len {
181 return None;
182 }
183 self.buf.get(index)
184 }
185
186 fn get_mut(&mut self, index: usize) -> Option<&mut u8> {
187 if index >= N || index >= self.len {
188 return None;
189 }
190 self.buf.get_mut(index)
191 }
192
193 fn capacity(&self) -> usize {
194 N
195 }
196
197 fn len(&self) -> usize {
198 self.len
199 }
200
201 fn clear(&mut self) {
202 self.len = 0
203 }
204
205 fn front(&self) -> Option<&u8> {
206 self.get(0)
207 }
208
209 fn front_mut(&mut self) -> Option<&mut u8> {
210 self.get_mut(0)
211 }
212
213 fn back(&self) -> Option<&u8> {
214 if N == 0 || self.len == 0 {
215 return None;
216 }
217 self.get(self.len - 1)
218 }
219
220 fn back_mut(&mut self) -> Option<&mut u8> {
221 if N == 0 || self.len == 0 {
222 return None;
223 }
224 self.get_mut(self.len - 1)
225 }
226
227 fn pop_front(&mut self) -> Option<u8> {
228 if N == 0 || self.len == 0 {
229 return None;
230 }
231 let out = self.buf[0];
232 for idx in 1..self.len {
233 self.buf[idx - 1] = self.buf[idx];
234 }
235 self.len -= 1;
236 Some(out)
237 }
238
239 fn pop_back(&mut self) -> Option<u8> {
240 if N == 0 || self.len == 0 {
241 return None;
242 }
243 let idx = self.len - 1;
244 self.len -= 1;
245 let val = self.buf[idx];
246 self.buf[idx] = 0;
247 Some(val)
248 }
249
250 fn push_front(&mut self, value: u8) -> Result<(), u8> {
251 if N == 0 || self.len == N {
252 return Err(value);
253 }
254 for idx in 0..self.len {
255 self.buf[idx + 1] = self.buf[idx];
256 }
257 self.buf[0] = value;
258 self.len += 1;
259 Ok(())
260 }
261
262 fn push_back(&mut self, value: u8) -> Result<(), u8> {
263 if N == 0 || self.len == N {
264 return Err(value);
265 }
266 self.buf[self.len] = value;
267 self.len += 1;
268 Ok(())
269 }
270}
271
272#[allow(clippy::panic)]
273impl<const N: usize> Index<usize> for FixedU8Buf<N> {
274 type Output = u8;
275
276 fn index(&self, index: usize) -> &Self::Output {
277 assert!(index < self.len, "index {index} >= len {}", self.len);
278 let Some(val) = self.buf.get(index) else {
279 panic!("expected value at offset {index} but was empty!");
280 };
281 val
282 }
283}
284#[allow(clippy::panic)]
285impl<const N: usize> IndexMut<usize> for FixedU8Buf<N> {
286 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
287 assert!(index < N, "index {index} >= capacity {N}");
288 if index >= self.len {
289 self.len = index + 1;
290 }
291 &mut self.buf[index]
292 }
293}
294
295pub struct FixedU8BufIter<'a, const N: usize> {
296 buf: &'a FixedU8Buf<N>,
297 idx: usize,
298}
299
300impl<'a, const N: usize> Iterator for FixedU8BufIter<'a, N> {
301 type Item = &'a u8;
302 fn next(&mut self) -> Option<Self::Item> {
303 if let Some(val) = self.buf.get(self.idx) {
304 self.idx += 1;
305 return Some(val);
306 }
307 None
308 }
309}
310impl<const N: usize> DoubleEndedIterator for FixedU8BufIter<'_, N> {
311 fn next_back(&mut self) -> Option<Self::Item> {
312 if self.idx >= self.buf.len {
313 return None;
314 }
315 let idx = self.buf.len().saturating_sub(self.idx).saturating_sub(1);
316
317 self.idx += 1;
318 if let Some(val) = self.buf.get(idx) {
319 return Some(val);
320 }
321 None
322 }
323}
324impl<const N: usize> ExactSizeIterator for FixedU8BufIter<'_, N> {
325 fn len(&self) -> usize {
326 self.buf.len()
327 }
328}
329
330pub struct FixedU8BufIterMut<'a, const N: usize> {
331 buf: &'a mut FixedU8Buf<N>,
332 idx: usize,
333}
334
335impl<const N: usize> LendingIterator for FixedU8BufIterMut<'_, N> {
336 type Item<'b>
337 = &'b mut u8
338 where
339 Self: 'b;
340
341 fn next_ref(&mut self) -> Option<Self::Item<'_>> {
342 if let Some(val) = self.buf.get_mut(self.idx) {
343 self.idx += 1;
344 return Some(val);
345 }
346 None
347 }
348}
349
350impl<const N: usize> MutBits for &mut FixedU8Buf<N> {
351 fn write_u8(&mut self, val: u8) -> Result<(), Error> {
352 if self.push_back(val).is_err() {
353 return Err(BitsErrorKind::UnexpectedEof.into());
354 }
355 Ok(())
356 }
357}
358impl<const N: usize> MutBits for FixedU8Buf<N> {
359 fn write_u8(&mut self, val: u8) -> Result<(), Error> {
360 if self.push_back(val).is_err() {
361 return Err(BitsErrorKind::UnexpectedEof.into());
362 }
363 Ok(())
364 }
365}