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 let start = self.len;
112 let end = start + buf.len();
113 self.buf[start..end].copy_from_slice(buf);
114 self.len = end;
115 Ok(())
116 }
117
118 pub fn as_str(&self) -> Result<&str, Utf8Error> {
121 core::str::from_utf8(self.as_ref_used())
122 }
123 pub fn as_str_mut(&mut self) -> Result<&mut str, Utf8Error> {
126 core::str::from_utf8_mut(self.as_mut_used())
127 }
128
129 pub fn as_f64(&self) -> Result<f64, core::num::ParseFloatError> {
133 let s = self.as_str().unwrap_or_default();
134 core::str::FromStr::from_str(s)
135 }
136
137 pub fn reverse(&mut self) {
140 let mut i = 0;
141 let mut j = self.len - 1;
142 while i < j {
143 self.buf.swap(i, j);
144 i += 1;
145 j -= 1;
146 }
147 }
148
149 pub fn from_slice(buf: &[u8]) -> Self {
150 let mut out = Self::new();
151 buf.iter().take(N).for_each(|b| {
152 let _ = out.push_back(*b);
153 });
154 out
155 }
156}
157impl<const N: usize> WriteToBEBits for FixedU8Buf<N> {
158 fn write_be_to<T: MutBits + ?Sized>(&self, bits: &mut T) -> Result<usize, Error> {
159 bits.write_be_u32_blob(self.as_ref_used())?;
160 Ok(self.len + 4)
161 }
162}
163impl<const N: usize> ReadFromBEBits for FixedU8Buf<N> {
164 fn read_from_be_bits<T: Bits>(inp: &mut T) -> Result<Self, Error> {
165 let mut out = Self::new();
166 inp.read_u32_blob_into(&mut out)?;
167 Ok(out)
168 }
169}
170
171impl<const N: usize> AsRef<[u8]> for FixedU8Buf<N> {
172 #[allow(clippy::indexing_slicing)]
173 fn as_ref(&self) -> &[u8] {
174 &self.buf[..self.len]
175 }
176}
177impl<const N: usize> AsMut<[u8]> for FixedU8Buf<N> {
178 fn as_mut(&mut self) -> &mut [u8] {
179 &mut self.buf
180 }
181}
182impl<const N: usize> Default for FixedU8Buf<N> {
183 fn default() -> Self {
184 Self::new()
185 }
186}
187
188impl<const N: usize> core::fmt::Write for FixedU8Buf<N> {
189 fn write_str(&mut self, s: &str) -> core::fmt::Result {
190 self.append(s.as_bytes()).map_err(|_| core::fmt::Error)?;
191 Ok(())
192 }
193}
194
195impl<const N: usize> Buffer<u8> for FixedU8Buf<N> {
196 fn get(&self, index: usize) -> Option<&u8> {
197 if index >= N || index >= self.len {
198 return None;
199 }
200 self.buf.get(index)
201 }
202
203 fn get_mut(&mut self, index: usize) -> Option<&mut u8> {
204 if index >= N || index >= self.len {
205 return None;
206 }
207 self.buf.get_mut(index)
208 }
209
210 fn capacity(&self) -> usize {
211 N
212 }
213
214 fn len(&self) -> usize {
215 self.len
216 }
217
218 fn clear(&mut self) {
219 self.len = 0
220 }
221
222 fn front(&self) -> Option<&u8> {
223 self.get(0)
224 }
225
226 fn front_mut(&mut self) -> Option<&mut u8> {
227 self.get_mut(0)
228 }
229
230 fn back(&self) -> Option<&u8> {
231 if N == 0 || self.len == 0 {
232 return None;
233 }
234 self.get(self.len - 1)
235 }
236
237 fn back_mut(&mut self) -> Option<&mut u8> {
238 if N == 0 || self.len == 0 {
239 return None;
240 }
241 self.get_mut(self.len - 1)
242 }
243
244 fn pop_front(&mut self) -> Option<u8> {
245 if N == 0 || self.len == 0 {
246 return None;
247 }
248 let out = self.buf[0];
249 for idx in 1..self.len {
250 self.buf[idx - 1] = self.buf[idx];
251 }
252 self.len -= 1;
253 Some(out)
254 }
255
256 fn pop_back(&mut self) -> Option<u8> {
257 if N == 0 || self.len == 0 {
258 return None;
259 }
260 let idx = self.len - 1;
261 self.len -= 1;
262 let val = self.buf[idx];
263 self.buf[idx] = 0;
264 Some(val)
265 }
266
267 fn push_front(&mut self, value: u8) -> Result<(), u8> {
268 if N == 0 || self.len == N {
269 return Err(value);
270 }
271 for idx in 0..self.len {
272 self.buf[idx + 1] = self.buf[idx];
273 }
274 self.buf[0] = value;
275 self.len += 1;
276 Ok(())
277 }
278
279 fn push_back(&mut self, value: u8) -> Result<(), u8> {
280 if N == 0 || self.len == N {
281 return Err(value);
282 }
283 self.buf[self.len] = value;
284 self.len += 1;
285 Ok(())
286 }
287}
288
289#[allow(clippy::panic)]
290impl<const N: usize> Index<usize> for FixedU8Buf<N> {
291 type Output = u8;
292
293 fn index(&self, index: usize) -> &Self::Output {
294 assert!(index < self.len, "index {index} >= len {}", self.len);
295 let Some(val) = self.buf.get(index) else {
296 panic!("expected value at offset {index} but was empty!");
297 };
298 val
299 }
300}
301#[allow(clippy::panic)]
302impl<const N: usize> IndexMut<usize> for FixedU8Buf<N> {
303 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
304 assert!(index < N, "index {index} >= capacity {N}");
305 if index >= self.len {
306 self.len = index + 1;
307 }
308 &mut self.buf[index]
309 }
310}
311pub struct FixedU8BufIter<'a, const N: usize> {
312 buf: &'a FixedU8Buf<N>,
313 idx: usize,
314}
315
316impl<'a, const N: usize> Iterator for FixedU8BufIter<'a, N> {
317 type Item = &'a u8;
318 fn next(&mut self) -> Option<Self::Item> {
319 if let Some(val) = self.buf.get(self.idx) {
320 self.idx += 1;
321 return Some(val);
322 }
323 None
324 }
325}
326impl<const N: usize> DoubleEndedIterator for FixedU8BufIter<'_, N> {
327 fn next_back(&mut self) -> Option<Self::Item> {
328 if self.idx >= self.buf.len {
329 return None;
330 }
331 let idx = self.buf.len().saturating_sub(self.idx).saturating_sub(1);
332
333 self.idx += 1;
334 if let Some(val) = self.buf.get(idx) {
335 return Some(val);
336 }
337 None
338 }
339}
340impl<const N: usize> ExactSizeIterator for FixedU8BufIter<'_, N> {
341 fn len(&self) -> usize {
342 self.buf.len()
343 }
344}
345
346pub struct FixedU8BufIterMut<'a, const N: usize> {
347 buf: &'a mut FixedU8Buf<N>,
348 idx: usize,
349}
350
351impl<const N: usize> LendingIterator for FixedU8BufIterMut<'_, N> {
352 type Item<'b>
353 = &'b mut u8
354 where
355 Self: 'b;
356
357 fn next_ref(&mut self) -> Option<Self::Item<'_>> {
358 if let Some(val) = self.buf.get_mut(self.idx) {
359 self.idx += 1;
360 return Some(val);
361 }
362 None
363 }
364}
365
366impl<const N: usize> MutBits for &mut FixedU8Buf<N> {
367 fn write_u8(&mut self, val: u8) -> Result<(), Error> {
368 if self.push_back(val).is_err() {
369 return Err(BitsErrorKind::UnexpectedEof.into());
370 }
371 Ok(())
372 }
373
374 fn write_all_bytes(&mut self, val: &[u8]) -> Result<(), Error> {
375 self.append(val)
376 }
377}
378impl<const N: usize> MutBits for FixedU8Buf<N> {
379 fn write_u8(&mut self, val: u8) -> Result<(), Error> {
380 if self.push_back(val).is_err() {
381 return Err(BitsErrorKind::UnexpectedEof.into());
382 }
383 Ok(())
384 }
385
386 fn write_all_bytes(&mut self, val: &[u8]) -> Result<(), Error> {
387 self.append(val)
388 }
389}
390
391impl<const N: usize> Bits for FixedU8Buf<N> {
392 fn next_u8(&mut self) -> Result<Option<u8>, Error> {
393 Ok(self.pop_front())
394 }
395}