use std::io;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct NoCapacity(u8);
impl std::fmt::Display for NoCapacity {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "No enough capacity")
}
}
impl std::error::Error for NoCapacity {}
#[derive(Debug, Clone, Copy)]
pub struct RingBuf<const CAP: usize> {
buffer: [u8; CAP],
tail: usize,
len: usize,
}
impl<const CAP: usize> Default for RingBuf<CAP> {
fn default() -> Self {
Self::new()
}
}
impl<const CAP: usize> RingBuf<CAP> {
pub const CAPACITY: usize = CAP;
pub const fn new() -> Self {
Self {
buffer: [0; CAP],
tail: 0,
len: 0,
}
}
pub const fn as_slices(&self) -> (&[u8], &[u8]) {
if self.is_contiguous() {
unsafe {
(
std::slice::from_raw_parts(&raw const self.buffer[self.tail], self.len),
std::slice::from_raw_parts(&raw const self.buffer[self.tail], 0),
)
}
} else {
let (mid, right) = self.buffer.split_at(self.tail);
let (left, _) = mid.split_at(self.head());
(right, left)
}
}
pub const fn as_mut_slices(&mut self) -> (&mut [u8], &mut [u8]) {
if self.is_contiguous() {
unsafe {
(
std::slice::from_raw_parts_mut(&raw mut self.buffer[self.tail], self.len),
std::slice::from_raw_parts_mut(&raw mut self.buffer[self.tail], 0),
)
}
} else {
let head = self.head();
let (mid, right) = self.buffer.split_at_mut(self.tail);
let (left, _) = mid.split_at_mut(head);
(right, left)
}
}
pub const fn push_back(&mut self, byte: u8) -> Result<(), NoCapacity> {
if self.is_full() {
Err(NoCapacity(byte))
} else {
self.buffer[self.head()] = byte;
self.len += 1;
Ok(())
}
}
pub const fn push_front(&mut self, byte: u8) -> Result<(), NoCapacity> {
if self.is_full() {
Err(NoCapacity(byte))
} else {
self.tail = Self::wrapping_sub(self.tail, 1);
self.buffer[self.tail] = byte;
self.len += 1;
Ok(())
}
}
pub const fn pop_back(&mut self) -> Option<u8> {
if self.is_empty() {
return None;
}
self.len -= 1;
let head = self.buffer[self.head()];
Some(head)
}
pub fn pop_n_back<const N: usize>(&mut self) -> Option<[u8; N]> {
if self.len < N {
return None;
}
let head = self.head();
let start = Self::wrapping_sub(head, N);
let mut chunk = [0; N];
if start > head {
chunk[..CAP - start].copy_from_slice(&self.buffer[start..CAP]);
chunk[CAP - start..].copy_from_slice(&self.buffer[..head]);
} else {
chunk.copy_from_slice(&self.buffer[start..head]);
};
self.len -= N;
Some(chunk)
}
pub fn pop_front(&mut self) -> Option<u8> {
if self.is_empty() {
return None;
}
let tail = self.buffer[self.tail];
self.tail = Self::wrapping_add(self.tail, 1);
self.len -= 1;
Some(tail)
}
pub fn pop_n_front<const N: usize>(&mut self) -> Option<[u8; N]> {
if self.len < N {
return None;
}
let end = Self::wrapping_add(self.tail, N);
let mut chunk = [0; N];
if self.tail > end {
chunk[..CAP - self.tail].copy_from_slice(&self.buffer[self.tail..CAP]);
chunk[CAP - self.tail..].copy_from_slice(&self.buffer[..end]);
} else {
chunk.copy_from_slice(&self.buffer[self.tail..end]);
}
self.tail = end;
self.len -= N;
Some(chunk)
}
pub const fn get(&self, index: usize) -> Option<&u8> {
if index < self.len {
let idx = Self::wrapping_add(self.tail, index);
Some(&self.buffer[idx])
} else {
None
}
}
pub const fn get_mut(&mut self, index: usize) -> Option<&mut u8> {
if index < self.len {
let idx = Self::wrapping_add(self.tail, index);
Some(&mut self.buffer[idx])
} else {
None
}
}
pub fn copy_to_writer(&mut self, writer: &mut (impl io::Write + ?Sized)) -> io::Result<usize> {
let (front, back) = self.as_slices();
let bufs = [io::IoSlice::new(front), io::IoSlice::new(back)];
let n = writer.write_vectored(&bufs)?;
self.tail = Self::wrapping_add(self.tail, n);
self.len -= n;
Ok(n)
}
pub fn copy_from_reader(&mut self, reader: &mut (impl io::Read + ?Sized)) -> io::Result<usize> {
let head = self.head();
let n = if head > self.tail {
reader.read(&mut self.buffer[self.tail..head])?
} else {
let (back, rem) = self.buffer.split_at_mut(head);
let (_, front) = rem.split_at_mut(self.tail);
let mut bufs = [io::IoSliceMut::new(front), io::IoSliceMut::new(back)];
reader.read_vectored(&mut bufs)?
};
self.len += n;
Ok(n)
}
const fn wrapping_add(tail: usize, rhs: usize) -> usize {
(tail + rhs) % CAP
}
const fn wrapping_sub(tail: usize, rhs: usize) -> usize {
(tail + CAP - rhs) % CAP
}
const fn head(&self) -> usize {
Self::wrapping_add(self.tail, self.len)
}
pub const fn is_full(&self) -> bool {
self.len == CAP
}
pub const fn is_empty(&self) -> bool {
self.len == 0
}
pub const fn is_contiguous(&self) -> bool {
self.len + self.tail < CAP
}
pub const fn len(&self) -> usize {
self.len
}
pub const fn capacity(&self) -> usize {
CAP
}
}
impl<const CAP: usize> io::Read for RingBuf<CAP> {
#[inline]
fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
let (ref mut front, ref mut back) = self.as_slices();
let mut n = front.read(buf)?;
if front.is_empty() {
buf = &mut buf[n..];
n += back.read(buf)?;
}
self.tail = Self::wrapping_add(self.tail, n);
self.len -= n;
if self.len == 0 {
self.tail = 0
}
Ok(n)
}
}
impl<const CAP: usize> io::Write for RingBuf<CAP> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if self.len == CAP {
return Ok(0);
}
let head = self.head();
let mut bytes = if head >= self.tail {
&mut self.buffer[head..]
} else {
&mut self.buffer[head..self.tail]
};
let n = bytes.write(buf)?;
self.len += n;
Ok(n)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}