@@ -84,6 +84,135 @@ impl<T, const N: usize> IntoIter<T, N> {
8484 IntoIterator :: into_iter ( array)
8585 }
8686
87+ /// Creates an iterator over the elements in a partially-initialized buffer.
88+ ///
89+ /// If you have a fully-initialized array, then use [`IntoIterator`].
90+ /// But this is useful for returning partial results from unsafe code.
91+ ///
92+ /// # Safety
93+ ///
94+ /// - The `buffer[initialized]` elements must all be initialized.
95+ /// - The range must be canonical, with `initialized.start <= initialized.end`.
96+ /// - The range must in in-bounds for the buffer, with `initialized.end <= N`.
97+ /// (Like how indexing `[0][100..100]` fails despite the range being empty.)
98+ ///
99+ /// It's sound to have more elements initialized than mentioned, though that
100+ /// will most likely result in them being leaked.
101+ ///
102+ /// # Examples
103+ ///
104+ /// ```
105+ /// #![feature(array_into_iter_constructors)]
106+ ///
107+ /// #![feature(maybe_uninit_array_assume_init)]
108+ /// #![feature(maybe_uninit_uninit_array)]
109+ /// use std::array::IntoIter;
110+ /// use std::mem::MaybeUninit;
111+ ///
112+ /// # // Hi! Thanks for reading the code. This is restricted to `Copy` because
113+ /// # // otherwise it could leak. A fully-general version this would need a drop
114+ /// # // guard to handle panics from the iterator, but this works for an example.
115+ /// fn next_chunk<T: Copy, const N: usize>(
116+ /// it: &mut impl Iterator<Item = T>,
117+ /// ) -> Result<[T; N], IntoIter<T, N>> {
118+ /// let mut buffer = MaybeUninit::uninit_array();
119+ /// let mut i = 0;
120+ /// while i < N {
121+ /// match it.next() {
122+ /// Some(x) => {
123+ /// buffer[i].write(x);
124+ /// i += 1;
125+ /// }
126+ /// None => {
127+ /// // SAFETY: We've initialized the first `i` items
128+ /// unsafe {
129+ /// return Err(IntoIter::new_unchecked(buffer, 0..i));
130+ /// }
131+ /// }
132+ /// }
133+ /// }
134+ ///
135+ /// // SAFETY: We've initialized all N items
136+ /// unsafe { Ok(MaybeUninit::array_assume_init(buffer)) }
137+ /// }
138+ ///
139+ /// let r: [_; 4] = next_chunk(&mut (10..16)).unwrap();
140+ /// assert_eq!(r, [10, 11, 12, 13]);
141+ /// let r: IntoIter<_, 40> = next_chunk(&mut (10..16)).unwrap_err();
142+ /// assert_eq!(r.collect::<Vec<_>>(), vec![10, 11, 12, 13, 14, 15]);
143+ /// ```
144+ #[ unstable( feature = "array_into_iter_constructors" , issue = "91583" ) ]
145+ #[ rustc_const_unstable( feature = "const_array_into_iter_constructors" , issue = "91583" ) ]
146+ pub const unsafe fn new_unchecked (
147+ buffer : [ MaybeUninit < T > ; N ] ,
148+ initialized : Range < usize > ,
149+ ) -> Self {
150+ Self { data : buffer, alive : initialized }
151+ }
152+
153+ /// Creates an iterator over `T` which returns no elements.
154+ ///
155+ /// If you just need an empty iterator, then use
156+ /// [`iter::empty()`](crate::iter::empty) instead.
157+ /// And if you need an empty array, use `[]`.
158+ ///
159+ /// But this is useful when you need an `array::IntoIter<T, N>` *specifically*.
160+ ///
161+ /// # Examples
162+ ///
163+ /// ```
164+ /// #![feature(array_into_iter_constructors)]
165+ /// use std::array::IntoIter;
166+ ///
167+ /// let empty = IntoIter::<i32, 3>::empty();
168+ /// assert_eq!(empty.len(), 0);
169+ /// assert_eq!(empty.as_slice(), &[]);
170+ ///
171+ /// let empty = IntoIter::<std::convert::Infallible, 200>::empty();
172+ /// assert_eq!(empty.len(), 0);
173+ /// ```
174+ ///
175+ /// `[1, 2].into_iter()` and `[].into_iter()` have different types
176+ /// ```should_fail,edition2021
177+ /// #![feature(array_into_iter_constructors)]
178+ /// use std::array::IntoIter;
179+ ///
180+ /// pub fn get_bytes(b: bool) -> IntoIter<i8, 4> {
181+ /// if b {
182+ /// [1, 2, 3, 4].into_iter()
183+ /// } else {
184+ /// [].into_iter() // error[E0308]: mismatched types
185+ /// }
186+ /// }
187+ /// ```
188+ ///
189+ /// But using this method you can get an empty iterator of appropriate size:
190+ /// ```edition2021
191+ /// #![feature(array_into_iter_constructors)]
192+ /// use std::array::IntoIter;
193+ ///
194+ /// pub fn get_bytes(b: bool) -> IntoIter<i8, 4> {
195+ /// if b {
196+ /// [1, 2, 3, 4].into_iter()
197+ /// } else {
198+ /// IntoIter::empty()
199+ /// }
200+ /// }
201+ ///
202+ /// assert_eq!(get_bytes(true).collect::<Vec<_>>(), vec![1, 2, 3, 4]);
203+ /// assert_eq!(get_bytes(false).collect::<Vec<_>>(), vec![]);
204+ /// ```
205+ #[ unstable( feature = "array_into_iter_constructors" , issue = "91583" ) ]
206+ #[ rustc_const_unstable( feature = "const_array_into_iter_constructors" , issue = "91583" ) ]
207+ pub const fn empty ( ) -> Self {
208+ let buffer = MaybeUninit :: uninit_array ( ) ;
209+ let initialized = 0 ..0 ;
210+
211+ // SAFETY: We're telling it that none of the elements are initialized,
212+ // which is trivially true. And ∀N: usize, 0 <= N.
213+ unsafe { Self :: new_unchecked ( buffer, initialized) }
214+ }
215+
87216 /// Returns an immutable slice of all elements that have not been yielded
88217 /// yet.
89218 #[ stable( feature = "array_value_iter" , since = "1.51.0" ) ]
0 commit comments