Skip to main content

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/// Build a raw slice pointer over the live sub-range `array[start..end]` of an iterator's
9/// backing `ManuallyDrop<GenericArray<T, N>>`, without ever forming a reference (not even a
10/// transient `&[T]`) that spans the moved-out slots outside `start..end`.
11///
12/// The base pointer is taken via `addr_of!`/`addr_of_mut!` on the array place (the same raw
13/// cast `GenericArray::as_slice` uses), so the only reference - if any - is the one the
14/// *caller* materializes from the returned raw pointer at the use site.
15///
16/// Forms:
17/// - `raw_subslice!(const $array, $start, $end)` -> `*const [T]`
18/// - `raw_subslice!(mut   $array, $start, $end)` -> `*mut [T]`
19///
20/// # Safety
21///
22/// The caller must ensure `$start <= $end <= N` (the iterator's `index <= index_back <= N`
23/// invariant) so the range is in bounds, and - for the `mut` form - that no other live
24/// borrow of the array overlaps `$start..$end`.
25macro_rules! raw_subslice {
26    (const $array:expr, $start:expr, $end:expr) => {{
27        let base = ::core::ptr::addr_of!(*$array) as *const T;
28        ::core::ptr::slice_from_raw_parts(base.add($start), $end - $start)
29    }};
30    (mut $array:expr, $start:expr, $end:expr) => {{
31        let base = ::core::ptr::addr_of_mut!(*$array) as *mut T;
32        ::core::ptr::slice_from_raw_parts_mut(base.add($start), $end - $start)
33    }};
34}
35
36/// An iterator that moves out of a [`GenericArray`]
37pub struct GenericArrayIter<T, N: ArrayLength> {
38    // Invariants: index <= index_back <= N
39    // Only values in array[index..index_back] are alive at any given time.
40    // Values from array[..index] and array[index_back..] are already moved/dropped.
41    array: ManuallyDrop<GenericArray<T, N>>,
42    index: usize,
43    index_back: usize,
44}
45
46impl<T, N: ArrayLength> GenericArrayIter<T, N> {
47    /// Raw `*const T` to element 0 of the backing array.
48    ///
49    /// Taken via a raw cast of the array's address (the same cast `GenericArray::as_slice`
50    /// uses), so that callers offsetting into the live range never form a reference - not
51    /// even a transient `&[T]` - spanning the moved-out slots in `..index`/`index_back..`.
52    #[inline(always)]
53    fn base_ptr(&self) -> *const T {
54        ptr::addr_of!(*self.array) as *const T
55    }
56
57    /// Returns the remaining items of this iterator as a slice
58    #[inline(always)]
59    pub fn as_slice(&self) -> &[T] {
60        // SAFETY: By the type invariant, `index <= index_back <= N`, so `index` is in
61        // bounds and `index_back - index` does not exceed the backing allocation. We form
62        // the slice directly over the live `index..index_back` range rather than letting
63        // `GenericArray`'s `Deref` materialize a `&[T]` spanning all `0..N` and then
64        // re-slicing: this way no reference ever spans the moved-out slots in `..index`
65        // or `index_back..` (same discipline as `core::array::IntoIter::as_slice`). The
66        // live elements are initialized and valid for reads. (Codegen is identical to the
67        // old `get_unchecked` form; see `examples/asm.rs`.)
68        unsafe { &*raw_subslice!(const self.array, self.index, self.index_back) }
69    }
70
71    /// Returns the remaining items of this iterator as a mutable slice
72    #[inline(always)]
73    pub fn as_mut_slice(&mut self) -> &mut [T] {
74        // SAFETY: By the type invariant, `index <= index_back <= N`, so `index` is in
75        // bounds and the length `index_back - index` does not exceed the backing
76        // allocation. The slice spans only the live range, so it never references the
77        // moved-out slots, and uniqueness holds because it is derived from `&mut self`.
78        unsafe { &mut *raw_subslice!(mut self.array, self.index, self.index_back) }
79    }
80}
81
82impl<T, N: ArrayLength> IntoIterator for GenericArray<T, N> {
83    type Item = T;
84    type IntoIter = GenericArrayIter<T, N>;
85
86    #[inline]
87    fn into_iter(self) -> Self::IntoIter {
88        GenericArrayIter {
89            array: ManuallyDrop::new(self),
90            index: 0,
91            index_back: N::USIZE,
92        }
93    }
94}
95
96// Based on work in rust-lang/rust#49000
97impl<T: fmt::Debug, N: ArrayLength> fmt::Debug for GenericArrayIter<T, N> {
98    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
99        f.debug_tuple("GenericArrayIter")
100            .field(&self.as_slice())
101            .finish()
102    }
103}
104
105impl<T, N: ArrayLength> Drop for GenericArrayIter<T, N> {
106    fn drop(&mut self) {
107        unsafe {
108            ptr::drop_in_place(self.as_mut_slice());
109        }
110    }
111}
112
113// Based on work in rust-lang/rust#49000
114impl<T: Clone, N: ArrayLength> Clone for GenericArrayIter<T, N> {
115    fn clone(&self) -> Self {
116        // This places all cloned elements at the start of the new array iterator,
117        // not at their original indices.
118
119        // work from within the iter so if clone panics then the iter will drop itself.
120        let mut iter = GenericArrayIter {
121            array: unsafe { ptr::read(&self.array) },
122            index: 0,
123            index_back: 0,
124        };
125
126        for (dst, src) in iter.array.as_mut_slice().iter_mut().zip(self.as_slice()) {
127            unsafe { ptr::write(dst, src.clone()) };
128            iter.index_back += 1;
129        }
130
131        iter
132    }
133}
134
135impl<T, N: ArrayLength> Iterator for GenericArrayIter<T, N> {
136    type Item = T;
137
138    #[inline]
139    fn next(&mut self) -> Option<T> {
140        if self.index < self.index_back {
141            // SAFETY: `index < index_back <= N`, so element `index` is in bounds, alive,
142            // and not yet read. Read it by value through the base pointer (no reference to
143            // a moved-out slot is ever formed); `index` is advanced past it immediately.
144            let p = unsafe { Some(ptr::read(self.base_ptr().add(self.index))) };
145
146            self.index += 1;
147
148            p
149        } else {
150            None
151        }
152    }
153
154    #[inline]
155    fn fold<B, F>(mut self, init: B, mut f: F) -> B
156    where
157        F: FnMut(B, Self::Item) -> B,
158    {
159        let ret = unsafe {
160            let GenericArrayIter {
161                ref array,
162                ref mut index,
163                index_back,
164            } = self;
165
166            // SAFETY: `index <= index_back <= N`. Form a slice over only the live
167            // `index..index_back` range (raw cast of the array address, so no reference
168            // ever spans the moved-out slots), then read each element out by value exactly
169            // once, advancing `index` so a panic in `f` drops only the tail.
170            let remaining = &*raw_subslice!(const *array, *index, index_back);
171
172            remaining.iter().fold(init, |acc, src| {
173                let value = ptr::read(src);
174
175                *index += 1;
176
177                f(acc, value)
178            })
179        };
180
181        // The current iterator is now empty after the remaining items are
182        // consumed by the above folding. Dropping it is unnecessary,
183        // so avoid the drop codegen and forget it instead. The iterator
184        // will still drop on panics from `f`, of course.
185        //
186        // Furthermore, putting `forget` here at the end ensures the above
187        // destructuring never moves by value, so its behavior on drop remains intact.
188        mem::forget(self);
189
190        ret
191    }
192
193    #[inline(always)]
194    fn size_hint(&self) -> (usize, Option<usize>) {
195        let len = self.len();
196        (len, Some(len))
197    }
198
199    #[inline(always)]
200    fn count(self) -> usize {
201        self.len()
202    }
203
204    fn nth(&mut self, n: usize) -> Option<T> {
205        // First consume values prior to the nth.
206        let next_index = self.index + cmp::min(n, self.len());
207
208        // SAFETY: `index <= next_index <= index_back <= N`, so `index..next_index` is a
209        // range of live, in-bounds elements. Drop exactly those in place via a raw slice
210        // pointer (no reference spanning moved-out slots), then advance `index` past them.
211        unsafe {
212            ptr::drop_in_place(raw_subslice!(mut self.array, self.index, next_index));
213        }
214
215        self.index = next_index;
216
217        self.next()
218    }
219
220    #[inline]
221    fn last(mut self) -> Option<T> {
222        // Note, everything else will correctly drop first as `self` leaves scope.
223        self.next_back()
224    }
225}
226
227impl<T, N: ArrayLength> DoubleEndedIterator for GenericArrayIter<T, N> {
228    #[inline]
229    fn next_back(&mut self) -> Option<T> {
230        if self.index < self.index_back {
231            self.index_back -= 1;
232
233            // SAFETY: after the decrement, `index <= index_back < N`, so element
234            // `index_back` is in bounds, alive, and not yet read. Read it by value through
235            // the base pointer; `index_back` already excludes it from the live range.
236            unsafe { Some(ptr::read(self.base_ptr().add(self.index_back))) }
237        } else {
238            None
239        }
240    }
241
242    #[inline]
243    fn rfold<B, F>(mut self, init: B, mut f: F) -> B
244    where
245        F: FnMut(B, Self::Item) -> B,
246    {
247        let ret = unsafe {
248            let GenericArrayIter {
249                ref array,
250                index,
251                ref mut index_back,
252            } = self;
253
254            // SAFETY: `index <= index_back <= N`. Form a slice over only the live
255            // `index..index_back` range (raw cast of the array address, so no reference
256            // spans moved-out slots), then read each element out by value exactly once from
257            // the back, decrementing `index_back` so a panic in `f` drops only the head.
258            let remaining = &*raw_subslice!(const *array, index, *index_back);
259
260            remaining.iter().rfold(init, |acc, src| {
261                let value = ptr::read(src);
262
263                *index_back -= 1;
264
265                f(acc, value)
266            })
267        };
268
269        // Same as `fold`
270        mem::forget(self);
271
272        ret
273    }
274
275    fn nth_back(&mut self, n: usize) -> Option<T> {
276        let next_back = self.index_back - cmp::min(n, self.len());
277
278        // SAFETY: `index <= next_back <= index_back <= N`, so `next_back..index_back` is a
279        // range of live, in-bounds elements. Drop exactly those in place via a raw slice
280        // pointer (no reference spanning moved-out slots), then retreat `index_back`.
281        unsafe {
282            ptr::drop_in_place(raw_subslice!(mut self.array, next_back, self.index_back));
283        }
284
285        self.index_back = next_back;
286
287        self.next_back()
288    }
289}
290
291impl<T, N: ArrayLength> ExactSizeIterator for GenericArrayIter<T, N> {
292    #[inline]
293    fn len(&self) -> usize {
294        self.index_back - self.index
295    }
296}
297
298impl<T, N: ArrayLength> FusedIterator for GenericArrayIter<T, N> {}
299
300// TODO: Implement `TrustedLen` when stabilized
301
302#[cfg(test)]
303mod test {
304    use super::*;
305
306    fn send<I: Send>(_iter: I) {}
307
308    #[test]
309    fn test_send_iter() {
310        send(GenericArray::from([1, 2, 3, 4]).into_iter());
311    }
312}