Skip to content

Commit 677f878

Browse files
authored
Rollup merge of #91341 - scottmcm:array-iter-frp, r=kennytm
Add `array::IntoIter::{empty, from_raw_parts}` `array::IntoIter` has a bunch of really handy logic for dealing with partial arrays, but it's currently hamstrung by only being creatable from a fully-initialized array. This PR adds two new constructors: - a safe & const `empty`, since `[].into_iter()` can only give `IntoIter<T, 0>`, not `IntoIter<T, N>`. - an unsafe `from_raw_parts`, to allow experimentation with new uses. (Slice & vec iterators don't need `from_raw_parts` because you `from_raw_parts` the slice or vec instead, but there's no useful way to made a `<[T; N]>::from_raw_parts`, so I think this is a reasonable place to have one.)
2 parents 57ae43d + 9b86c59 commit 677f878

File tree

2 files changed

+131
-0
lines changed

2 files changed

+131
-0
lines changed

library/core/src/array/iter.rs

+129
Original file line numberDiff line numberDiff line change
@@ -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")]

library/core/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
#![feature(const_align_of_val)]
102102
#![feature(const_alloc_layout)]
103103
#![feature(const_arguments_as_str)]
104+
#![feature(const_array_into_iter_constructors)]
104105
#![feature(const_bigint_helper_methods)]
105106
#![feature(const_caller_location)]
106107
#![feature(const_cell_into_inner)]
@@ -138,6 +139,7 @@
138139
#![feature(const_type_name)]
139140
#![feature(const_default_impls)]
140141
#![feature(duration_consts_float)]
142+
#![feature(maybe_uninit_uninit_array)]
141143
#![feature(ptr_metadata)]
142144
#![feature(slice_ptr_get)]
143145
#![feature(str_internals)]

0 commit comments

Comments
 (0)