use crate::{ChunkFooter, Stack};
use core::iter::Iterator;
use core::ptr::NonNull;
pub struct Iter<'a, T> {
_stack: &'a Stack<T>,
current_footer: NonNull<ChunkFooter>,
ptr_or_idx: *const T,
end_or_len: *const T,
}
impl<'a, T> Iter<'a, T> {
pub(crate) fn new(stack: &'a Stack<T>) -> Self {
let current_footer = unsafe { stack.current_footer.get().as_ref() };
if const { Stack::<T>::ELEMENT_IS_ZST } {
Self {
_stack: stack,
current_footer: current_footer.get(),
ptr_or_idx: core::ptr::without_provenance(0),
end_or_len: core::ptr::without_provenance(stack.len()),
}
} else {
let ptr = unsafe { stack.first_footer.get().as_ref().data.cast().as_ptr() };
let end = current_footer.ptr.get().cast().as_ptr();
Self {
_stack: stack,
current_footer: stack.first_footer.get(),
ptr_or_idx: ptr,
end_or_len: end,
}
}
}
}
impl<'a, T> Iter<'a, T> {
#[inline(always)]
unsafe fn next_element_fast(&mut self) -> Option<NonNull<T>> {
unsafe {
let current_footer = self.current_footer.as_ref();
let chunk_ptr = current_footer.ptr.get().cast().as_ptr();
if self.ptr_or_idx != chunk_ptr {
let ptr = self.ptr_or_idx;
self.ptr_or_idx = ptr.byte_add(Stack::<T>::ELEMENT_SIZE);
Some(NonNull::new_unchecked(ptr as *mut T))
} else {
None
}
}
}
unsafe fn next_element_slow(&mut self) -> Option<NonNull<T>> {
unsafe {
let current_footer = self.current_footer.as_ref();
self.current_footer = current_footer.next.get();
let current_footer = self.current_footer.as_ref();
self.ptr_or_idx = current_footer.data.cast().as_ptr();
self.next_element_fast()
}
}
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if const { Stack::<T>::ELEMENT_IS_ZST } {
if self.ptr_or_idx < self.end_or_len {
unsafe {
self.ptr_or_idx = self.ptr_or_idx.wrapping_byte_add(1);
Some(self.current_footer.cast().as_ref())
}
} else {
None
}
} else {
if self.ptr_or_idx == self.end_or_len {
return None;
}
unsafe {
if let Some(elem_ptr) = self.next_element_fast() {
Some(elem_ptr.as_ref())
} else {
self.next_element_slow().map(|ptr| ptr.as_ref())
}
}
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
if const { Stack::<T>::ELEMENT_IS_ZST } {
let remains = self.end_or_len as usize - self.ptr_or_idx as usize;
(remains, Some(remains))
} else {
(0, None)
}
}
#[inline]
fn count(self) -> usize
where
Self: Sized,
{
if const { Stack::<T>::ELEMENT_IS_ZST } {
self.end_or_len as usize - self.ptr_or_idx as usize
} else {
self.fold(0, |count, _| count + 1)
}
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
let m = n + 1;
let mut need = m * Stack::<T>::ELEMENT_SIZE;
if const { Stack::<T>::ELEMENT_IS_ZST } {
let index = self.ptr_or_idx as usize;
let length = self.end_or_len as usize;
if length - index > n {
unsafe {
self.ptr_or_idx = self.ptr_or_idx.wrapping_byte_add(m);
Some(self.current_footer.cast().as_ref())
}
} else {
self.ptr_or_idx = self.end_or_len;
None
}
} else {
loop {
let current_footer = unsafe { self.current_footer.as_ref() };
let current_start = current_footer.data.as_ptr() as *const T;
let current_end = current_footer.ptr.get().as_ptr() as *const T;
let ptr = self.ptr_or_idx;
let end = self.end_or_len;
if current_start <= end && end <= current_end {
let size = end as usize - ptr as usize;
if need <= size {
let new_ptr = ptr.wrapping_byte_add(need);
let ptr = ptr.wrapping_byte_add(need - Stack::<T>::ELEMENT_SIZE);
self.ptr_or_idx = new_ptr;
break Some(unsafe { &*ptr });
} else {
self.ptr_or_idx = end;
break None;
}
} else {
debug_assert!(current_start <= ptr && ptr <= current_end);
let size = current_end as usize - ptr as usize;
if need <= size {
let new_ptr = ptr.wrapping_byte_add(need);
let ptr = ptr.wrapping_byte_add(need - Stack::<T>::ELEMENT_SIZE);
self.ptr_or_idx = new_ptr;
break Some(unsafe { &*ptr });
} else {
need -= size;
self.current_footer = current_footer.next.get();
self.ptr_or_idx =
unsafe { self.current_footer.as_ref().data.cast().as_ptr() };
}
}
}
}
}
}