use core::{fmt, iter::FusedIterator, mem::MaybeUninit, ops::Range};
use crate::{Array, ArrayShorthand, MaybeUninitSlice};
pub struct IterMove<A: Array> {
alive: Range<usize>,
inner: A::Maybe,
}
impl<A> IterMove<A>
where
A: Array,
{
#[inline]
pub fn new(array: A) -> Self {
Self {
alive: 0..A::SIZE,
inner: array.into_uninit(),
}
}
#[inline]
pub fn as_slice(&self) -> &[A::Item] {
unsafe {
let slice: &[MaybeUninit<A::Item>] = self.inner.index(self.alive.clone());
slice.assume_init()
}
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [A::Item] {
unsafe {
let slice: &mut [MaybeUninit<A::Item>] = self.inner.index_mut(self.alive.clone());
slice.assume_init_mut()
}
}
}
impl<A> Iterator for IterMove<A>
where
A: Array,
{
type Item = A::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
unsafe {
let idx = self.alive.next()?;
let result: A::Item = self.inner.replace(idx, MaybeUninit::uninit()).assume_init();
Some(result)
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let exact = self.alive.len();
(exact, Some(exact))
}
#[inline]
fn count(self) -> usize {
self.alive.len()
}
}
impl<A> DoubleEndedIterator for IterMove<A>
where
A: Array,
{
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
unsafe {
let idx = self.alive.next_back()?;
let result: A::Item = self.inner.replace(idx, MaybeUninit::uninit()).assume_init();
Some(result)
}
}
}
impl<A> ExactSizeIterator for IterMove<A>
where
A: Array,
{
#[inline]
fn len(&self) -> usize {
self.alive.len()
}
#[inline]
#[cfg(feature = "nightly")]
fn is_empty(&self) -> bool {
ExactSizeIterator::is_empty(&self.alive)
}
}
impl<A> FusedIterator for IterMove<A> where A: Array {}
#[cfg(feature = "nightly")]
unsafe impl<A> core::iter::TrustedLen for IterMove<A> where A: Array {}
impl<A> Clone for IterMove<A>
where
A: Array,
A::Item: Clone,
{
#[inline]
fn clone(&self) -> Self {
let inner = {
let mut array: A::Maybe = A::uninit();
for i in self.alive.clone() {
let cloned = unsafe {
(&*self.inner.index(i).as_ptr()).clone()
};
*array.index_mut(i) = MaybeUninit::new(cloned);
}
array
};
Self {
alive: self.alive.clone(),
inner,
}
}
}
impl<A> fmt::Debug for IterMove<A>
where
A: Array,
A::Item: fmt::Debug,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("IterMove").field(&self.as_slice()).finish()
}
}
impl<A> Drop for IterMove<A>
where
A: Array,
{
#[inline]
fn drop(&mut self) {
for _ in self { }
}
}
#[cfg(test)]
mod tests {
use core::{convert::identity, iter};
use crate::{iter::IterMove, Array};
#[test]
fn empty() {
let arr: [String; 0] = [];
let mut iter = IterMove::new(arr);
assert_eq!(iter.next(), None);
}
#[test]
fn test() {
let arr = <[usize; 5]>::from_fn(identity);
let iter = IterMove::new(arr);
assert!(iter.eq(vec![0, 1, 2, 3, 4]));
}
#[test]
fn len() {
let arr = <[usize; 5]>::from_fn(identity);
let mut iter = IterMove::new(arr);
assert_eq!(iter.len(), 5);
iter.next();
assert_eq!(iter.len(), 4);
for _ in iter.by_ref() {}
assert_eq!(iter.len(), 0);
}
#[test]
fn clone() {
let arr = <[usize; 5]>::from_fn(identity);
let mut iter = IterMove::new(arr);
assert!(iter.clone().eq(vec![0, 1, 2, 3, 4]));
iter.next();
iter.next_back();
assert!(iter.clone().eq(vec![1, 2, 3]));
for _ in iter.by_ref() {}
assert!(iter.eq(iter::empty()));
}
#[test]
fn as_slice() {
let arr = <[usize; 5]>::from_fn(identity);
let mut iter = IterMove::new(arr);
assert_eq!(iter.as_slice(), &[0, 1, 2, 3, 4]);
assert_eq!(iter.as_mut_slice(), &mut [0, 1, 2, 3, 4]);
iter.next();
assert_eq!(iter.as_slice(), &[1, 2, 3, 4]);
assert_eq!(iter.as_mut_slice(), &mut [1, 2, 3, 4]);
iter.next_back();
assert_eq!(iter.as_slice(), &[1, 2, 3]);
assert_eq!(iter.as_mut_slice(), &mut [1, 2, 3]);
for _ in iter.by_ref() {}
assert_eq!(iter.as_slice(), &[]);
assert_eq!(iter.as_mut_slice(), &mut []);
}
#[test]
fn back() {
let arr = <[usize; 5]>::from_fn(identity);
let iter = IterMove::new(arr).rev();
assert!(iter.eq(vec![4, 3, 2, 1, 0]));
}
}