#![allow(dead_code)]
use core::fmt;
use core::mem::MaybeUninit;
pub type Idx = u16;
#[derive(Clone)]
pub struct RingBuf<T: Copy, const CAP: usize> {
mem: [MaybeUninit<T>; CAP],
start: Idx,
end: Idx,
}
impl<T: Copy, const CAP: usize> RingBuf<T, CAP> {
pub const fn new() -> Self {
assert!(CAP.is_power_of_two(), "capacity must be a power of two");
assert!(
CAP <= Idx::MAX as usize / 2,
"capacity must be at most half of the max index"
);
Self {
mem: [MaybeUninit::uninit(); CAP],
start: 0,
end: 0,
}
}
pub const fn len(&self) -> Idx {
self.end.wrapping_sub(self.start)
}
pub const fn is_empty(&self) -> bool {
self.start == self.end
}
pub const fn is_full(&self) -> bool {
self.len() as usize == CAP
}
#[must_use]
pub fn try_push(&mut self, elem: T) -> Option<()> {
if self.is_full() {
return None;
}
unsafe {
self.push_unchecked(elem);
}
Some(())
}
pub fn push(&mut self, elem: T) {
if self.is_full() {
unsafe {
self.pop_unchecked();
}
}
unsafe {
self.push_unchecked(elem);
}
}
pub fn pop(&mut self) -> Option<T> {
if self.is_empty() {
return None;
}
let elem = unsafe { self.pop_unchecked() };
Some(elem)
}
pub fn clear(&mut self) {
self.end = self.start;
}
pub fn truncate_front(&mut self, new_len: Idx) {
if new_len < self.len() {
self.end = self.start.wrapping_add(new_len);
}
}
pub fn truncate_back(&mut self, new_len: Idx) {
if new_len < self.len() {
self.start = self.end.wrapping_sub(new_len);
}
}
pub const fn iter(&self) -> Iter<'_, T, CAP> {
Iter {
mem: &self.mem,
start: self.start,
end: self.end,
}
}
}
impl<T: Copy, const CAP: usize> RingBuf<T, CAP> {
unsafe fn push_unchecked(&mut self, elem: T) {
debug_assert!(!self.is_full());
let ptr = self.mem.as_mut_ptr().cast::<T>().add(Self::mask(self.end));
ptr.write(elem);
self.end = self.end.wrapping_add(1);
}
unsafe fn pop_unchecked(&mut self) -> T {
debug_assert!(!self.is_empty());
let ptr = self.mem.as_ptr().cast::<T>().add(Self::mask(self.start));
self.start = self.start.wrapping_add(1);
ptr.read()
}
}
impl<T: Copy, const CAP: usize> RingBuf<T, CAP> {
const fn mask(val: Idx) -> usize {
val as usize % CAP
}
}
impl<T: Copy + fmt::Debug, const CAP: usize> fmt::Debug for RingBuf<T, CAP> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut dbg = f.debug_list();
for elem in self.iter() {
dbg.entry(elem);
}
dbg.finish()
}
}
impl<T: Copy, const CAP: usize> FromIterator<T> for RingBuf<T, CAP> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let mut buf = Self::new();
for elem in iter {
buf.try_push(elem)
.expect("iterator exceeds RingBuf capacity");
}
buf
}
}
impl<const N: usize, T: Copy + PartialEq, const CAP: usize> PartialEq<[T; N]> for RingBuf<T, CAP> {
fn eq(&self, other: &[T; N]) -> bool {
self.len() as usize == other.len() && self.iter().zip(other).all(|(a, b)| a == b)
}
}
pub struct Iter<'a, T: Copy, const CAP: usize> {
mem: &'a [MaybeUninit<T>; CAP],
start: Idx,
end: Idx,
}
impl<'a, T: Copy, const CAP: usize> Iterator for Iter<'a, T, CAP> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
if self.start == self.end {
return None;
}
unsafe {
let ptr = self
.mem
.as_ptr()
.cast::<T>()
.add(RingBuf::<T, CAP>::mask(self.start));
self.start = self.start.wrapping_add(1);
let elem_ref = ptr.as_ref();
debug_assert!(
elem_ref.is_some(),
"slices have non-null pointers (according to docs for slice::from_raw_parts)"
);
Some(elem_ref.unwrap_unchecked())
}
}
}
impl<'a, T: Copy, const CAP: usize> DoubleEndedIterator for Iter<'a, T, CAP> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.start == self.end {
return None;
}
unsafe {
self.end = self.end.wrapping_sub(1);
let ptr = self
.mem
.as_ptr()
.cast::<T>()
.add(RingBuf::<T, CAP>::mask(self.end));
let elem_ref = ptr.as_ref();
debug_assert!(
elem_ref.is_some(),
"slices have non-null pointers (according to docs for slice::from_raw_parts)"
);
Some(elem_ref.unwrap_unchecked())
}
}
}