Skip to content

Commit 6c6b51c

Browse files
lperlakilcnr
authored andcommitted
Add array::FillError to core
1 parent 78a0894 commit 6c6b51c

File tree

3 files changed

+138
-0
lines changed

3 files changed

+138
-0
lines changed

library/core/src/array/mod.rs

+99
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ use crate::cmp::Ordering;
1111
use crate::convert::{Infallible, TryFrom};
1212
use crate::fmt;
1313
use crate::hash::{self, Hash};
14+
use crate::iter::FromIterator;
1415
use crate::marker::Unsize;
16+
use crate::mem::MaybeUninit;
1517
use crate::slice::{Iter, IterMut};
1618

1719
mod iter;
@@ -174,6 +176,103 @@ impl<T: fmt::Debug, const N: usize> fmt::Debug for [T; N] {
174176
}
175177
}
176178

179+
/// Return Error of the FromIterator impl for array
180+
#[unstable(feature = "array_from_iter_impl", issue = "none")]
181+
pub struct FillError<T, const N: usize> {
182+
array: [MaybeUninit<T>; N],
183+
len: usize,
184+
}
185+
186+
#[unstable(feature = "array_from_iter_impl", issue = "none")]
187+
impl<T, const N: usize> fmt::Display for FillError<T, N> {
188+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189+
fmt::Display::fmt(
190+
&format_args!("The iterator only returned {} items, but {} were needed", self.len(), N),
191+
f,
192+
)
193+
}
194+
}
195+
196+
#[unstable(feature = "array_from_iter_impl", issue = "none")]
197+
impl<T: fmt::Debug, const N: usize> fmt::Debug for FillError<T, N> {
198+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199+
f.debug_struct("FillError")
200+
.field("array", &self.as_slice())
201+
.field("len", &self.len())
202+
.finish()
203+
}
204+
}
205+
206+
#[unstable(feature = "array_from_iter_impl", issue = "none")]
207+
impl<T, const N: usize> Drop for FillError<T, N> {
208+
fn drop(&mut self) {
209+
// SAFETY: This is safe: `as_mut_slice` returns exactly the sub-slice
210+
// of elements that have been initialized and need to be droped
211+
unsafe { crate::ptr::drop_in_place(self.as_mut_slice()) }
212+
}
213+
}
214+
215+
#[unstable(feature = "array_from_iter_impl", issue = "none")]
216+
impl<T, const N: usize> FillError<T, N> {
217+
fn new() -> Self {
218+
Self { array: MaybeUninit::uninit_array(), len: 0 }
219+
}
220+
221+
/// Returns how many elements were read from the given iterator.
222+
pub fn len(&self) -> usize {
223+
self.len
224+
}
225+
226+
/// Returns an immutable slice of all initialized elements.
227+
pub fn as_slice(&self) -> &[T] {
228+
// SAFETY: We know that all elements from 0 to len are properly initialized.
229+
unsafe { MaybeUninit::slice_get_ref(&self.array[0..self.len]) }
230+
}
231+
232+
/// Returns a mutable slice of all initialized elements.
233+
pub fn as_mut_slice(&mut self) -> &mut [T] {
234+
// SAFETY: We know that all elements from 0 to len are properly initialized.
235+
unsafe { MaybeUninit::slice_get_mut(&mut self.array[0..self.len]) }
236+
}
237+
238+
/// Tries to initialize the left-over elements using `iter`.
239+
pub fn fill<I: IntoIterator<Item = T>>(mut self, iter: I) -> Result<[T; N], FillError<T, N>> {
240+
let mut iter = iter.into_iter();
241+
242+
for i in self.len..N {
243+
if let Some(value) = iter.next() {
244+
self.array[i].write(value);
245+
} else {
246+
self.len = i;
247+
return Err(self);
248+
}
249+
}
250+
251+
// SAFETY: The transmute here is actually safe. The docs of `MaybeUninit`
252+
// promise:
253+
//
254+
// > `MaybeUninit<T>` is guaranteed to have the same size and alignment
255+
// > as `T`.
256+
//
257+
// The docs even show a transmute from an array of `MaybeUninit<T>` to
258+
// an array of `T`.
259+
//
260+
// With that, this initialization satisfies the invariants.
261+
// FIXME: actually use `mem::transmute` here, once it
262+
// works with const generics:
263+
// `mem::transmute::<[MaybeUninit<T>; N], [T; N]>(array)`
264+
Ok(unsafe { crate::ptr::read(&self.array as *const [MaybeUninit<T>; N] as *const [T; N]) })
265+
}
266+
}
267+
268+
#[unstable(feature = "array_from_iter_impl", issue = "none")]
269+
impl<T, const N: usize> FromIterator<T> for Result<[T; N], FillError<T, N>> {
270+
#[inline]
271+
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
272+
FillError::<T, N>::new().fill(iter)
273+
}
274+
}
275+
177276
#[stable(feature = "rust1", since = "1.0.0")]
178277
impl<'a, T, const N: usize> IntoIterator for &'a [T; N] {
179278
type Item = &'a T;

library/core/tests/array.rs

+38
Original file line numberDiff line numberDiff line change
@@ -330,3 +330,41 @@ fn array_map_drop_safety() {
330330
assert_eq!(DROPPED.load(Ordering::SeqCst), num_to_create);
331331
panic!("test succeeded")
332332
}
333+
334+
#[test]
335+
fn array_collects() {
336+
let v = vec![1, 2, 3, 4, 5];
337+
let a: [i32; 5] = v
338+
.clone()
339+
.into_iter()
340+
.collect::<Result<[i32; 5], core::array::FillError<i32, 5>>>()
341+
.unwrap();
342+
343+
assert_eq!(v[..], a[..]);
344+
}
345+
346+
#[test]
347+
fn array_collect_drop_on_panic() {
348+
use std::sync::atomic::{AtomicUsize, Ordering};
349+
use std::sync::Arc;
350+
351+
#[derive(Clone)]
352+
struct Foo(Arc<AtomicUsize>);
353+
354+
// count the number of eleemts that got dropped
355+
impl Drop for Foo {
356+
fn drop(&mut self) {
357+
self.0.fetch_add(1, Ordering::SeqCst);
358+
}
359+
}
360+
361+
let i = Arc::new(AtomicUsize::new(0));
362+
let foo = Foo(i.clone());
363+
364+
std::panic::catch_unwind(move || {
365+
let _a: [Foo; 5] = from_iter(vec![foo.clone(), foo.clone(), foo.clone(), foo]);
366+
})
367+
.unwrap_err();
368+
369+
assert_eq!(i.load(Ordering::SeqCst), 4);
370+
}

library/core/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
#![feature(unsafe_block_in_unsafe_fn)]
5757
#![feature(int_bits_const)]
5858
#![deny(unsafe_op_in_unsafe_fn)]
59+
#![feature(array_from_iter_impl)]
5960

6061
extern crate test;
6162

0 commit comments

Comments
 (0)