use core::mem::MaybeUninit;
use std::{boxed::Box, vec::Vec};
pub(crate) struct Ring<T> {
slots: Box<[MaybeUninit<T>]>,
head: usize,
len: usize,
}
impl<T> Ring<T> {
pub(super) fn with_capacity(cap: usize) -> Self {
debug_assert!(cap > 0, "a bounded ring needs a non-zero capacity");
let mut slots = Vec::with_capacity(cap);
slots.resize_with(cap, MaybeUninit::uninit);
Self {
slots: slots.into_boxed_slice(),
head: 0,
len: 0,
}
}
#[inline(always)]
pub(super) fn cap(&self) -> usize {
self.slots.len()
}
#[inline(always)]
pub(super) fn len(&self) -> usize {
self.len
}
#[inline(always)]
pub(super) fn is_empty(&self) -> bool {
self.len == 0
}
#[inline(always)]
pub(super) fn is_full(&self) -> bool {
self.len == self.cap()
}
#[inline(always)]
pub(super) fn push(&mut self, item: T) -> Result<(), T> {
if self.is_full() {
return Err(item);
}
let tail = (self.head + self.len) % self.cap();
self.slots[tail].write(item);
self.len += 1;
Ok(())
}
#[inline(always)]
pub(super) fn pop(&mut self) -> Option<T> {
if self.len == 0 {
return None;
}
let item = unsafe { self.slots[self.head].assume_init_read() };
self.head = (self.head + 1) % self.cap();
self.len -= 1;
Some(item)
}
#[inline(always)]
pub(super) fn clear(&mut self) {
while self.pop().is_some() {}
}
}
impl<T> Drop for Ring<T> {
fn drop(&mut self) {
self.clear();
}
}
#[cfg(all(test, feature = "std"))]
mod tests;