11//! Defines the `IntoIter` owned iterator for arrays.
22
33use crate :: {
4- cmp , fmt,
4+ fmt,
55 iter:: { self , ExactSizeIterator , FusedIterator , TrustedLen } ,
66 mem:: { self , MaybeUninit } ,
7- ops:: Range ,
7+ ops:: { IndexRange , Range } ,
88 ptr,
99} ;
1010
@@ -29,9 +29,10 @@ pub struct IntoIter<T, const N: usize> {
2929 /// The elements in `data` that have not been yielded yet.
3030 ///
3131 /// Invariants:
32- /// - `alive.start <= alive.end`
3332 /// - `alive.end <= N`
34- alive : Range < usize > ,
33+ ///
34+ /// (And the `IndexRange` type requires `alive.start <= alive.end`.)
35+ alive : IndexRange ,
3536}
3637
3738// Note: the `#[rustc_skip_array_during_method_dispatch]` on `trait IntoIterator`
@@ -69,7 +70,7 @@ impl<T, const N: usize> IntoIterator for [T; N] {
6970 // Until then, we can use `mem::transmute_copy` to create a bitwise copy
7071 // as a different type, then forget `array` so that it is not dropped.
7172 unsafe {
72- let iter = IntoIter { data : mem:: transmute_copy ( & self ) , alive : 0 .. N } ;
73+ let iter = IntoIter { data : mem:: transmute_copy ( & self ) , alive : IndexRange :: zero_to ( N ) } ;
7374 mem:: forget ( self ) ;
7475 iter
7576 }
@@ -147,7 +148,9 @@ impl<T, const N: usize> IntoIter<T, N> {
147148 buffer : [ MaybeUninit < T > ; N ] ,
148149 initialized : Range < usize > ,
149150 ) -> Self {
150- Self { data : buffer, alive : initialized }
151+ // SAFETY: one of our safety conditions is that the range is canonical.
152+ let alive = unsafe { IndexRange :: new_unchecked ( initialized. start , initialized. end ) } ;
153+ Self { data : buffer, alive }
151154 }
152155
153156 /// Creates an iterator over `T` which returns no elements.
@@ -283,24 +286,19 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
283286 }
284287
285288 fn advance_by ( & mut self , n : usize ) -> Result < ( ) , usize > {
286- let len = self . len ( ) ;
287-
288- // The number of elements to drop. Always in-bounds by construction.
289- let delta = cmp:: min ( n, len) ;
290-
291- let range_to_drop = self . alive . start ..( self . alive . start + delta) ;
289+ let original_len = self . len ( ) ;
292290
293- // Moving the start marks them as conceptually "dropped", so if anything
294- // goes bad then our drop impl won't double-free them.
295- self . alive . start += delta ;
291+ // This also moves the start, which marks them as conceptually "dropped",
292+ // so if anything goes bad then our drop impl won't double-free them.
293+ let range_to_drop = self . alive . take_prefix ( n ) ;
296294
297295 // SAFETY: These elements are currently initialized, so it's fine to drop them.
298296 unsafe {
299297 let slice = self . data . get_unchecked_mut ( range_to_drop) ;
300298 ptr:: drop_in_place ( MaybeUninit :: slice_assume_init_mut ( slice) ) ;
301299 }
302300
303- if n > len { Err ( len ) } else { Ok ( ( ) ) }
301+ if n > original_len { Err ( original_len ) } else { Ok ( ( ) ) }
304302 }
305303}
306304
@@ -338,24 +336,19 @@ impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
338336 }
339337
340338 fn advance_back_by ( & mut self , n : usize ) -> Result < ( ) , usize > {
341- let len = self . len ( ) ;
342-
343- // The number of elements to drop. Always in-bounds by construction.
344- let delta = cmp:: min ( n, len) ;
345-
346- let range_to_drop = ( self . alive . end - delta) ..self . alive . end ;
339+ let original_len = self . len ( ) ;
347340
348- // Moving the end marks them as conceptually "dropped", so if anything
349- // goes bad then our drop impl won't double-free them.
350- self . alive . end -= delta ;
341+ // This also moves the end, which marks them as conceptually "dropped",
342+ // so if anything goes bad then our drop impl won't double-free them.
343+ let range_to_drop = self . alive . take_suffix ( n ) ;
351344
352345 // SAFETY: These elements are currently initialized, so it's fine to drop them.
353346 unsafe {
354347 let slice = self . data . get_unchecked_mut ( range_to_drop) ;
355348 ptr:: drop_in_place ( MaybeUninit :: slice_assume_init_mut ( slice) ) ;
356349 }
357350
358- if n > len { Err ( len ) } else { Ok ( ( ) ) }
351+ if n > original_len { Err ( original_len ) } else { Ok ( ( ) ) }
359352 }
360353}
361354
@@ -372,9 +365,7 @@ impl<T, const N: usize> Drop for IntoIter<T, N> {
372365#[ stable( feature = "array_value_iter_impls" , since = "1.40.0" ) ]
373366impl < T , const N : usize > ExactSizeIterator for IntoIter < T , N > {
374367 fn len ( & self ) -> usize {
375- // Will never underflow due to the invariant `alive.start <=
376- // alive.end`.
377- self . alive . end - self . alive . start
368+ self . alive . len ( )
378369 }
379370 fn is_empty ( & self ) -> bool {
380371 self . alive . is_empty ( )
@@ -396,14 +387,15 @@ impl<T: Clone, const N: usize> Clone for IntoIter<T, N> {
396387 fn clone ( & self ) -> Self {
397388 // Note, we don't really need to match the exact same alive range, so
398389 // we can just clone into offset 0 regardless of where `self` is.
399- let mut new = Self { data : MaybeUninit :: uninit_array ( ) , alive : 0 .. 0 } ;
390+ let mut new = Self { data : MaybeUninit :: uninit_array ( ) , alive : IndexRange :: zero_to ( 0 ) } ;
400391
401392 // Clone all alive elements.
402393 for ( src, dst) in iter:: zip ( self . as_slice ( ) , & mut new. data ) {
403394 // Write a clone into the new array, then update its alive range.
404395 // If cloning panics, we'll correctly drop the previous items.
405396 dst. write ( src. clone ( ) ) ;
406- new. alive . end += 1 ;
397+ // This addition cannot overflow as we're iterating a slice
398+ new. alive = IndexRange :: zero_to ( new. alive . end ( ) + 1 ) ;
407399 }
408400
409401 new
0 commit comments