//! Defines the `IntoIter` owned iterator for arrays. use crate::mem::MaybeUninit; use crate::num::NonZero; use crate::ops::{IndexRange, NeverShortCircuit, Try}; use crate::{fmt, iter}; #[allow(private_bounds)] trait PartialDrop { /// # Safety /// `self[alive]` are all initialized before the call, /// then are never used (without reinitializing them) after it. unsafe fn partial_drop(&mut self, alive: IndexRange); } impl PartialDrop for [MaybeUninit] { unsafe fn partial_drop(&mut self, alive: IndexRange) { // SAFETY: We know that all elements within `alive` are properly initialized. unsafe { self.get_unchecked_mut(alive).assume_init_drop() } } } impl PartialDrop for [MaybeUninit; N] { unsafe fn partial_drop(&mut self, alive: IndexRange) { let slice: &mut [MaybeUninit] = self; // SAFETY: Initialized elements in the array are also initialized in the slice. unsafe { slice.partial_drop(alive) } } } /// The internals of a by-value array iterator. /// /// The real `array::IntoIter` stores a `PolymorphicIter<[MaybeUninit, N]>` /// which it unsizes to `PolymorphicIter<[MaybeUninit]>` to iterate. #[allow(private_bounds)] pub(super) struct PolymorphicIter where DATA: PartialDrop, { /// The elements in `data` that have not been yielded yet. /// /// Invariants: /// - `alive.end <= N` /// /// (And the `IndexRange` type requires `alive.start <= alive.end`.) alive: IndexRange, /// This is the array we are iterating over. /// /// Elements with index `i` where `alive.start <= i < alive.end` have not /// been yielded yet and are valid array entries. Elements with indices `i /// < alive.start` or `i >= alive.end` have been yielded already and must /// not be accessed anymore! Those dead elements might even be in a /// completely uninitialized state! /// /// So the invariants are: /// - `data[alive]` is alive (i.e. contains valid elements) /// - `data[..alive.start]` and `data[alive.end..]` are dead (i.e. the /// elements were already read and must not be touched anymore!) data: DATA, } #[allow(private_bounds)] impl PolymorphicIter where DATA: PartialDrop, { #[inline] pub(super) const fn len(&self) -> usize { self.alive.len() } } #[allow(private_bounds)] impl Drop for PolymorphicIter where DATA: PartialDrop, { #[inline] fn drop(&mut self) { // SAFETY: by our type invariant `self.alive` is exactly the initialized // items, and this is drop so nothing can use the items afterwards. unsafe { self.data.partial_drop(self.alive.clone()) } } } impl PolymorphicIter<[MaybeUninit; N]> { #[inline] pub(super) const fn empty() -> Self { Self { alive: IndexRange::zero_to(0), data: [const { MaybeUninit::uninit() }; N] } } /// # Safety /// `data[alive]` are all initialized. #[inline] pub(super) const unsafe fn new_unchecked(alive: IndexRange, data: [MaybeUninit; N]) -> Self { Self { alive, data } } } impl Clone for PolymorphicIter<[MaybeUninit; N]> { #[inline] fn clone(&self) -> Self { // Note, we don't really need to match the exact same alive range, so // we can just clone into offset 0 regardless of where `self` is. let mut new = Self::empty(); fn clone_into_new( source: &PolymorphicIter<[MaybeUninit]>, target: &mut PolymorphicIter<[MaybeUninit]>, ) { // Clone all alive elements. for (src, dst) in iter::zip(source.as_slice(), &mut target.data) { // Write a clone into the new array, then update its alive range. // If cloning panics, we'll correctly drop the previous items. dst.write(src.clone()); // This addition cannot overflow as we're iterating a slice, // the length of which always fits in usize. target.alive = IndexRange::zero_to(target.alive.end() + 1); } } clone_into_new(self, &mut new); new } } impl PolymorphicIter<[MaybeUninit]> { #[inline] pub(super) fn as_slice(&self) -> &[T] { // SAFETY: We know that all elements within `alive` are properly initialized. unsafe { let slice = self.data.get_unchecked(self.alive.clone()); slice.assume_init_ref() } } #[inline] pub(super) fn as_mut_slice(&mut self) -> &mut [T] { // SAFETY: We know that all elements within `alive` are properly initialized. unsafe { let slice = self.data.get_unchecked_mut(self.alive.clone()); slice.assume_init_mut() } } } impl fmt::Debug for PolymorphicIter<[MaybeUninit]> { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Only print the elements that were not yielded yet: we cannot // access the yielded elements anymore. f.debug_tuple("IntoIter").field(&self.as_slice()).finish() } } /// Iterator-equivalent methods. /// /// We don't implement the actual iterator traits because we want to implement /// things like `try_fold` that require `Self: Sized` (which we're not). impl PolymorphicIter<[MaybeUninit]> { #[inline] pub(super) fn next(&mut self) -> Option { // Get the next index from the front. // // Increasing `alive.start` by 1 maintains the invariant regarding // `alive`. However, due to this change, for a short time, the alive // zone is not `data[alive]` anymore, but `data[idx..alive.end]`. self.alive.next().map(|idx| { // Read the element from the array. // SAFETY: `idx` is an index into the former "alive" region of the // array. Reading this element means that `data[idx]` is regarded as // dead now (i.e. do not touch). As `idx` was the start of the // alive-zone, the alive zone is now `data[alive]` again, restoring // all invariants. unsafe { self.data.get_unchecked(idx).assume_init_read() } }) } #[inline] pub(super) fn size_hint(&self) -> (usize, Option) { let len = self.len(); (len, Some(len)) } #[inline] pub(super) fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { // This also moves the start, which marks them as conceptually "dropped", // so if anything goes bad then our drop impl won't double-free them. let range_to_drop = self.alive.take_prefix(n); let remaining = n - range_to_drop.len(); // SAFETY: These elements are currently initialized, so it's fine to drop them. unsafe { let slice = self.data.get_unchecked_mut(range_to_drop); slice.assume_init_drop(); } NonZero::new(remaining).map_or(Ok(()), Err) } #[inline] pub(super) fn fold(&mut self, init: B, f: impl FnMut(B, T) -> B) -> B { self.try_fold(init, NeverShortCircuit::wrap_mut_2(f)).0 } #[inline] pub(super) fn try_fold(&mut self, init: B, mut f: F) -> R where F: FnMut(B, T) -> R, R: Try, { // `alive` is an `IndexRange`, not an arbitrary iterator, so we can // trust that its `try_fold` isn't going to do something weird like // call the fold-er multiple times for the same index. let data = &mut self.data; self.alive.try_fold(init, move |accum, idx| { // SAFETY: `idx` has been removed from the alive range, so we're not // going to drop it (even if `f` panics) and thus its ok to give // out ownership of that item to `f` to handle. let elem = unsafe { data.get_unchecked(idx).assume_init_read() }; f(accum, elem) }) } #[inline] pub(super) fn next_back(&mut self) -> Option { // Get the next index from the back. // // Decreasing `alive.end` by 1 maintains the invariant regarding // `alive`. However, due to this change, for a short time, the alive // zone is not `data[alive]` anymore, but `data[alive.start..=idx]`. self.alive.next_back().map(|idx| { // Read the element from the array. // SAFETY: `idx` is an index into the former "alive" region of the // array. Reading this element means that `data[idx]` is regarded as // dead now (i.e. do not touch). As `idx` was the end of the // alive-zone, the alive zone is now `data[alive]` again, restoring // all invariants. unsafe { self.data.get_unchecked(idx).assume_init_read() } }) } #[inline] pub(super) fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { // This also moves the end, which marks them as conceptually "dropped", // so if anything goes bad then our drop impl won't double-free them. let range_to_drop = self.alive.take_suffix(n); let remaining = n - range_to_drop.len(); // SAFETY: These elements are currently initialized, so it's fine to drop them. unsafe { let slice = self.data.get_unchecked_mut(range_to_drop); slice.assume_init_drop(); } NonZero::new(remaining).map_or(Ok(()), Err) } #[inline] pub(super) fn rfold(&mut self, init: B, f: impl FnMut(B, T) -> B) -> B { self.try_rfold(init, NeverShortCircuit::wrap_mut_2(f)).0 } #[inline] pub(super) fn try_rfold(&mut self, init: B, mut f: F) -> R where F: FnMut(B, T) -> R, R: Try, { // `alive` is an `IndexRange`, not an arbitrary iterator, so we can // trust that its `try_rfold` isn't going to do something weird like // call the fold-er multiple times for the same index. let data = &mut self.data; self.alive.try_rfold(init, move |accum, idx| { // SAFETY: `idx` has been removed from the alive range, so we're not // going to drop it (even if `f` panics) and thus its ok to give // out ownership of that item to `f` to handle. let elem = unsafe { data.get_unchecked(idx).assume_init_read() }; f(accum, elem) }) } }