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}