use core::{mem::MaybeUninit, num::NonZeroUsize, ops::Range, ptr, slice};
pub trait RbBase<T> {
#[allow(clippy::mut_from_ref)]
unsafe fn data(&self) -> &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());
}
fn occupied_ranges(&self) -> (Range<usize>, Range<usize>) {
let head = self.head();
let tail = self.tail();
let len = self.capacity_nonzero();
let (head_div, head_mod) = (head / len, head % len);
let (tail_div, tail_mod) = (tail / len, tail % len);
if head_div == tail_div {
(head_mod..tail_mod, 0..0)
} else {
(head_mod..len.get(), 0..tail_mod)
}
}
unsafe fn occupied_slices(&self) -> (&mut [MaybeUninit<T>], &mut [MaybeUninit<T>]) {
let ranges = self.occupied_ranges();
let ptr = self.data().as_mut_ptr();
(
slice::from_raw_parts_mut(ptr.add(ranges.0.start), ranges.0.len()),
slice::from_raw_parts_mut(ptr.add(ranges.1.start), ranges.1.len()),
)
}
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());
}
fn vacant_ranges(&self) -> (Range<usize>, Range<usize>) {
let head = self.head();
let tail = self.tail();
let len = self.capacity_nonzero();
let (head_div, head_mod) = (head / len, head % len);
let (tail_div, tail_mod) = (tail / len, tail % len);
if head_div == tail_div {
(tail_mod..len.get(), 0..head_mod)
} else {
(tail_mod..head_mod, 0..0)
}
}
unsafe fn vacant_slices(&self) -> (&mut [MaybeUninit<T>], &mut [MaybeUninit<T>]) {
let ranges = self.vacant_ranges();
let ptr = self.data().as_mut_ptr();
(
slice::from_raw_parts_mut(ptr.add(ranges.0.start), ranges.0.len()),
slice::from_raw_parts_mut(ptr.add(ranges.1.start), ranges.1.len()),
)
}
}