use core::{
fmt::Debug,
iter::FusedIterator,
marker::PhantomData,
mem,
ptr::{self, NonNull},
slice,
};
use crate::{SizedTypeProperties, polyfill::non_null, traits::BumpAllocatorTyped};
pub struct IntoIter<T, A> {
ptr: NonNull<T>,
end: NonNull<T>,
#[expect(dead_code)]
allocator: A,
marker: PhantomData<(A, T)>,
}
unsafe impl<T: Send, A: Send> Send for IntoIter<T, A> {}
unsafe impl<T: Sync, A: Sync> Sync for IntoIter<T, A> {}
impl<T: Debug, A: BumpAllocatorTyped> Debug for IntoIter<T, A> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("IntoIter").field(&self.as_slice()).finish()
}
}
impl<T, A> IntoIter<T, A> {
pub(crate) unsafe fn new(slice: NonNull<[T]>, allocator: A) -> Self {
unsafe {
if T::IS_ZST {
IntoIter {
ptr: NonNull::dangling(),
end: non_null::wrapping_byte_add(NonNull::dangling(), slice.len()),
allocator,
marker: PhantomData,
}
} else {
let start = non_null::as_non_null_ptr(slice);
let end = start.add(slice.len());
IntoIter {
ptr: start,
end,
allocator,
marker: PhantomData,
}
}
}
}
#[must_use]
#[inline(always)]
pub fn len(&self) -> usize {
if T::IS_ZST {
self.end.addr().get().wrapping_sub(self.ptr.addr().get())
} else {
unsafe { non_null::offset_from_unsigned(self.end, self.ptr) }
}
}
#[must_use]
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.ptr == self.end
}
#[must_use]
pub fn as_slice(&self) -> &[T] {
unsafe { slice::from_raw_parts(self.ptr.as_ptr(), self.len()) }
}
#[must_use]
pub fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { &mut *self.as_raw_mut_slice() }
}
fn as_raw_mut_slice(&mut self) -> *mut [T] {
ptr::slice_from_raw_parts_mut(self.ptr.as_ptr(), self.len())
}
}
impl<T, A> AsRef<[T]> for IntoIter<T, A> {
#[inline]
fn as_ref(&self) -> &[T] {
self.as_slice()
}
}
impl<T, A> Iterator for IntoIter<T, A> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.ptr == self.end {
None
} else if T::IS_ZST {
self.end = unsafe { non_null::wrapping_byte_sub(self.end, 1) };
Some(unsafe { mem::zeroed() })
} else {
let old = self.ptr;
self.ptr = unsafe { self.ptr.add(1) };
Some(unsafe { old.read() })
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let exact = self.len();
(exact, Some(exact))
}
#[inline]
fn count(self) -> usize {
self.len()
}
}
impl<T, A> DoubleEndedIterator for IntoIter<T, A> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
if self.end == self.ptr {
None
} else if T::IS_ZST {
self.end = unsafe { non_null::wrapping_byte_sub(self.end, 1) };
Some(unsafe { mem::zeroed() })
} else {
self.end = unsafe { self.end.sub(1) };
Some(unsafe { self.end.read() })
}
}
}
impl<T, A> ExactSizeIterator for IntoIter<T, A> {}
impl<T, A> FusedIterator for IntoIter<T, A> {}
#[cfg(feature = "nightly-trusted-len")]
unsafe impl<T, A> core::iter::TrustedLen for IntoIter<T, A> {}
impl<T, A> Drop for IntoIter<T, A> {
#[inline]
fn drop(&mut self) {
unsafe {
NonNull::slice_from_raw_parts(self.ptr, self.len()).drop_in_place();
}
}
}