use core::fmt::{self, Debug};
use core::mem::{ManuallyDrop, MaybeUninit};
#[repr(C)]
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))]
pub struct ArrayConsumer<T, const N: usize> {
array: [MaybeUninit<T>; N],
taken_front: usize,
taken_back: usize,
}
impl<T, const N: usize> ArrayConsumer<T, N> {
pub const fn new(array: [T; N]) -> Self {
Self {
array: array_into_md(array),
taken_front: 0,
taken_back: 0,
}
}
pub const fn empty() -> Self {
Self {
array: crate::maybe_uninit::uninit_array(),
taken_front: N,
taken_back: 0,
}
}
const fn is_empty(&self) -> bool {
(N - self.taken_front - self.taken_back) == 0
}
const fn slice_len(&self) -> usize {
N - self.taken_front - self.taken_back
}
#[track_caller]
pub const fn assert_is_empty(self) {
assert!(self.is_empty());
core::mem::forget(self);
}
pub const fn as_slice(&self) -> &[T] {
unsafe {
let ptr = self.array.as_ptr().add(self.taken_front).cast::<T>();
core::slice::from_raw_parts(ptr, self.slice_len())
}
}
pub const fn as_mut_slice(&mut self) -> &mut [T] {
unsafe {
let ptr = self.array.as_mut_ptr().add(self.taken_front).cast::<T>();
core::slice::from_raw_parts_mut(ptr, self.slice_len())
}
}
pub const fn copy(&self) -> Self
where
T: Copy
{
Self {..*self}
}
pub const fn next(&mut self) -> Option<ManuallyDrop<T>> {
if self.is_empty() {
return None;
}
let ret = unsafe { self.array[self.taken_front].assume_init_read() };
self.taken_front += 1;
Some(ManuallyDrop::new(ret))
}
pub const fn next_back(&mut self) -> Option<ManuallyDrop<T>> {
if self.is_empty() {
return None;
}
let index = N - self.taken_back - 1;
let ret = unsafe { self.array[index].assume_init_read() };
self.taken_back += 1;
Some(ManuallyDrop::new(ret))
}
}
impl<T: Debug, const N: usize> Debug for ArrayConsumer<T, N> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
Debug::fmt(self.as_slice(), fmt)
}
}
impl<T: Clone, const N: usize> Clone for ArrayConsumer<T, N> {
fn clone(&self) -> Self {
let mut this = Self {
array: crate::maybe_uninit::uninit_array(),
taken_front: 0,
taken_back: N,
};
for (i, elem) in self.as_slice().iter().cloned().enumerate() {
this.array[i] = MaybeUninit::new(elem);
this.taken_back -= 1;
}
this
}
}
impl<T, const N: usize> Drop for ArrayConsumer<T, N> {
fn drop(&mut self) {
unsafe {
let slice_len = self.slice_len();
let ptr = self.array.as_mut_ptr().cast::<T>();
core::ptr::slice_from_raw_parts_mut(ptr.add(self.taken_front), slice_len).drop_in_place();
}
}
}
#[doc(hidden)]
const fn array_into_md<T, const N: usize>(arr: [T; N]) -> [MaybeUninit<T>; N] {
unsafe {
crate::__::__priv_transmute! {[T; N], [MaybeUninit<T>; N], arr}
}
}