use core::mem::MaybeUninit;
pub struct RingBuf<T, const N: usize> {
buf: [T; N],
head: usize, tail: usize, }
pub struct RingBufIter<'a, T, const N: usize> {
buf: &'a [T; N],
current: usize,
remaining: usize,
}
impl<'a, T: Copy + Default, const N: usize> Iterator for RingBufIter<'a, T, N> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
if self.remaining == 0 {
return None;
}
let item = &self.buf[self.current];
self.current = (self.current + 1) % N;
self.remaining -= 1;
Some(item)
}
}
impl<'a, T: Copy + Default, const N: usize> IntoIterator for &'a RingBuf<T, N> {
type Item = &'a T;
type IntoIter = RingBufIter<'a, T, N>;
fn into_iter(self) -> Self::IntoIter {
RingBufIter {
buf: &self.buf,
current: self.tail,
remaining: self.len(),
}
}
}
impl<T: Copy + Default, const N: usize> RingBuf<T, N> {
pub const fn new() -> Self {
assert!(N > 1, "RINGBUF SIZE ERR");
Self {
buf: unsafe {
MaybeUninit::<[T; N]>::zeroed().assume_init()
},
head: 0,
tail: 0,
}
}
pub const fn capacity(&self) -> usize {
N - 1
}
pub fn len(&self) -> usize {
let h = self.head;
let t = self.tail;
if h >= t { h - t } else { N - t + h }
}
pub fn is_empty(&self) -> bool {
self.tail == self.head
}
pub fn is_full(&self) -> bool {
(self.head + 1) % N == self.tail
}
pub fn clear(&mut self) {
self.tail = self.head;
}
pub fn front(&self) -> Option<&T> {
if self.is_empty() {
None
} else {
Some(&self.buf[self.tail])
}
}
pub fn tail(&self) -> Option<&T> {
if self.is_empty() {
None
} else {
let idx = if self.head == 0 { N - 1 } else { self.head - 1 };
Some(&self.buf[idx])
}
}
pub fn pop(&mut self) -> Option<T> {
if !self.is_empty() {
let value = self.buf[self.tail];
self.tail = (self.tail + 1) % N;
Some(value)
} else {
None
}
}
pub fn push(&mut self, value: T) -> bool {
let next = (self.head + 1) % N;
if next == self.tail {
false
} else {
self.buf[self.head] = value;
self.head = next;
true
}
}
pub fn is_continuous(&self) -> bool {
self.is_empty() || self.tail < self.head
}
pub fn copy_to(&self, dest: &mut [T]) -> usize {
let n = dest.len().min(self.len());
if n == 0 {
return 0;
}
if self.is_continuous() {
dest[..n].copy_from_slice(&self.buf[self.tail..self.tail + n]);
} else {
let first = N - self.tail;
if first >= n {
dest[..n].copy_from_slice(&self.buf[self.tail..self.tail + n]);
} else {
dest[..first].copy_from_slice(&self.buf[self.tail..]);
dest[first..n].copy_from_slice(&self.buf[..n - first]);
}
}
n
}
}