Rollup merge of #80600 - CoffeeBlend:maybe_uninit_array_assume_init, r=dtolnay
Add `MaybeUninit` method `array_assume_init` When initialising an array element-by-element, the conversion to the initialised array is done through `mem::transmute`, which is both ugly and does not work with const generics (see #61956). This PR proposes the associated method `array_assume_init`, matching the style of `slice_assume_init_*`: ```rust unsafe fn array_assume_init<T, const N: usize>(array: [MaybeUninit<T>; N]) -> [T; N]; ``` Example: ```rust let mut array: [MaybeUninit<i32>; 3] = MaybeUninit::uninit_array(); array[0].write(0); array[1].write(1); array[2].write(2); // SAFETY: Now safe as we initialised all elements let array: [i32; 3] = unsafe { MaybeUninit::array_assume_init(array) }; ``` Things I'm unsure about: * Should this be a method of array instead? * Should the function be const?
This commit is contained in:
commit
babfdafb10
3 changed files with 56 additions and 0 deletions
|
|
@ -804,6 +804,46 @@ impl<T> MaybeUninit<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Extracts the values from an array of `MaybeUninit` containers.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is up to the caller to guarantee that all elements of the array are
|
||||
/// in an initialized state.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(maybe_uninit_uninit_array)]
|
||||
/// #![feature(maybe_uninit_array_assume_init)]
|
||||
/// use std::mem::MaybeUninit;
|
||||
///
|
||||
/// let mut array: [MaybeUninit<i32>; 3] = MaybeUninit::uninit_array();
|
||||
/// array[0] = MaybeUninit::new(0);
|
||||
/// array[1] = MaybeUninit::new(1);
|
||||
/// array[2] = MaybeUninit::new(2);
|
||||
///
|
||||
/// // SAFETY: Now safe as we initialised all elements
|
||||
/// let array = unsafe {
|
||||
/// MaybeUninit::array_assume_init(array)
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(array, [0, 1, 2]);
|
||||
/// ```
|
||||
#[unstable(feature = "maybe_uninit_array_assume_init", issue = "80908")]
|
||||
#[inline(always)]
|
||||
pub unsafe fn array_assume_init<const N: usize>(array: [Self; N]) -> [T; N] {
|
||||
// SAFETY:
|
||||
// * The caller guarantees that all elements of the array are initialized
|
||||
// * `MaybeUninit<T>` and T are guaranteed to have the same layout
|
||||
// * MaybeUnint does not drop, so there are no double-frees
|
||||
// And thus the conversion is safe
|
||||
unsafe {
|
||||
intrinsics::assert_inhabited::<T>();
|
||||
(&array as *const _ as *const [T; N]).read()
|
||||
}
|
||||
}
|
||||
|
||||
/// Assuming all the elements are initialized, get a slice to them.
|
||||
///
|
||||
/// # Safety
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@
|
|||
#![feature(raw)]
|
||||
#![feature(sort_internals)]
|
||||
#![feature(slice_partition_at_index)]
|
||||
#![feature(maybe_uninit_uninit_array)]
|
||||
#![feature(maybe_uninit_array_assume_init)]
|
||||
#![feature(maybe_uninit_extra)]
|
||||
#![feature(maybe_uninit_write_slice)]
|
||||
#![feature(min_specialization)]
|
||||
|
|
|
|||
|
|
@ -140,6 +140,20 @@ fn assume_init_good() {
|
|||
assert!(TRUE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uninit_array_assume_init() {
|
||||
let mut array: [MaybeUninit<i16>; 5] = MaybeUninit::uninit_array();
|
||||
array[0].write(3);
|
||||
array[1].write(1);
|
||||
array[2].write(4);
|
||||
array[3].write(1);
|
||||
array[4].write(5);
|
||||
|
||||
let array = unsafe { MaybeUninit::array_assume_init(array) };
|
||||
|
||||
assert_eq!(array, [3, 1, 4, 1, 5]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uninit_write_slice() {
|
||||
let mut dst = [MaybeUninit::new(255); 64];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue