//! `GenericArray` iterator implementation. | |
use super::{ArrayLength, GenericArray}; | |
use core::iter::FusedIterator; | |
use core::mem::ManuallyDrop; | |
use core::{cmp, fmt, mem, ptr}; | |
/// An iterator that moves out of a `GenericArray` | |
pub struct GenericArrayIter<T, N: ArrayLength<T>> { | |
// Invariants: index <= index_back <= N | |
// Only values in array[index..index_back] are alive at any given time. | |
// Values from array[..index] and array[index_back..] are already moved/dropped. | |
array: ManuallyDrop<GenericArray<T, N>>, | |
index: usize, | |
index_back: usize, | |
} | |
#[cfg(test)] | |
mod test { | |
use super::*; | |
fn send<I: Send>(_iter: I) {} | |
#[test] | |
fn test_send_iter() { | |
send(GenericArray::from([1, 2, 3, 4]).into_iter()); | |
} | |
} | |
impl<T, N> GenericArrayIter<T, N> | |
where | |
N: ArrayLength<T>, | |
{ | |
/// Returns the remaining items of this iterator as a slice | |
#[inline] | |
pub fn as_slice(&self) -> &[T] { | |
&self.array.as_slice()[self.index..self.index_back] | |
} | |
/// Returns the remaining items of this iterator as a mutable slice | |
#[inline] | |
pub fn as_mut_slice(&mut self) -> &mut [T] { | |
&mut self.array.as_mut_slice()[self.index..self.index_back] | |
} | |
} | |
impl<T, N> IntoIterator for GenericArray<T, N> | |
where | |
N: ArrayLength<T>, | |
{ | |
type Item = T; | |
type IntoIter = GenericArrayIter<T, N>; | |
fn into_iter(self) -> Self::IntoIter { | |
GenericArrayIter { | |
array: ManuallyDrop::new(self), | |
index: 0, | |
index_back: N::USIZE, | |
} | |
} | |
} | |
// Based on work in rust-lang/rust#49000 | |
impl<T: fmt::Debug, N> fmt::Debug for GenericArrayIter<T, N> | |
where | |
N: ArrayLength<T>, | |
{ | |
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
f.debug_tuple("GenericArrayIter") | |
.field(&self.as_slice()) | |
.finish() | |
} | |
} | |
impl<T, N> Drop for GenericArrayIter<T, N> | |
where | |
N: ArrayLength<T>, | |
{ | |
#[inline] | |
fn drop(&mut self) { | |
if mem::needs_drop::<T>() { | |
// Drop values that are still alive. | |
for p in self.as_mut_slice() { | |
unsafe { | |
ptr::drop_in_place(p); | |
} | |
} | |
} | |
} | |
} | |
// Based on work in rust-lang/rust#49000 | |
impl<T: Clone, N> Clone for GenericArrayIter<T, N> | |
where | |
N: ArrayLength<T>, | |
{ | |
fn clone(&self) -> Self { | |
// This places all cloned elements at the start of the new array iterator, | |
// not at their original indices. | |
let mut array = unsafe { ptr::read(&self.array) }; | |
let mut index_back = 0; | |
for (dst, src) in array.as_mut_slice().into_iter().zip(self.as_slice()) { | |
unsafe { ptr::write(dst, src.clone()) }; | |
index_back += 1; | |
} | |
GenericArrayIter { | |
array, | |
index: 0, | |
index_back, | |
} | |
} | |
} | |
impl<T, N> Iterator for GenericArrayIter<T, N> | |
where | |
N: ArrayLength<T>, | |
{ | |
type Item = T; | |
#[inline] | |
fn next(&mut self) -> Option<T> { | |
if self.index < self.index_back { | |
let p = unsafe { Some(ptr::read(self.array.get_unchecked(self.index))) }; | |
self.index += 1; | |
p | |
} else { | |
None | |
} | |
} | |
fn fold<B, F>(mut self, init: B, mut f: F) -> B | |
where | |
F: FnMut(B, Self::Item) -> B, | |
{ | |
let ret = unsafe { | |
let GenericArrayIter { | |
ref array, | |
ref mut index, | |
index_back, | |
} = self; | |
let remaining = &array[*index..index_back]; | |
remaining.iter().fold(init, |acc, src| { | |
let value = ptr::read(src); | |
*index += 1; | |
f(acc, value) | |
}) | |
}; | |
// ensure the drop happens here after iteration | |
drop(self); | |
ret | |
} | |
#[inline] | |
fn size_hint(&self) -> (usize, Option<usize>) { | |
let len = self.len(); | |
(len, Some(len)) | |
} | |
#[inline] | |
fn count(self) -> usize { | |
self.len() | |
} | |
fn nth(&mut self, n: usize) -> Option<T> { | |
// First consume values prior to the nth. | |
let ndrop = cmp::min(n, self.len()); | |
for p in &mut self.array[self.index..self.index + ndrop] { | |
self.index += 1; | |
unsafe { | |
ptr::drop_in_place(p); | |
} | |
} | |
self.next() | |
} | |
#[inline] | |
fn last(mut self) -> Option<T> { | |
// Note, everything else will correctly drop first as `self` leaves scope. | |
self.next_back() | |
} | |
} | |
impl<T, N> DoubleEndedIterator for GenericArrayIter<T, N> | |
where | |
N: ArrayLength<T>, | |
{ | |
fn next_back(&mut self) -> Option<T> { | |
if self.index < self.index_back { | |
self.index_back -= 1; | |
unsafe { Some(ptr::read(self.array.get_unchecked(self.index_back))) } | |
} else { | |
None | |
} | |
} | |
fn rfold<B, F>(mut self, init: B, mut f: F) -> B | |
where | |
F: FnMut(B, Self::Item) -> B, | |
{ | |
let ret = unsafe { | |
let GenericArrayIter { | |
ref array, | |
index, | |
ref mut index_back, | |
} = self; | |
let remaining = &array[index..*index_back]; | |
remaining.iter().rfold(init, |acc, src| { | |
let value = ptr::read(src); | |
*index_back -= 1; | |
f(acc, value) | |
}) | |
}; | |
// ensure the drop happens here after iteration | |
drop(self); | |
ret | |
} | |
} | |
impl<T, N> ExactSizeIterator for GenericArrayIter<T, N> | |
where | |
N: ArrayLength<T>, | |
{ | |
fn len(&self) -> usize { | |
self.index_back - self.index | |
} | |
} | |
impl<T, N> FusedIterator for GenericArrayIter<T, N> where N: ArrayLength<T> {} | |
// TODO: Implement `TrustedLen` when stabilized |