#![allow(clippy::len_without_is_empty)]
#![allow(clippy::new_without_default)]
use core::mem::MaybeUninit as MU;
pub struct MUBuf<const SIZE: usize> {
buf: [MU<u8>; SIZE],
len: usize,
}
impl<const SIZE: usize> MUBuf<SIZE> {
pub const fn new() -> Self {
Self {
len: 0,
buf: [const { MU::uninit() }; SIZE],
}
}
pub fn len(&self) -> usize {
self.len
}
pub const fn capacity(&self) -> usize {
SIZE
}
pub fn clear(&mut self) {
self.len = 0;
}
pub fn spare_capacity_mut(&mut self) -> &mut [MU<u8>] {
&mut self.buf[self.len..]
}
#[allow(clippy::result_unit_err)]
pub fn extend_from_slice(&mut self, other: &[u8]) -> Result<(), ()> {
let end = self.len + other.len();
if end > SIZE {
return Err(());
}
for (dst, &src) in self.buf[self.len..end].iter_mut().zip(other) {
dst.write(src);
}
self.len = end;
Ok(())
}
pub fn as_slice(&self) -> &[u8] {
self.as_ref()
}
pub unsafe fn set_len(&mut self, len: usize) {
self.len = len;
}
}
impl<const SIZE: usize> Default for MUBuf<SIZE> {
fn default() -> Self {
Self::new()
}
}
impl<const SIZE: usize> PartialEq for MUBuf<SIZE> {
fn eq(&self, other: &Self) -> bool {
self.as_ref() == other.as_ref()
}
}
impl<const SIZE: usize> Eq for MUBuf<SIZE> {}
impl<const SIZE: usize> core::fmt::Debug for MUBuf<SIZE> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Debug::fmt(self.as_ref(), f)
}
}
impl<const SIZE: usize> AsRef<[u8]> for MUBuf<SIZE> {
fn as_ref(&self) -> &[u8] {
let filled_mu = &self.buf[..self.len];
unsafe { filled_mu.assume_init_ref() }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn spare_capacity_starts_after_initialized_region() {
let mut buf = MUBuf::<8>::new();
assert_eq!(buf.spare_capacity_mut().len(), 8);
buf.extend_from_slice(&[1, 2, 3]).unwrap();
assert_eq!(buf.spare_capacity_mut().len(), 5);
buf.clear();
assert_eq!(buf.spare_capacity_mut().len(), 8);
}
}