diff options
| author | Yuki Okushi <huyuumi.dev@gmail.com> | 2021-01-12 16:13:24 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-01-12 16:13:24 +0900 |
| commit | babfdafb10cb77f980b11eb7e2ccf0ccdb72b8a1 (patch) | |
| tree | 4f0a9446173ddd9fe94683fc4d1ed2edcd516701 | |
| parent | 86b900a3eaaf84b48f080dab14b7994385bd19b8 (diff) | |
| parent | 985071b08f5c03e4f18d43c15f3ea82395588a5e (diff) | |
| download | rust-babfdafb10cb77f980b11eb7e2ccf0ccdb72b8a1.tar.gz rust-babfdafb10cb77f980b11eb7e2ccf0ccdb72b8a1.zip | |
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?
| -rw-r--r-- | library/core/src/mem/maybe_uninit.rs | 40 | ||||
| -rw-r--r-- | library/core/tests/lib.rs | 2 | ||||
| -rw-r--r-- | library/core/tests/mem.rs | 14 |
3 files changed, 56 insertions, 0 deletions
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index b2a4d897eed..fda0553f94c 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -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 diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index e01aaa4cbf1..bc737cd1927 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -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)] diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 79ca2bba403..2279a16429f 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -141,6 +141,20 @@ fn assume_init_good() { } #[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]; let src = [0; 64]; |
