generic_array/
iter.rs

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