diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 966272ca11549..af10f843fa8b2 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -11,7 +11,9 @@ use crate::cmp::Ordering; use crate::convert::{Infallible, TryFrom}; use crate::fmt; use crate::hash::{self, Hash}; +use crate::iter::FromIterator; use crate::marker::Unsize; +use crate::mem::MaybeUninit; use crate::slice::{Iter, IterMut}; mod iter; @@ -188,6 +190,104 @@ impl fmt::Debug for [T; N] { } } +/// Return Error of the FromIterator impl for array +#[unstable(feature = "array_from_iter_impl", issue = "none")] +pub struct FillError { + array: [MaybeUninit; N], + len: usize, +} + +#[unstable(feature = "array_from_iter_impl", issue = "none")] +impl fmt::Display for FillError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt( + &format_args!("The iterator only returned {} items, but {} were needed", self.len(), N), + f, + ) + } +} + +#[unstable(feature = "array_from_iter_impl", issue = "none")] +impl fmt::Debug for FillError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("FillError") + .field("array", &self.as_slice()) + .field("len", &self.len()) + .finish() + } +} + +#[unstable(feature = "array_from_iter_impl", issue = "none")] +impl Drop for FillError { + fn drop(&mut self) { + // SAFETY: This is safe: `as_mut_slice` returns exactly the sub-slice + // of elements that have been initialized and need to be droped + unsafe { crate::ptr::drop_in_place(self.as_mut_slice()) } + } +} + +#[unstable(feature = "array_from_iter_impl", issue = "none")] +impl FillError { + fn new() -> Self { + Self { array: MaybeUninit::uninit_array(), len: 0 } + } + + /// Returns the how many elements were read from the given iterator. + pub fn len(&self) -> usize { + self.len + } + + /// Returns an immutable slice of all initialized elements. + pub fn as_slice(&self) -> &[T] { + // SAFETY: We know that all elements from 0 to len are properly initialized. + unsafe { MaybeUninit::slice_assume_init_ref(&self.array[0..self.len]) } + } + + /// Returns a mutable slice of all initialized elements. + pub fn as_mut_slice(&mut self) -> &mut [T] { + // SAFETY: We know that all elements from 0 to len are properly initialized. + unsafe { MaybeUninit::slice_assume_init_mut(&mut self.array[0..self.len]) } + } + + /// Tries to initialize the left-over elements using `iter`. + pub fn fill>(mut self, iter: I) -> Result<[T; N], FillError> { + let mut iter = iter.into_iter(); + + for i in self.len..N { + if let Some(value) = iter.next() { + self.array[i].write(value); + self.len += 1; + } else { + self.len = i; + return Err(self); + } + } + + // SAFETY: The transmute here is actually safe. The docs of `MaybeUninit` + // promise: + // + // > `MaybeUninit` is guaranteed to have the same size and alignment + // > as `T`. + // + // The docs even show a transmute from an array of `MaybeUninit` to + // an array of `T`. + // + // With that, this initialization satisfies the invariants. + // FIXME: actually use `mem::transmute` here, once it + // works with const generics: + // `mem::transmute::<[MaybeUninit; N], [T; N]>(array)` + Ok(unsafe { crate::ptr::read(&self.array as *const [MaybeUninit; N] as *const [T; N]) }) + } +} + +#[unstable(feature = "array_from_iter_impl", issue = "none")] +impl FromIterator for Result<[T; N], FillError> { + #[inline] + fn from_iter>(iter: I) -> Self { + FillError::::new().fill(iter) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T, const N: usize> IntoIterator for &'a [T; N] { type Item = &'a T; @@ -403,7 +503,6 @@ impl [T; N] { where F: FnMut(T) -> U, { - use crate::mem::MaybeUninit; struct Guard { dst: *mut T, initialized: usize, diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs index 89c2a969c28bb..a3a13b94b6169 100644 --- a/library/core/tests/array.rs +++ b/library/core/tests/array.rs @@ -374,3 +374,11 @@ fn cell_allows_array_cycle() { b3.a[0].set(Some(&b1)); b3.a[1].set(Some(&b2)); } + +#[test] +fn array_collects() { + let v = vec![1, 2, 3, 4, 5]; + let a: [i32; 5] = v.clone().into_iter().collect::>().unwrap(); + + assert_eq!(v[..], a[..]); +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 0c4ce867f542d..e13999de41c97 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -60,6 +60,7 @@ #![feature(unsafe_block_in_unsafe_fn)] #![feature(int_bits_const)] #![deny(unsafe_op_in_unsafe_fn)] +#![feature(array_from_iter_impl)] extern crate test; diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 81bbf37637875..0adf229721a52 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -492,6 +492,7 @@ mod prim_pointer {} /// Arrays of *any* size implement the following traits if the element type allows it: /// /// - [`Debug`] +/// - [`iter::FromIterator`] /// - [`IntoIterator`] (implemented for `&[T; N]` and `&mut [T; N]`) /// - [`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] /// - [`Hash`]