@@ -5,6 +5,34 @@ use core::iter::FusedIterator;
55use core:: mem:: ManuallyDrop ;
66use core:: { cmp, fmt, mem, ptr} ;
77
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`.
25+ macro_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+
836/// An iterator that moves out of a [`GenericArray`]
937pub struct GenericArrayIter < T , N : ArrayLength > {
1038 // Invariants: index <= index_back <= N
@@ -16,18 +44,38 @@ pub struct GenericArrayIter<T, N: ArrayLength> {
1644}
1745
1846impl < 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+
1957 /// Returns the remaining items of this iterator as a slice
2058 #[ inline( always) ]
2159 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 ) }
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) }
2469 }
2570
2671 /// Returns the remaining items of this iterator as a mutable slice
2772 #[ inline( always) ]
2873 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 ) }
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) }
3179 }
3280}
3381
@@ -90,7 +138,10 @@ impl<T, N: ArrayLength> Iterator for GenericArrayIter<T, N> {
90138 #[ inline]
91139 fn next ( & mut self ) -> Option < T > {
92140 if self . index < self . index_back {
93- let p = unsafe { Some ( ptr:: read ( self . array . get_unchecked ( self . index ) ) ) } ;
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 ) ) ) } ;
94145
95146 self . index += 1 ;
96147
@@ -112,7 +163,11 @@ impl<T, N: ArrayLength> Iterator for GenericArrayIter<T, N> {
112163 index_back,
113164 } = self ;
114165
115- let remaining = array. get_unchecked ( * index..index_back) ;
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) ;
116171
117172 remaining. iter ( ) . fold ( init, |acc, src| {
118173 let value = ptr:: read ( src) ;
@@ -150,8 +205,11 @@ impl<T, N: ArrayLength> Iterator for GenericArrayIter<T, N> {
150205 // First consume values prior to the nth.
151206 let next_index = self . index + cmp:: min ( n, self . len ( ) ) ;
152207
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.
153211 unsafe {
154- ptr:: drop_in_place ( self . array . get_unchecked_mut ( self . index .. next_index) ) ;
212+ ptr:: drop_in_place ( raw_subslice ! ( mut self . array, self . index, next_index) ) ;
155213 }
156214
157215 self . index = next_index;
@@ -172,7 +230,10 @@ impl<T, N: ArrayLength> DoubleEndedIterator for GenericArrayIter<T, N> {
172230 if self . index < self . index_back {
173231 self . index_back -= 1 ;
174232
175- unsafe { Some ( ptr:: read ( self . array . get_unchecked ( self . index_back ) ) ) }
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 ) ) ) }
176237 } else {
177238 None
178239 }
@@ -190,7 +251,11 @@ impl<T, N: ArrayLength> DoubleEndedIterator for GenericArrayIter<T, N> {
190251 ref mut index_back,
191252 } = self ;
192253
193- let remaining = array. get_unchecked ( index..* index_back) ;
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) ;
194259
195260 remaining. iter ( ) . rfold ( init, |acc, src| {
196261 let value = ptr:: read ( src) ;
@@ -210,8 +275,11 @@ impl<T, N: ArrayLength> DoubleEndedIterator for GenericArrayIter<T, N> {
210275 fn nth_back ( & mut self , n : usize ) -> Option < T > {
211276 let next_back = self . index_back - cmp:: min ( n, self . len ( ) ) ;
212277
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`.
213281 unsafe {
214- ptr:: drop_in_place ( self . array . get_unchecked_mut ( next_back.. self . index_back ) ) ;
282+ ptr:: drop_in_place ( raw_subslice ! ( mut self . array, next_back, self . index_back) ) ;
215283 }
216284
217285 self . index_back = next_back;
0 commit comments