partial_array/
iter.rs

1//! Types for external iteration.
2//!
3//! This module provides the [`iter::IntoIter`] type, which is an by-value
4//! iterator over a [`PartialArray`]. You most likely do not need to interact
5//! with this module directly. One exception is, when you explicitly need to
6//! store the iterator. In the following example a local variable is explicitly
7//! annotated, but normally one would use just type-inference.
8//! ```
9//! # use partial_array::partial_array;
10//! let array = partial_array![2, 4, 8, 16, 32, 64];
11//! let iter: partial_array::iter::IntoIter<_, 6> = array.into_iter();
12//! for (i, value) in iter.enumerate() {
13//!     println!("Item #{}: {}", i, value);
14//! }
15//! ```
16//!
17//! [`iter::IntoIter`]: IntoIter
18use crate::PartialArray;
19use core::fmt::{self, Debug, Formatter};
20use core::iter::FusedIterator;
21use core::mem::{self, MaybeUninit};
22
23/// An iterator that moves out of a [`PartialArray`], therefore an owning
24/// by-value iterator.
25///
26/// This struct is created by the [`into_iter`] method on Vec (provided by
27/// the [`IntoIterator`] trait).
28///
29/// # Example
30/// ```
31/// # use partial_array::PartialArray;
32/// let v = PartialArray::<u8, 3>::from([0, 1, 2]);
33/// let iter: partial_array::iter::IntoIter<_, 3> = v.into_iter();
34/// ```
35///
36/// [`into_iter`]: IntoIterator::into_iter
37#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
38pub struct IntoIter<T, const N: usize> {
39    // invariant: `read..filled` has to be initialized
40    array: [MaybeUninit<T>; N],
41    filled: usize,
42    read: usize,
43}
44impl<T, const N: usize> IntoIter<T, N> {
45    /// Create a new [`IntoIter<T, N>`] from a [`PartialArray<T, N>`].
46    pub(crate) fn new(array: PartialArray<T, N>) -> Self {
47        // we don't want to drop the `PartialArray`, since we re-use its memory
48        // in this new `IntoIter` and drop the memory ourselves
49        let mut array = mem::ManuallyDrop::new(array);
50        let uninit = [PartialArray::<T, N>::UNINIT; N];
51
52        Self {
53            array: mem::replace(&mut array.array, uninit),
54            filled: array.filled,
55            read: 0,
56        }
57    }
58}
59impl<T: Debug, const N: usize> Debug for IntoIter<T, N> {
60    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
61        let slice = &self.array[self.read..self.filled];
62        // SAFETY: the invariant is: `self.read..self.filled` is initialized, so
63        // it is no UB reading those. The transmute itself is safe, since
64        // `MaybeUninit` is `#[repr(transparent)]`.
65        let slice = unsafe { mem::transmute(slice) };
66        <[T] as Debug>::fmt(slice, f)
67    }
68}
69impl<T, const N: usize> Iterator for IntoIter<T, N> {
70    type Item = T;
71
72    fn next(&mut self) -> Option<Self::Item> {
73        if self.read != self.filled {
74            let value = mem::replace(&mut self.array[self.read], PartialArray::<_, N>::UNINIT);
75            self.read += 1;
76            Some(unsafe { value.assume_init() })
77        } else {
78            None
79        }
80    }
81
82    fn size_hint(&self) -> (usize, Option<usize>) {
83        let len = self.filled - self.read;
84        (len, Some(len))
85    }
86}
87impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
88    fn next_back(&mut self) -> Option<Self::Item> {
89        if self.read != self.filled && self.filled > 0 {
90            self.filled -= 1;
91            let value = mem::replace(&mut self.array[self.filled], PartialArray::<_, N>::UNINIT);
92            Some(unsafe { value.assume_init() })
93        } else {
94            None
95        }
96    }
97}
98impl<T, const N: usize> FusedIterator for IntoIter<T, N> {}
99impl<T, const N: usize> ExactSizeIterator for IntoIter<T, N> {}
100impl<T, const N: usize> Drop for IntoIter<T, N> {
101    fn drop(&mut self) {
102        self.for_each(drop);
103    }
104}