use core::fmt::{self, Debug};
use core::mem::{ManuallyDrop, MaybeUninit};
use crate::{
drop_flavor::{DropFlavor, MayDrop, NonDrop, as_inner, as_inner_mut, wrap},
iter::{ConstIntoIter, IntoIterWrapper, IsIteratorKind, IsStdKind},
};
use typewit::Identity;
#[repr(C)]
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))]
pub struct IntoIter<T, const N: usize, D: DropFlavor> {
inner: D::Wrap<IntoIterInner<T, N>>,
}
#[repr(C)]
pub struct IntoIterInner<T, const N: usize> {
array: [MaybeUninit<T>; N],
taken_front: usize,
taken_back: usize,
}
impl<T, const N: usize> IntoIterInner<T, N> {
const fn into_ii<D: DropFlavor>(self) -> IntoIter<T, N, D> {
IntoIter { inner: wrap(self) }
}
const fn slice_len(&self) -> usize {
N - self.taken_front - self.taken_back
}
}
impl<T, const N: usize> ConstIntoIter for [T; N] {
type Kind = IsStdKind;
type IntoIter = IntoIter<T, N, MayDrop>;
type Item = T;
const ITEMS_NEED_DROP: bool = core::mem::needs_drop::<T>();
}
impl<T, const N: usize> IntoIterWrapper<[T; N], IsStdKind> {
pub const fn const_into_iter(self) -> IntoIter<T, N, MayDrop> {
IntoIter::of_drop(ManuallyDrop::into_inner(self.iter))
}
}
impl<T, const N: usize, D: DropFlavor> ConstIntoIter for IntoIter<T, N, D> {
type Kind = IsIteratorKind;
type IntoIter = IntoIter<T, N, D>;
type Item = T;
const ITEMS_NEED_DROP: bool = core::mem::needs_drop::<T>();
}
impl<T, const N: usize> IntoIter<T, N, MayDrop> {
pub const fn of_drop<const N2: usize>(array: [T; N]) -> Self
where
Self: Identity<Type = IntoIter<T, N2, MayDrop>>,
{
IntoIterInner {
array: array_into_md(array),
taken_front: 0,
taken_back: 0,
}
.into_ii()
}
}
impl<T, const N: usize> IntoIter<T, N, NonDrop> {
pub const fn of_copy<const N2: usize>(array: [T; N]) -> Self
where
T: Copy,
Self: Identity<Type = IntoIter<T, N2, NonDrop>>,
{
IntoIterInner {
array: array_into_md(array),
taken_front: 0,
taken_back: 0,
}
.into_ii()
}
pub const fn of_assumed_nondrop<const N2: usize>(array: [T; N]) -> Self
where
Self: Identity<Type = IntoIter<T, N2, NonDrop>>,
{
IntoIterInner {
array: array_into_md(array),
taken_front: 0,
taken_back: 0,
}
.into_ii()
}
pub const fn empty<const N2: usize>() -> Self
where
Self: Identity<Type = IntoIter<T, N2, NonDrop>>,
{
IntoIterInner {
array: crate::maybe_uninit::uninit_array(),
taken_front: N,
taken_back: 0,
}
.into_ii()
}
}
impl<T, const N: usize, D: DropFlavor> IntoIter<T, N, D> {
pub const fn next(&mut self) -> Option<T> {
if self.is_empty() {
return None;
}
let this = as_inner_mut::<D, _>(&mut self.inner);
let ret = unsafe { this.array[this.taken_front].assume_init_read() };
this.taken_front += 1;
Some(ret)
}
pub const fn next_back(&mut self) -> Option<T> {
if self.is_empty() {
return None;
}
let this = as_inner_mut::<D, _>(&mut self.inner);
let index = N - this.taken_back - 1;
let ret = unsafe { this.array[index].assume_init_read() };
this.taken_back += 1;
Some(ret)
}
pub const fn rev(self) -> IntoIterRev<T, N, D> {
IntoIterRev(self)
}
const fn is_empty(&self) -> bool {
let this = as_inner::<D, _>(&self.inner);
(N - this.taken_front - this.taken_back) == 0
}
#[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 this = as_inner::<D, _>(&self.inner);
let ptr = this.array.as_ptr().add(this.taken_front).cast::<T>();
core::slice::from_raw_parts(ptr, this.slice_len())
}
}
pub const fn as_mut_slice(&mut self) -> &mut [T] {
unsafe {
let this = as_inner_mut::<D, _>(&mut self.inner);
let slice_len = this.slice_len();
let ptr = this.array.as_mut_ptr().add(this.taken_front).cast::<T>();
core::slice::from_raw_parts_mut(ptr, slice_len)
}
}
pub const fn copy(&self) -> Self
where
T: Copy,
{
IntoIterInner {
..*as_inner::<D, _>(&self.inner)
}
.into_ii()
}
pub const fn into_drop(self) -> IntoIter<T, N, MayDrop> {
self.into_any_flavor()
}
pub const fn into_copy(self) -> IntoIter<T, N, NonDrop>
where
T: Copy,
{
self.into_any_flavor()
}
const fn into_any_flavor<D2: DropFlavor>(self) -> IntoIter<T, N, D2> {
unsafe { crate::__priv_transmute!(IntoIter<T, N, D>, IntoIter<T, N, D2>, self) }
}
}
impl<T: Debug, const N: usize, D: DropFlavor> Debug for IntoIter<T, N, D> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
Debug::fmt(self.as_slice(), fmt)
}
}
impl<T: Clone, const N: usize, D: DropFlavor> Clone for IntoIter<T, N, D> {
fn clone(&self) -> Self {
let mut this = IntoIterInner {
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.into_ii()
}
}
impl<T, const N: usize> Drop for IntoIterInner<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}
}
}
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "iter")))]
pub struct IntoIterRev<T, const N: usize, D: DropFlavor>(IntoIter<T, N, D>);
impl<T, const N: usize, D: DropFlavor> ConstIntoIter for IntoIterRev<T, N, D> {
type Kind = IsIteratorKind;
type IntoIter = IntoIterRev<T, N, D>;
type Item = T;
const ITEMS_NEED_DROP: bool = core::mem::needs_drop::<T>();
}
impl<T, const N: usize, D: DropFlavor> IntoIterRev<T, N, D> {
pub const fn assert_is_empty(self) {
self.rev().assert_is_empty()
}
pub const fn as_slice(&self) -> &[T] {
self.0.as_slice()
}
pub const fn as_mut_slice(&mut self) -> &mut [T] {
self.0.as_mut_slice()
}
pub const fn copy(&self) -> Self
where
T: Copy,
{
Self(self.0.copy())
}
pub const fn next(&mut self) -> Option<T> {
self.0.next_back()
}
pub const fn next_back(&mut self) -> Option<T> {
self.0.next()
}
pub const fn rev(self) -> IntoIter<T, N, D> {
crate::destructure! {Self(x) = self}
x
}
}
impl<T: Debug, const N: usize, D: DropFlavor> Debug for IntoIterRev<T, N, D> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
Debug::fmt(self.as_slice(), fmt)
}
}
impl<T: Clone, const N: usize, D: DropFlavor> Clone for IntoIterRev<T, N, D> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}