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.)
This commit is contained in:
commit
677f878e36
@ -84,6 +84,135 @@ impl<T, const N: usize> IntoIter<T, N> {
|
||||
IntoIterator::into_iter(array)
|
||||
}
|
||||
|
||||
/// Creates an iterator over the elements in a partially-initialized buffer.
|
||||
///
|
||||
/// If you have a fully-initialized array, then use [`IntoIterator`].
|
||||
/// But this is useful for returning partial results from unsafe code.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - The `buffer[initialized]` elements must all be initialized.
|
||||
/// - The range must be canonical, with `initialized.start <= initialized.end`.
|
||||
/// - The range must in in-bounds for the buffer, with `initialized.end <= N`.
|
||||
/// (Like how indexing `[0][100..100]` fails despite the range being empty.)
|
||||
///
|
||||
/// It's sound to have more elements initialized than mentioned, though that
|
||||
/// will most likely result in them being leaked.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(array_into_iter_constructors)]
|
||||
///
|
||||
/// #![feature(maybe_uninit_array_assume_init)]
|
||||
/// #![feature(maybe_uninit_uninit_array)]
|
||||
/// use std::array::IntoIter;
|
||||
/// use std::mem::MaybeUninit;
|
||||
///
|
||||
/// # // Hi! Thanks for reading the code. This is restricted to `Copy` because
|
||||
/// # // otherwise it could leak. A fully-general version this would need a drop
|
||||
/// # // guard to handle panics from the iterator, but this works for an example.
|
||||
/// fn next_chunk<T: Copy, const N: usize>(
|
||||
/// it: &mut impl Iterator<Item = T>,
|
||||
/// ) -> Result<[T; N], IntoIter<T, N>> {
|
||||
/// let mut buffer = MaybeUninit::uninit_array();
|
||||
/// let mut i = 0;
|
||||
/// while i < N {
|
||||
/// match it.next() {
|
||||
/// Some(x) => {
|
||||
/// buffer[i].write(x);
|
||||
/// i += 1;
|
||||
/// }
|
||||
/// None => {
|
||||
/// // SAFETY: We've initialized the first `i` items
|
||||
/// unsafe {
|
||||
/// return Err(IntoIter::new_unchecked(buffer, 0..i));
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // SAFETY: We've initialized all N items
|
||||
/// unsafe { Ok(MaybeUninit::array_assume_init(buffer)) }
|
||||
/// }
|
||||
///
|
||||
/// let r: [_; 4] = next_chunk(&mut (10..16)).unwrap();
|
||||
/// assert_eq!(r, [10, 11, 12, 13]);
|
||||
/// let r: IntoIter<_, 40> = next_chunk(&mut (10..16)).unwrap_err();
|
||||
/// assert_eq!(r.collect::<Vec<_>>(), vec![10, 11, 12, 13, 14, 15]);
|
||||
/// ```
|
||||
#[unstable(feature = "array_into_iter_constructors", issue = "91583")]
|
||||
#[rustc_const_unstable(feature = "const_array_into_iter_constructors", issue = "91583")]
|
||||
pub const unsafe fn new_unchecked(
|
||||
buffer: [MaybeUninit<T>; N],
|
||||
initialized: Range<usize>,
|
||||
) -> Self {
|
||||
Self { data: buffer, alive: initialized }
|
||||
}
|
||||
|
||||
/// Creates an iterator over `T` which returns no elements.
|
||||
///
|
||||
/// If you just need an empty iterator, then use
|
||||
/// [`iter::empty()`](crate::iter::empty) instead.
|
||||
/// And if you need an empty array, use `[]`.
|
||||
///
|
||||
/// But this is useful when you need an `array::IntoIter<T, N>` *specifically*.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(array_into_iter_constructors)]
|
||||
/// use std::array::IntoIter;
|
||||
///
|
||||
/// let empty = IntoIter::<i32, 3>::empty();
|
||||
/// assert_eq!(empty.len(), 0);
|
||||
/// assert_eq!(empty.as_slice(), &[]);
|
||||
///
|
||||
/// let empty = IntoIter::<std::convert::Infallible, 200>::empty();
|
||||
/// assert_eq!(empty.len(), 0);
|
||||
/// ```
|
||||
///
|
||||
/// `[1, 2].into_iter()` and `[].into_iter()` have different types
|
||||
/// ```should_fail,edition2021
|
||||
/// #![feature(array_into_iter_constructors)]
|
||||
/// use std::array::IntoIter;
|
||||
///
|
||||
/// pub fn get_bytes(b: bool) -> IntoIter<i8, 4> {
|
||||
/// if b {
|
||||
/// [1, 2, 3, 4].into_iter()
|
||||
/// } else {
|
||||
/// [].into_iter() // error[E0308]: mismatched types
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// But using this method you can get an empty iterator of appropriate size:
|
||||
/// ```edition2021
|
||||
/// #![feature(array_into_iter_constructors)]
|
||||
/// use std::array::IntoIter;
|
||||
///
|
||||
/// pub fn get_bytes(b: bool) -> IntoIter<i8, 4> {
|
||||
/// if b {
|
||||
/// [1, 2, 3, 4].into_iter()
|
||||
/// } else {
|
||||
/// IntoIter::empty()
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(get_bytes(true).collect::<Vec<_>>(), vec![1, 2, 3, 4]);
|
||||
/// assert_eq!(get_bytes(false).collect::<Vec<_>>(), vec![]);
|
||||
/// ```
|
||||
#[unstable(feature = "array_into_iter_constructors", issue = "91583")]
|
||||
#[rustc_const_unstable(feature = "const_array_into_iter_constructors", issue = "91583")]
|
||||
pub const fn empty() -> Self {
|
||||
let buffer = MaybeUninit::uninit_array();
|
||||
let initialized = 0..0;
|
||||
|
||||
// SAFETY: We're telling it that none of the elements are initialized,
|
||||
// which is trivially true. And ∀N: usize, 0 <= N.
|
||||
unsafe { Self::new_unchecked(buffer, initialized) }
|
||||
}
|
||||
|
||||
/// Returns an immutable slice of all elements that have not been yielded
|
||||
/// yet.
|
||||
#[stable(feature = "array_value_iter", since = "1.51.0")]
|
||||
|
@ -101,6 +101,7 @@
|
||||
#![feature(const_align_of_val)]
|
||||
#![feature(const_alloc_layout)]
|
||||
#![feature(const_arguments_as_str)]
|
||||
#![feature(const_array_into_iter_constructors)]
|
||||
#![feature(const_bigint_helper_methods)]
|
||||
#![feature(const_caller_location)]
|
||||
#![feature(const_cell_into_inner)]
|
||||
@ -138,6 +139,7 @@
|
||||
#![feature(const_type_name)]
|
||||
#![feature(const_default_impls)]
|
||||
#![feature(duration_consts_float)]
|
||||
#![feature(maybe_uninit_uninit_array)]
|
||||
#![feature(ptr_metadata)]
|
||||
#![feature(slice_ptr_get)]
|
||||
#![feature(str_internals)]
|
||||
|
Loading…
Reference in New Issue
Block a user