use crate::utils::ring_buffer_ranges;
use core::{mem::MaybeUninit, num::NonZeroUsize, ops::Range, ptr};
pub trait RbBase<T> {
unsafe fn slices(
&self,
head: usize,
tail: usize,
) -> (&mut [MaybeUninit<T>], &mut [MaybeUninit<T>]);
fn capacity_nonzero(&self) -> NonZeroUsize;
fn head(&self) -> usize;
fn tail(&self) -> usize;
#[inline]
fn modulus(&self) -> NonZeroUsize {
unsafe { NonZeroUsize::new_unchecked(2 * self.capacity_nonzero().get()) }
}
fn occupied_len(&self) -> usize {
let modulus = self.modulus();
(modulus.get() + self.tail() - self.head()) % modulus
}
fn vacant_len(&self) -> usize {
let modulus = self.modulus();
(self.capacity_nonzero().get() + self.head() - self.tail()) % modulus
}
fn is_empty(&self) -> bool {
self.head() == self.tail()
}
fn is_full(&self) -> bool {
self.vacant_len() == 0
}
}
pub trait RbRead<T>: RbBase<T> {
unsafe fn set_head(&self, value: usize);
unsafe fn advance_head(&self, count: usize) {
debug_assert!(count <= self.occupied_len());
self.set_head((self.head() + count) % self.modulus());
}
#[inline]
fn occupied_ranges(&self) -> (Range<usize>, Range<usize>) {
ring_buffer_ranges(self.capacity_nonzero(), self.head(), self.tail())
}
#[inline]
unsafe fn occupied_slices(&self) -> (&mut [MaybeUninit<T>], &mut [MaybeUninit<T>]) {
self.slices(self.head(), self.tail())
}
unsafe fn skip_internal(&self, count_or_all: Option<usize>) -> usize {
let (left, right) = self.occupied_slices();
let count = match count_or_all {
Some(count) => {
debug_assert!(count <= left.len() + right.len());
count
}
None => left.len() + right.len(),
};
for elem in left.iter_mut().chain(right.iter_mut()).take(count) {
ptr::drop_in_place(elem.as_mut_ptr());
}
self.advance_head(count);
count
}
}
pub trait RbWrite<T>: RbBase<T> {
unsafe fn set_tail(&self, value: usize);
unsafe fn advance_tail(&self, count: usize) {
debug_assert!(count <= self.vacant_len());
self.set_tail((self.tail() + count) % self.modulus());
}
#[inline]
fn vacant_ranges(&self) -> (Range<usize>, Range<usize>) {
ring_buffer_ranges(
self.capacity_nonzero(),
self.tail(),
self.head() + self.capacity_nonzero().get(),
)
}
#[inline]
unsafe fn vacant_slices(&self) -> (&mut [MaybeUninit<T>], &mut [MaybeUninit<T>]) {
self.slices(self.tail(), self.head() + self.capacity_nonzero().get())
}
}