From 826bc3648af1596413de0e7dcfe5f32665619608 Mon Sep 17 00:00:00 2001 From: CoffeeBlend Date: Fri, 1 Jan 2021 22:03:14 +0100 Subject: [PATCH 1/6] Implement MaybeUninit::array_assume_init --- library/core/src/mem/maybe_uninit.rs | 49 ++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index b2a4d897eeded..b157eec24b410 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -804,6 +804,55 @@ impl MaybeUninit { } } + /// 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; 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 = "none")] + #[inline(always)] + pub unsafe fn array_assume_init(array: [Self; N]) -> [T; N] { + // Convert using a union because mem::transmute does not support const_generics + union ArrayInit { + maybe_uninit: ManuallyDrop<[MaybeUninit; N]>, + init: ManuallyDrop<[T; N]>, + } + + // SAFETY: + // * The caller guarantees that all elements of the array are initialized, + // * `MaybeUninit` and T are guaranteed to have the same layout, + // Therefore the conversion is safe + unsafe { + intrinsics::assert_inhabited::(); + + let array = ArrayInit { + maybe_uninit: ManuallyDrop::new(array), + }; + ManuallyDrop::into_inner(array.init) + } + } + /// Assuming all the elements are initialized, get a slice to them. /// /// # Safety From 0ff1e6c697f711aa25b8fa2c0cc43bf2ad84ff52 Mon Sep 17 00:00:00 2001 From: CoffeeBlend Date: Fri, 1 Jan 2021 22:12:49 +0100 Subject: [PATCH 2/6] Add test for MaybeUninit::array_assume_init --- library/core/tests/lib.rs | 2 ++ library/core/tests/mem.rs | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index e01aaa4cbf179..bc737cd1927cf 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 79ca2bba40388..547f6a2c78cc9 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -140,6 +140,22 @@ fn assume_init_good() { assert!(TRUE); } +#[test] +fn uninit_array_assume_init() { + let mut array: [MaybeUninit; 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]; From 72a3dee16f6c854fc61d475581b4730189984fa5 Mon Sep 17 00:00:00 2001 From: CoffeeBlend Date: Fri, 1 Jan 2021 22:56:54 +0100 Subject: [PATCH 3/6] Format code --- library/core/src/mem/maybe_uninit.rs | 18 ++++++++---------- library/core/tests/mem.rs | 6 ++---- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index b157eec24b410..a39f93466377a 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -804,12 +804,12 @@ impl MaybeUninit { } } - /// Extracts the values from an array of `MaybeUninit` containers. - /// + /// 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. + /// in an initialized state. /// /// # Examples /// @@ -817,17 +817,17 @@ impl MaybeUninit { /// #![feature(maybe_uninit_uninit_array)] /// #![feature(maybe_uninit_array_assume_init)] /// use std::mem::MaybeUninit; - /// + /// /// let mut array: [MaybeUninit; 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 = "none")] @@ -846,9 +846,7 @@ impl MaybeUninit { unsafe { intrinsics::assert_inhabited::(); - let array = ArrayInit { - maybe_uninit: ManuallyDrop::new(array), - }; + let array = ArrayInit { maybe_uninit: ManuallyDrop::new(array) }; ManuallyDrop::into_inner(array.init) } } diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 547f6a2c78cc9..2279a16429f98 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -149,10 +149,8 @@ fn uninit_array_assume_init() { array[3].write(1); array[4].write(5); - let array = unsafe { - MaybeUninit::array_assume_init(array) - }; - + let array = unsafe { MaybeUninit::array_assume_init(array) }; + assert_eq!(array, [3, 1, 4, 1, 5]); } From dec8c033a3d3287cdb9e0b9f4888b21bbb86d60c Mon Sep 17 00:00:00 2001 From: CoffeeBlend Date: Mon, 11 Jan 2021 10:07:29 +0100 Subject: [PATCH 4/6] Add tracking issue for array_assume_init --- library/core/src/mem/maybe_uninit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index a39f93466377a..3d96ad32a1277 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -830,7 +830,7 @@ impl MaybeUninit { /// /// assert_eq!(array, [0, 1, 2]); /// ``` - #[unstable(feature = "maybe_uninit_array_assume_init", issue = "none")] + #[unstable(feature = "maybe_uninit_array_assume_init", issue = "80908")] #[inline(always)] pub unsafe fn array_assume_init(array: [Self; N]) -> [T; N] { // Convert using a union because mem::transmute does not support const_generics From 5d65b7e055f469ee5bcc733860c6ebe37649bfa5 Mon Sep 17 00:00:00 2001 From: CoffeeBlend Date: Mon, 11 Jan 2021 23:32:03 +0100 Subject: [PATCH 5/6] Simplify array_assume_init --- library/core/src/mem/maybe_uninit.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 3d96ad32a1277..b186aa61eb0eb 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -833,21 +833,14 @@ impl MaybeUninit { #[unstable(feature = "maybe_uninit_array_assume_init", issue = "80908")] #[inline(always)] pub unsafe fn array_assume_init(array: [Self; N]) -> [T; N] { - // Convert using a union because mem::transmute does not support const_generics - union ArrayInit { - maybe_uninit: ManuallyDrop<[MaybeUninit; N]>, - init: ManuallyDrop<[T; N]>, - } - // SAFETY: - // * The caller guarantees that all elements of the array are initialized, - // * `MaybeUninit` and T are guaranteed to have the same layout, - // Therefore the conversion is safe + // * The caller guarantees that all elements of the array are initialized + // * `MaybeUninit` 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::(); - - let array = ArrayInit { maybe_uninit: ManuallyDrop::new(array) }; - ManuallyDrop::into_inner(array.init) + (&array as *const _ as *const T).read() } } From 985071b08f5c03e4f18d43c15f3ea82395588a5e Mon Sep 17 00:00:00 2001 From: CoffeeBlend Date: Tue, 12 Jan 2021 01:39:10 +0100 Subject: [PATCH 6/6] Fix implementation --- library/core/src/mem/maybe_uninit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index b186aa61eb0eb..fda0553f94c5f 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -840,7 +840,7 @@ impl MaybeUninit { // And thus the conversion is safe unsafe { intrinsics::assert_inhabited::(); - (&array as *const _ as *const T).read() + (&array as *const _ as *const [T; N]).read() } }