iter.rs.html -- source
Description: Source to the Rust file `library/core/src/array/iter.rs`.
Keywords: rust, rustlang, rust-lang

      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202

    //! Defines the `IntoIter` owned iterator for arrays.

    use crate::{
        fmt,
        iter::{ExactSizeIterator, FusedIterator, TrustedLen},
        mem::{self, MaybeUninit},
        ops::Range,
        ptr,
    };

    /// A by-value [array] iterator.
    ///
    /// [array]: ../../std/primitive.array.html
    #[unstable(feature = "array_value_iter", issue = "65798")]
    pub struct IntoIter<T, const N: usize> {
        /// This is the array we are iterating over.
        ///
        /// Elements with index `i` where `alive.start <= i < alive.end` have not
        /// been yielded yet and are valid array entries. Elements with indices `i
        /// < alive.start` or `i >= alive.end` have been yielded already and must
        /// not be accessed anymore! Those dead elements might even be in a
        /// completely uninitialized state!
        ///
        /// So the invariants are:
        /// - `data[alive]` is alive (i.e. contains valid elements)
        /// - `data[..alive.start]` and `data[alive.end..]` are dead (i.e. the
        ///   elements were already read and must not be touched anymore!)
        data: [MaybeUninit<T>; N],

        /// The elements in `data` that have not been yielded yet.
        ///
        /// Invariants:
        /// - `alive.start <= alive.end`
        /// - `alive.end <= N`
        alive: Range<usize>,
    }

    impl<T, const N: usize> IntoIter<T, N> {
        /// Creates a new iterator over the given `array`.
        ///
        /// *Note*: this method might never get stabilized and/or removed in the
        /// future as there will likely be another, preferred way of obtaining this
        /// iterator (either via `IntoIterator` for arrays or via another way).
        #[unstable(feature = "array_value_iter", issue = "65798")]
        pub fn new(array: [T; N]) -> Self {
            // SAFETY: The transmute here is actually safe. The docs of `MaybeUninit`
            // promise:
            //
            // > `MaybeUninit<T>` is guaranteed to have the same size and alignment
            // > as `T`.
            //
            // The docs even show a transmute from an array of `MaybeUninit<T>` to
            // an array of `T`.
            //
            // With that, this initialization satisfies the invariants.

            // FIXME(LukasKalbertodt): actually use `mem::transmute` here, once it
            // works with const generics:
            //     `mem::transmute::<[T; N], [MaybeUninit<T>; N]>(array)`
            //
            // Until then, we can use `mem::transmute_copy` to create a bitwise copy
            // as a different type, then forget `array` so that it is not dropped.
            unsafe {
                let iter = Self { data: mem::transmute_copy(&array), alive: 0..N };
                mem::forget(array);
                iter
            }
        }

        /// Returns an immutable slice of all elements that have not been yielded
        /// yet.
        fn as_slice(&self) -> &[T] {
            // SAFETY: We know that all elements within `alive` are properly initialized.
            unsafe {
                let slice = self.data.get_unchecked(self.alive.clone());
                MaybeUninit::slice_get_ref(slice)
            }
        }

        /// Returns a mutable slice of all elements that have not been yielded yet.
        fn as_mut_slice(&mut self) -> &mut [T] {
            // SAFETY: We know that all elements within `alive` are properly initialized.
            unsafe {
                let slice = self.data.get_unchecked_mut(self.alive.clone());
                MaybeUninit::slice_get_mut(slice)
            }
        }
    }

    #[stable(feature = "array_value_iter_impls", since = "1.40.0")]
    impl<T, const N: usize> Iterator for IntoIter<T, N> {
        type Item = T;
        fn next(&mut self) -> Option<Self::Item> {
            // Get the next index from the front.
            //
            // Increasing `alive.start` by 1 maintains the invariant regarding
            // `alive`. However, due to this change, for a short time, the alive
            // zone is not `data[alive]` anymore, but `data[idx..alive.end]`.
            self.alive.next().map(|idx| {
                // Read the element from the array.
                // SAFETY: `idx` is an index into the former "alive" region of the
                // array. Reading this element means that `data[idx]` is regarded as
                // dead now (i.e. do not touch). As `idx` was the start of the
                // alive-zone, the alive zone is now `data[alive]` again, restoring
                // all invariants.
                unsafe { self.data.get_unchecked(idx).read() }
            })
        }

        fn size_hint(&self) -> (usize, Option<usize>) {
            let len = self.len();
            (len, Some(len))
        }

        fn count(self) -> usize {
            self.len()
        }

        fn last(mut self) -> Option<Self::Item> {
            self.next_back()
        }
    }

    #[stable(feature = "array_value_iter_impls", since = "1.40.0")]
    impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
        fn next_back(&mut self) -> Option<Self::Item> {
            // Get the next index from the back.
            //
            // Decreasing `alive.end` by 1 maintains the invariant regarding
            // `alive`. However, due to this change, for a short time, the alive
            // zone is not `data[alive]` anymore, but `data[alive.start..=idx]`.
            self.alive.next_back().map(|idx| {
                // Read the element from the array.
                // SAFETY: `idx` is an index into the former "alive" region of the
                // array. Reading this element means that `data[idx]` is regarded as
                // dead now (i.e. do not touch). As `idx` was the end of the
                // alive-zone, the alive zone is now `data[alive]` again, restoring
                // all invariants.
                unsafe { self.data.get_unchecked(idx).read() }
            })
        }
    }

    #[stable(feature = "array_value_iter_impls", since = "1.40.0")]
    impl<T, const N: usize> Drop for IntoIter<T, N> {
        fn drop(&mut self) {
            // SAFETY: This is safe: `as_mut_slice` returns exactly the sub-slice
            // of elements that have not been moved out yet and that remain
            // to be dropped.
            unsafe { ptr::drop_in_place(self.as_mut_slice()) }
        }
    }

    #[stable(feature = "array_value_iter_impls", since = "1.40.0")]
    impl<T, const N: usize> ExactSizeIterator for IntoIter<T, N> {
        fn len(&self) -> usize {
            // Will never underflow due to the invariant `alive.start <=
            // alive.end`.
            self.alive.end - self.alive.start
        }
        fn is_empty(&self) -> bool {
            self.alive.is_empty()
        }
    }

    #[stable(feature = "array_value_iter_impls", since = "1.40.0")]
    impl<T, const N: usize> FusedIterator for IntoIter<T, N> {}

    // The iterator indeed reports the correct length. The number of "alive"
    // elements (that will still be yielded) is the length of the range `alive`.
    // This range is decremented in length in either `next` or `next_back`. It is
    // always decremented by 1 in those methods, but only if `Some(_)` is returned.
    #[stable(feature = "array_value_iter_impls", since = "1.40.0")]
    unsafe impl<T, const N: usize> TrustedLen for IntoIter<T, N> {}

    #[stable(feature = "array_value_iter_impls", since = "1.40.0")]
    impl<T: Clone, const N: usize> Clone for IntoIter<T, N> {
        fn clone(&self) -> Self {
            // Note, we don't really need to match the exact same alive range, so
            // we can just clone into offset 0 regardless of where `self` is.
            let mut new = Self { data: MaybeUninit::uninit_array(), alive: 0..0 };

            // Clone all alive elements.
            for (src, dst) in self.as_slice().iter().zip(&mut new.data) {
                // Write a clone into the new array, then update its alive range.
                // If cloning panics, we'll correctly drop the previous items.
                dst.write(src.clone());
                new.alive.end += 1;
            }

            new
        }
    }

    #[stable(feature = "array_value_iter_impls", since = "1.40.0")]
    impl<T: fmt::Debug, const N: usize> fmt::Debug for IntoIter<T, N> {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            // Only print the elements that were not yielded yet: we cannot
            // access the yielded elements anymore.
            f.debug_tuple("IntoIter").field(&self.as_slice()).finish()
        }
    }