core/array/iter.rs
1//! Defines the `IntoIter` owned iterator for arrays.
2
3use crate::intrinsics::transmute_unchecked;
4#[cfg(not(feature = "ferrocene_certified"))]
5use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccessNoCoerce};
6use crate::mem::{ManuallyDrop, MaybeUninit};
7#[cfg(not(feature = "ferrocene_certified"))]
8use crate::num::NonZero;
9#[cfg(not(feature = "ferrocene_certified"))]
10use crate::ops::{Deref as _, DerefMut as _, IndexRange, Range, Try};
11#[cfg(not(feature = "ferrocene_certified"))]
12use crate::{fmt, ptr};
13
14// Ferrocene addition: imports for certified subset
15#[cfg(feature = "ferrocene_certified")]
16#[rustfmt::skip]
17use crate::ops::{Deref as _, DerefMut as _, IndexRange};
18
19mod iter_inner;
20
21type InnerSized<T, const N: usize> = iter_inner::PolymorphicIter<[MaybeUninit<T>; N]>;
22type InnerUnsized<T> = iter_inner::PolymorphicIter<[MaybeUninit<T>]>;
23
24/// A by-value [array] iterator.
25#[stable(feature = "array_value_iter", since = "1.51.0")]
26#[rustc_insignificant_dtor]
27#[rustc_diagnostic_item = "ArrayIntoIter"]
28#[derive(Clone)]
29pub struct IntoIter<T, const N: usize> {
30 inner: ManuallyDrop<InnerSized<T, N>>,
31}
32
33impl<T, const N: usize> IntoIter<T, N> {
34 #[inline]
35 fn unsize(&self) -> &InnerUnsized<T> {
36 self.inner.deref()
37 }
38 #[inline]
39 fn unsize_mut(&mut self) -> &mut InnerUnsized<T> {
40 self.inner.deref_mut()
41 }
42}
43
44// Note: the `#[rustc_skip_during_method_dispatch(array)]` on `trait IntoIterator`
45// hides this implementation from explicit `.into_iter()` calls on editions < 2021,
46// so those calls will still resolve to the slice implementation, by reference.
47#[stable(feature = "array_into_iter_impl", since = "1.53.0")]
48impl<T, const N: usize> IntoIterator for [T; N] {
49 type Item = T;
50 type IntoIter = IntoIter<T, N>;
51
52 /// Creates a consuming iterator, that is, one that moves each value out of
53 /// the array (from start to end).
54 ///
55 /// The array cannot be used after calling this unless `T` implements
56 /// `Copy`, so the whole array is copied.
57 ///
58 /// Arrays have special behavior when calling `.into_iter()` prior to the
59 /// 2021 edition -- see the [array] Editions section for more information.
60 ///
61 /// [array]: prim@array
62 #[inline]
63 fn into_iter(self) -> Self::IntoIter {
64 // SAFETY: The transmute here is actually safe. The docs of `MaybeUninit`
65 // promise:
66 //
67 // > `MaybeUninit<T>` is guaranteed to have the same size and alignment
68 // > as `T`.
69 //
70 // The docs even show a transmute from an array of `MaybeUninit<T>` to
71 // an array of `T`.
72 //
73 // With that, this initialization satisfies the invariants.
74 //
75 // FIXME: If normal `transmute` ever gets smart enough to allow this
76 // directly, use it instead of `transmute_unchecked`.
77 let data: [MaybeUninit<T>; N] = unsafe { transmute_unchecked(self) };
78 // SAFETY: The original array was entirely initialized and the the alive
79 // range we're passing here represents that fact.
80 let inner = unsafe { InnerSized::new_unchecked(IndexRange::zero_to(N), data) };
81 IntoIter { inner: ManuallyDrop::new(inner) }
82 }
83}
84
85#[cfg(not(feature = "ferrocene_certified"))]
86impl<T, const N: usize> IntoIter<T, N> {
87 /// Creates a new iterator over the given `array`.
88 #[stable(feature = "array_value_iter", since = "1.51.0")]
89 #[deprecated(since = "1.59.0", note = "use `IntoIterator::into_iter` instead")]
90 pub fn new(array: [T; N]) -> Self {
91 IntoIterator::into_iter(array)
92 }
93
94 /// Creates an iterator over the elements in a partially-initialized buffer.
95 ///
96 /// If you have a fully-initialized array, then use [`IntoIterator`].
97 /// But this is useful for returning partial results from unsafe code.
98 ///
99 /// # Safety
100 ///
101 /// - The `buffer[initialized]` elements must all be initialized.
102 /// - The range must be canonical, with `initialized.start <= initialized.end`.
103 /// - The range must be in-bounds for the buffer, with `initialized.end <= N`.
104 /// (Like how indexing `[0][100..100]` fails despite the range being empty.)
105 ///
106 /// It's sound to have more elements initialized than mentioned, though that
107 /// will most likely result in them being leaked.
108 ///
109 /// # Examples
110 ///
111 /// ```
112 /// #![feature(array_into_iter_constructors)]
113 /// #![feature(maybe_uninit_uninit_array_transpose)]
114 /// use std::array::IntoIter;
115 /// use std::mem::MaybeUninit;
116 ///
117 /// # // Hi! Thanks for reading the code. This is restricted to `Copy` because
118 /// # // otherwise it could leak. A fully-general version this would need a drop
119 /// # // guard to handle panics from the iterator, but this works for an example.
120 /// fn next_chunk<T: Copy, const N: usize>(
121 /// it: &mut impl Iterator<Item = T>,
122 /// ) -> Result<[T; N], IntoIter<T, N>> {
123 /// let mut buffer = [const { MaybeUninit::uninit() }; N];
124 /// let mut i = 0;
125 /// while i < N {
126 /// match it.next() {
127 /// Some(x) => {
128 /// buffer[i].write(x);
129 /// i += 1;
130 /// }
131 /// None => {
132 /// // SAFETY: We've initialized the first `i` items
133 /// unsafe {
134 /// return Err(IntoIter::new_unchecked(buffer, 0..i));
135 /// }
136 /// }
137 /// }
138 /// }
139 ///
140 /// // SAFETY: We've initialized all N items
141 /// unsafe { Ok(buffer.transpose().assume_init()) }
142 /// }
143 ///
144 /// let r: [_; 4] = next_chunk(&mut (10..16)).unwrap();
145 /// assert_eq!(r, [10, 11, 12, 13]);
146 /// let r: IntoIter<_, 40> = next_chunk(&mut (10..16)).unwrap_err();
147 /// assert_eq!(r.collect::<Vec<_>>(), vec![10, 11, 12, 13, 14, 15]);
148 /// ```
149 #[unstable(feature = "array_into_iter_constructors", issue = "91583")]
150 #[inline]
151 pub const unsafe fn new_unchecked(
152 buffer: [MaybeUninit<T>; N],
153 initialized: Range<usize>,
154 ) -> Self {
155 // SAFETY: one of our safety conditions is that the range is canonical.
156 let alive = unsafe { IndexRange::new_unchecked(initialized.start, initialized.end) };
157 // SAFETY: one of our safety condition is that these items are initialized.
158 let inner = unsafe { InnerSized::new_unchecked(alive, buffer) };
159 IntoIter { inner: ManuallyDrop::new(inner) }
160 }
161
162 /// Creates an iterator over `T` which returns no elements.
163 ///
164 /// If you just need an empty iterator, then use
165 /// [`iter::empty()`](crate::iter::empty) instead.
166 /// And if you need an empty array, use `[]`.
167 ///
168 /// But this is useful when you need an `array::IntoIter<T, N>` *specifically*.
169 ///
170 /// # Examples
171 ///
172 /// ```
173 /// #![feature(array_into_iter_constructors)]
174 /// use std::array::IntoIter;
175 ///
176 /// let empty = IntoIter::<i32, 3>::empty();
177 /// assert_eq!(empty.len(), 0);
178 /// assert_eq!(empty.as_slice(), &[]);
179 ///
180 /// let empty = IntoIter::<std::convert::Infallible, 200>::empty();
181 /// assert_eq!(empty.len(), 0);
182 /// ```
183 ///
184 /// `[1, 2].into_iter()` and `[].into_iter()` have different types
185 /// ```should_fail,edition2021
186 /// #![feature(array_into_iter_constructors)]
187 /// use std::array::IntoIter;
188 ///
189 /// pub fn get_bytes(b: bool) -> IntoIter<i8, 4> {
190 /// if b {
191 /// [1, 2, 3, 4].into_iter()
192 /// } else {
193 /// [].into_iter() // error[E0308]: mismatched types
194 /// }
195 /// }
196 /// ```
197 ///
198 /// But using this method you can get an empty iterator of appropriate size:
199 /// ```edition2021
200 /// #![feature(array_into_iter_constructors)]
201 /// use std::array::IntoIter;
202 ///
203 /// pub fn get_bytes(b: bool) -> IntoIter<i8, 4> {
204 /// if b {
205 /// [1, 2, 3, 4].into_iter()
206 /// } else {
207 /// IntoIter::empty()
208 /// }
209 /// }
210 ///
211 /// assert_eq!(get_bytes(true).collect::<Vec<_>>(), vec![1, 2, 3, 4]);
212 /// assert_eq!(get_bytes(false).collect::<Vec<_>>(), vec![]);
213 /// ```
214 #[unstable(feature = "array_into_iter_constructors", issue = "91583")]
215 #[inline]
216 pub const fn empty() -> Self {
217 let inner = InnerSized::empty();
218 IntoIter { inner: ManuallyDrop::new(inner) }
219 }
220
221 /// Returns an immutable slice of all elements that have not been yielded
222 /// yet.
223 #[stable(feature = "array_value_iter", since = "1.51.0")]
224 #[inline]
225 pub fn as_slice(&self) -> &[T] {
226 self.unsize().as_slice()
227 }
228
229 /// Returns a mutable slice of all elements that have not been yielded yet.
230 #[stable(feature = "array_value_iter", since = "1.51.0")]
231 #[inline]
232 pub fn as_mut_slice(&mut self) -> &mut [T] {
233 self.unsize_mut().as_mut_slice()
234 }
235}
236
237#[stable(feature = "array_value_iter_default", since = "1.89.0")]
238#[cfg(not(feature = "ferrocene_certified"))]
239impl<T, const N: usize> Default for IntoIter<T, N> {
240 fn default() -> Self {
241 IntoIter::empty()
242 }
243}
244
245#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
246impl<T, const N: usize> Iterator for IntoIter<T, N> {
247 type Item = T;
248
249 #[inline]
250 fn next(&mut self) -> Option<Self::Item> {
251 self.unsize_mut().next()
252 }
253
254 #[inline]
255 fn size_hint(&self) -> (usize, Option<usize>) {
256 self.unsize().size_hint()
257 }
258
259 #[inline]
260 #[cfg(not(feature = "ferrocene_certified"))]
261 fn fold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc
262 where
263 Fold: FnMut(Acc, Self::Item) -> Acc,
264 {
265 self.unsize_mut().fold(init, fold)
266 }
267
268 #[inline]
269 #[cfg(not(feature = "ferrocene_certified"))]
270 fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
271 where
272 Self: Sized,
273 F: FnMut(B, Self::Item) -> R,
274 R: Try<Output = B>,
275 {
276 self.unsize_mut().try_fold(init, f)
277 }
278
279 #[inline]
280 #[cfg(not(feature = "ferrocene_certified"))]
281 fn count(self) -> usize {
282 self.len()
283 }
284
285 #[inline]
286 #[cfg(not(feature = "ferrocene_certified"))]
287 fn last(mut self) -> Option<Self::Item> {
288 self.next_back()
289 }
290
291 #[inline]
292 #[cfg(not(feature = "ferrocene_certified"))]
293 fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
294 self.unsize_mut().advance_by(n)
295 }
296
297 #[inline]
298 #[cfg(not(feature = "ferrocene_certified"))]
299 unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
300 // SAFETY: The caller must provide an idx that is in bound of the remainder.
301 let elem_ref = unsafe { self.as_mut_slice().get_unchecked_mut(idx) };
302 // SAFETY: We only implement `TrustedRandomAccessNoCoerce` for types
303 // which are actually `Copy`, so cannot have multiple-drop issues.
304 unsafe { ptr::read(elem_ref) }
305 }
306}
307
308#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
309#[cfg(not(feature = "ferrocene_certified"))]
310impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
311 #[inline]
312 fn next_back(&mut self) -> Option<Self::Item> {
313 self.unsize_mut().next_back()
314 }
315
316 #[inline]
317 fn rfold<Acc, Fold>(mut self, init: Acc, rfold: Fold) -> Acc
318 where
319 Fold: FnMut(Acc, Self::Item) -> Acc,
320 {
321 self.unsize_mut().rfold(init, rfold)
322 }
323
324 #[inline]
325 fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
326 where
327 Self: Sized,
328 F: FnMut(B, Self::Item) -> R,
329 R: Try<Output = B>,
330 {
331 self.unsize_mut().try_rfold(init, f)
332 }
333
334 #[inline]
335 fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
336 self.unsize_mut().advance_back_by(n)
337 }
338}
339
340#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
341// Even though all the Drop logic could be completely handled by
342// PolymorphicIter, this impl still serves two purposes:
343// - Drop has been part of the public API, so we can't remove it
344// - the partial_drop function doesn't always get fully optimized away
345// for !Drop types and ends up as dead code in the final binary.
346// Branching on needs_drop higher in the call-tree allows it to be
347// removed by earlier optimization passes.
348impl<T, const N: usize> Drop for IntoIter<T, N> {
349 #[inline]
350 fn drop(&mut self) {
351 if crate::mem::needs_drop::<T>() {
352 // SAFETY: This is the only place where we drop this field.
353 unsafe { ManuallyDrop::drop(&mut self.inner) }
354 }
355 }
356}
357
358#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
359#[cfg(not(feature = "ferrocene_certified"))]
360impl<T, const N: usize> ExactSizeIterator for IntoIter<T, N> {
361 #[inline]
362 fn len(&self) -> usize {
363 self.inner.len()
364 }
365 #[inline]
366 fn is_empty(&self) -> bool {
367 self.inner.len() == 0
368 }
369}
370
371#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
372#[cfg(not(feature = "ferrocene_certified"))]
373impl<T, const N: usize> FusedIterator for IntoIter<T, N> {}
374
375// The iterator indeed reports the correct length. The number of "alive"
376// elements (that will still be yielded) is the length of the range `alive`.
377// This range is decremented in length in either `next` or `next_back`. It is
378// always decremented by 1 in those methods, but only if `Some(_)` is returned.
379#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
380#[cfg(not(feature = "ferrocene_certified"))]
381unsafe impl<T, const N: usize> TrustedLen for IntoIter<T, N> {}
382
383#[doc(hidden)]
384#[unstable(issue = "none", feature = "std_internals")]
385#[rustc_unsafe_specialization_marker]
386#[cfg(not(feature = "ferrocene_certified"))]
387pub trait NonDrop {}
388
389// T: Copy as approximation for !Drop since get_unchecked does not advance self.alive
390// and thus we can't implement drop-handling
391#[unstable(issue = "none", feature = "std_internals")]
392#[cfg(not(feature = "ferrocene_certified"))]
393impl<T: Copy> NonDrop for T {}
394
395#[doc(hidden)]
396#[unstable(issue = "none", feature = "std_internals")]
397#[cfg(not(feature = "ferrocene_certified"))]
398unsafe impl<T, const N: usize> TrustedRandomAccessNoCoerce for IntoIter<T, N>
399where
400 T: NonDrop,
401{
402 const MAY_HAVE_SIDE_EFFECT: bool = false;
403}
404
405#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
406#[cfg(not(feature = "ferrocene_certified"))]
407impl<T: fmt::Debug, const N: usize> fmt::Debug for IntoIter<T, N> {
408 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
409 self.unsize().fmt(f)
410 }
411}