generic_array/
iter.rs

1//! `GenericArray` iterator implementation.
2
3use super::{ArrayLength, GenericArray};
4use core::iter::FusedIterator;
5use core::mem::{MaybeUninit, ManuallyDrop};
6use core::{cmp, fmt, ptr, mem};
7
8/// An iterator that moves out of a `GenericArray`
9pub struct GenericArrayIter<T, N: ArrayLength<T>> {
10    // Invariants: index <= index_back <= N
11    // Only values in array[index..index_back] are alive at any given time.
12    // Values from array[..index] and array[index_back..] are already moved/dropped.
13    array: ManuallyDrop<GenericArray<T, N>>,
14    index: usize,
15    index_back: usize,
16}
17
18#[cfg(test)]
19mod test {
20    use super::*;
21
22    fn send<I: Send>(_iter: I) {}
23
24    #[test]
25    fn test_send_iter() {
26        send(GenericArray::from([1, 2, 3, 4]).into_iter());
27    }
28}
29
30impl<T, N> GenericArrayIter<T, N>
31where
32    N: ArrayLength<T>,
33{
34    /// Returns the remaining items of this iterator as a slice
35    #[inline]
36    pub fn as_slice(&self) -> &[T] {
37        &self.array.as_slice()[self.index..self.index_back]
38    }
39
40    /// Returns the remaining items of this iterator as a mutable slice
41    #[inline]
42    pub fn as_mut_slice(&mut self) -> &mut [T] {
43        &mut self.array.as_mut_slice()[self.index..self.index_back]
44    }
45}
46
47impl<T, N> IntoIterator for GenericArray<T, N>
48where
49    N: ArrayLength<T>,
50{
51    type Item = T;
52    type IntoIter = GenericArrayIter<T, N>;
53
54    fn into_iter(self) -> Self::IntoIter {
55        GenericArrayIter {
56            array: ManuallyDrop::new(self),
57            index: 0,
58            index_back: N::USIZE,
59        }
60    }
61}
62
63// Based on work in rust-lang/rust#49000
64impl<T: fmt::Debug, N> fmt::Debug for GenericArrayIter<T, N>
65where
66    N: ArrayLength<T>,
67{
68    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69        f.debug_tuple("GenericArrayIter")
70            .field(&self.as_slice())
71            .finish()
72    }
73}
74
75impl<T, N> Drop for GenericArrayIter<T, N>
76where
77    N: ArrayLength<T>,
78{
79    #[inline]
80    fn drop(&mut self) {
81        if mem::needs_drop::<T>() {
82            // Drop values that are still alive.
83            for p in self.as_mut_slice() {
84                unsafe {
85                    ptr::drop_in_place(p);
86                }
87            }
88        }
89    }
90}
91
92// Based on work in rust-lang/rust#49000
93impl<T: Clone, N> Clone for GenericArrayIter<T, N>
94where
95    N: ArrayLength<T>,
96{
97    fn clone(&self) -> Self {
98        // This places all cloned elements at the start of the new array iterator,
99        // not at their original indices.
100        unsafe {
101            let mut array: MaybeUninit<GenericArray<T, N>> = MaybeUninit::uninit();
102            let mut index_back = 0;
103
104            for (dst, src) in (&mut *array.as_mut_ptr()).iter_mut().zip(self.as_slice()) {
105                ptr::write(dst, src.clone());
106
107                index_back += 1;
108            }
109
110            GenericArrayIter {
111                array: ManuallyDrop::new(array.assume_init()),
112                index: 0,
113                index_back
114            }
115        }
116    }
117}
118
119impl<T, N> Iterator for GenericArrayIter<T, N>
120where
121    N: ArrayLength<T>,
122{
123    type Item = T;
124
125    #[inline]
126    fn next(&mut self) -> Option<T> {
127        if self.index < self.index_back {
128            let p = unsafe { Some(ptr::read(self.array.get_unchecked(self.index))) };
129
130            self.index += 1;
131
132            p
133        } else {
134            None
135        }
136    }
137
138    fn fold<B, F>(mut self, init: B, mut f: F) -> B
139    where
140        F: FnMut(B, Self::Item) -> B,
141    {
142        let ret = unsafe {
143            let GenericArrayIter {
144                ref array,
145                ref mut index,
146                index_back,
147            } = self;
148
149            let remaining = &array[*index..index_back];
150
151            remaining.iter().fold(init, |acc, src| {
152                let value = ptr::read(src);
153
154                *index += 1;
155
156                f(acc, value)
157            })
158        };
159
160        // ensure the drop happens here after iteration
161        drop(self);
162
163        ret
164    }
165
166    #[inline]
167    fn size_hint(&self) -> (usize, Option<usize>) {
168        let len = self.len();
169        (len, Some(len))
170    }
171
172    #[inline]
173    fn count(self) -> usize {
174        self.len()
175    }
176
177    fn nth(&mut self, n: usize) -> Option<T> {
178        // First consume values prior to the nth.
179        let ndrop = cmp::min(n, self.len());
180
181        for p in &mut self.array[self.index..self.index + ndrop] {
182            self.index += 1;
183
184            unsafe {
185                ptr::drop_in_place(p);
186            }
187        }
188
189        self.next()
190    }
191
192    #[inline]
193    fn last(mut self) -> Option<T> {
194        // Note, everything else will correctly drop first as `self` leaves scope.
195        self.next_back()
196    }
197}
198
199impl<T, N> DoubleEndedIterator for GenericArrayIter<T, N>
200where
201    N: ArrayLength<T>,
202{
203    fn next_back(&mut self) -> Option<T> {
204        if self.index < self.index_back {
205            self.index_back -= 1;
206
207            unsafe { Some(ptr::read(self.array.get_unchecked(self.index_back))) }
208        } else {
209            None
210        }
211    }
212
213    fn rfold<B, F>(mut self, init: B, mut f: F) -> B
214    where
215        F: FnMut(B, Self::Item) -> B,
216    {
217        let ret = unsafe {
218            let GenericArrayIter {
219                ref array,
220                index,
221                ref mut index_back,
222            } = self;
223
224            let remaining = &array[index..*index_back];
225
226            remaining.iter().rfold(init, |acc, src| {
227                let value = ptr::read(src);
228
229                *index_back -= 1;
230
231                f(acc, value)
232            })
233        };
234
235        // ensure the drop happens here after iteration
236        drop(self);
237
238        ret
239    }
240}
241
242impl<T, N> ExactSizeIterator for GenericArrayIter<T, N>
243where
244    N: ArrayLength<T>,
245{
246    fn len(&self) -> usize {
247        self.index_back - self.index
248    }
249}
250
251impl<T, N> FusedIterator for GenericArrayIter<T, N>
252where
253    N: ArrayLength<T>,
254{
255}
256
257// TODO: Implement `TrustedLen` when stabilized