use std::mem;
pub struct Inline<T, const N: usize> {
slots: [mem::MaybeUninit<T>; N],
head: usize,
tail: usize,
}
#[must_use = "an empty batch proof does nothing unless it is used to fill the batch"]
#[repr(transparent)]
pub struct Fill<'a, T, const N: usize> {
batch: &'a mut Inline<T, N>,
}
#[repr(transparent)]
pub struct Vacant<'a, T, const N: usize> {
batch: &'a mut Inline<T, N>,
}
#[repr(transparent)]
pub struct FrontVacant<'a, T, const N: usize> {
batch: &'a mut Inline<T, N>,
}
impl<T, const N: usize> Inline<T, N> {
#[inline]
pub const fn new() -> Self {
Self {
slots: [const { mem::MaybeUninit::uninit() }; N],
head: 0,
tail: 0,
}
}
#[inline]
pub fn fill(&mut self) -> Option<Fill<'_, T, N>> {
if !self.is_empty() {
return None;
}
self.head = 0;
self.tail = 0;
Some(Fill { batch: self })
}
#[inline]
pub fn pop_front(&mut self) -> Option<T> {
if self.is_empty() {
return None;
}
let index = self.head;
self.head += 1;
Some(unsafe { self.slots[index].assume_init_read() })
}
#[inline]
pub fn pop_front_reserved(&mut self) -> Option<(T, FrontVacant<'_, T, N>)> {
let value = self.pop_front()?;
Some((value, FrontVacant { batch: self }))
}
#[inline]
pub fn clear(&mut self) {
while let Some(value) = self.pop_front() {
drop(value);
}
self.head = 0;
self.tail = 0;
}
#[inline]
pub const fn capacity(&self) -> usize {
N
}
#[inline]
pub const fn len(&self) -> usize {
self.tail - self.head
}
#[inline]
pub const fn is_empty(&self) -> bool {
self.head == self.tail
}
}
impl<T, const N: usize> Fill<'_, T, N> {
#[inline]
pub fn vacant_entry(&mut self) -> Option<Vacant<'_, T, N>> {
if self.batch.tail == N {
None
} else {
Some(Vacant { batch: self.batch })
}
}
}
impl<T, const N: usize> Vacant<'_, T, N> {
#[inline]
pub fn insert(self, value: T) {
let index = self.batch.tail;
self.batch.slots[index].write(value);
self.batch.tail = index + 1;
}
}
impl<T, const N: usize> FrontVacant<'_, T, N> {
#[inline]
pub fn restore(self, value: T) {
self.batch.head -= 1;
self.batch.slots[self.batch.head].write(value);
}
}
impl<T, const N: usize> Default for Inline<T, N> {
fn default() -> Self {
Self::new()
}
}
impl<T, const N: usize> Drop for Inline<T, N> {
fn drop(&mut self) {
self.clear();
}
}