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}