use core::{fmt, iter, mem, ptr};
pub struct StackIntoIter<T, const N: usize> {
items: [mem::MaybeUninit<T>; N],
top_len: usize,
bottom_len: usize,
}
impl<T, const N: usize> StackIntoIter<T, N> {
#[inline]
pub(super) const unsafe fn new(items: [mem::MaybeUninit<T>; N], top_len: usize) -> Self {
Self {
items,
top_len,
bottom_len: 0,
}
}
#[inline]
fn pop_top(&mut self) -> Option<T> {
debug_assert!(self.bottom_len <= self.top_len);
if self.top_len == self.bottom_len {
None
} else {
self.top_len -= 1;
Some(unsafe { ptr::read(self.items.as_ptr().add(self.top_len)).assume_init() })
}
}
#[inline]
fn pop_bottom(&mut self) -> Option<T> {
debug_assert!(self.bottom_len <= self.top_len);
if self.bottom_len == self.top_len {
None
} else {
let result =
Some(unsafe { ptr::read(self.items.as_ptr().add(self.bottom_len)).assume_init() });
self.bottom_len += 1;
result
}
}
}
impl<T, const N: usize> Iterator for StackIntoIter<T, N> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.pop_top()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.bottom_len, Some(self.top_len))
}
}
impl<T, const N: usize> iter::DoubleEndedIterator for StackIntoIter<T, N> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.pop_bottom()
}
}
impl<T, const N: usize> Default for StackIntoIter<T, N> {
#[inline]
fn default() -> Self {
Self {
top_len: 0,
bottom_len: 0,
items: unsafe { mem::MaybeUninit::uninit().assume_init() },
}
}
}
impl<T, const N: usize> Clone for StackIntoIter<T, N>
where
T: Clone,
{
#[inline]
fn clone(&self) -> Self {
unsafe {
let mut items = mem::MaybeUninit::<[mem::MaybeUninit<T>; N]>::uninit().assume_init();
self.items
.get_unchecked(self.bottom_len..self.top_len)
.iter()
.zip(items.get_unchecked_mut(self.bottom_len..self.top_len))
.for_each(|(src, dst)| {
dst.write(src.assume_init_ref().clone());
});
Self {
items,
top_len: self.top_len,
bottom_len: self.bottom_len,
}
}
}
}
impl<T, const N: usize> Drop for StackIntoIter<T, N> {
#[inline]
fn drop(&mut self) {
debug_assert!(self.bottom_len <= self.top_len);
unsafe {
let items = self.items.get_unchecked_mut(self.bottom_len..self.top_len)
as *mut [mem::MaybeUninit<T>] as *mut [T];
ptr::drop_in_place(items);
}
}
}
impl<T, const N: usize> fmt::Debug for StackIntoIter<T, N>
where
T: fmt::Debug,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut list = f.debug_list();
unsafe {
list.entries(
self.items
.get_unchecked(self.bottom_len..self.top_len)
.iter()
.map(|item| item.assume_init_ref()),
);
}
list.finish()
}
}
impl<T, const N: usize> iter::FusedIterator for StackIntoIter<T, N> {}
impl<T, const N: usize, const M: usize> PartialEq<StackIntoIter<T, M>> for StackIntoIter<T, N>
where
T: PartialEq,
{
#[inline]
fn eq(&self, other: &StackIntoIter<T, M>) -> bool {
unsafe {
let items1 = self.items.get_unchecked(self.bottom_len..self.top_len)
as *const [mem::MaybeUninit<T>] as *const [T];
let items2 = other.items.get_unchecked(other.bottom_len..other.top_len)
as *const [mem::MaybeUninit<T>] as *const [T];
*items1 == *items2
}
}
}