Skip to content

Commit a3a790d

Browse files
committed
What if we just add <[MaybeUninit<T>; N]>::assume_init directly?
1 parent 101e182 commit a3a790d

File tree

6 files changed

+54
-9
lines changed

6 files changed

+54
-9
lines changed

library/alloc/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
#![feature(allocator_api)]
9393
#![feature(array_chunks)]
9494
#![feature(array_into_iter_constructors)]
95+
#![feature(array_maybe_uninit_assume_init)]
9596
#![feature(array_methods)]
9697
#![feature(array_windows)]
9798
#![feature(assert_matches)]
@@ -127,7 +128,6 @@
127128
#![feature(layout_for_ptr)]
128129
#![feature(maybe_uninit_slice)]
129130
#![feature(maybe_uninit_uninit_array)]
130-
#![feature(maybe_uninit_uninit_array_transpose)]
131131
#![cfg_attr(test, feature(new_uninit))]
132132
#![feature(nonnull_slice_from_raw_parts)]
133133
#![feature(pattern)]

library/alloc/src/vec/into_iter.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
223223

224224
self.ptr = self.ptr.wrapping_byte_add(N);
225225
// Safety: ditto
226-
return Ok(unsafe { raw_ary.transpose().assume_init() });
226+
return Ok(unsafe { raw_ary.assume_init() });
227227
}
228228

229229
if len < N {
@@ -241,7 +241,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
241241
return unsafe {
242242
ptr::copy_nonoverlapping(self.ptr, raw_ary.as_mut_ptr() as *mut T, N);
243243
self.ptr = self.ptr.add(N);
244-
Ok(raw_ary.transpose().assume_init())
244+
Ok(raw_ary.assume_init())
245245
};
246246
}
247247

library/core/src/array/iter.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ impl<T, const N: usize> IntoIter<T, N> {
104104
///
105105
/// ```
106106
/// #![feature(array_into_iter_constructors)]
107-
/// #![feature(maybe_uninit_uninit_array_transpose)]
107+
/// #![feature(array_maybe_uninit_assume_init)]
108108
/// #![feature(maybe_uninit_uninit_array)]
109109
/// use std::array::IntoIter;
110110
/// use std::mem::MaybeUninit;
@@ -133,7 +133,7 @@ impl<T, const N: usize> IntoIter<T, N> {
133133
/// }
134134
///
135135
/// // SAFETY: We've initialized all N items
136-
/// unsafe { Ok(buffer.transpose().assume_init()) }
136+
/// unsafe { Ok(buffer.assume_init()) }
137137
/// }
138138
///
139139
/// let r: [_; 4] = next_chunk(&mut (10..16)).unwrap();

library/core/src/array/mod.rs

+46-1
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,51 @@ impl<T, const N: usize> [T; N] {
799799
}
800800
}
801801

802+
impl<T, const N: usize> [MaybeUninit<T>; N] {
803+
/// Extracts the values from an array of [`MaybeUninit<T>`] containers.
804+
///
805+
/// This is essentially `.map(MaybeUninit::assume_init)`, but in a way
806+
/// that's *much* clearer to the optimizer how to do efficiently.
807+
///
808+
/// # Safety
809+
///
810+
/// It is up to the caller to guarantee that all elements of the array are
811+
/// in an initialized state.
812+
///
813+
/// # Examples
814+
///
815+
/// ```
816+
/// #![feature(inline_const)]
817+
/// #![feature(array_maybe_uninit_assume_init)]
818+
/// use std::mem::MaybeUninit;
819+
///
820+
/// let mut array = [const { MaybeUninit::<i32>::uninit() }; 3];
821+
/// array[0].write(0);
822+
/// array[1].write(1);
823+
/// array[2].write(2);
824+
///
825+
/// // SAFETY: we initialised all three elements
826+
/// let array = unsafe { array.assume_init() };
827+
///
828+
/// assert_eq!(array, [0, 1, 2]);
829+
/// ```
830+
#[unstable(feature = "array_maybe_uninit_assume_init", issue = "96097")]
831+
#[rustc_const_unstable(feature = "const_array_maybe_uninit_assume_init", issue = "96097")]
832+
#[inline(always)]
833+
#[track_caller]
834+
pub const unsafe fn assume_init(self) -> [T; N] {
835+
// SAFETY:
836+
// * The caller guarantees that all elements of the array are initialized
837+
// * `MaybeUninit<T>` and T are guaranteed to have the same layout
838+
// * `MaybeUninit` does not drop, so there are no double-frees
839+
// And thus the conversion is safe
840+
unsafe {
841+
crate::intrinsics::assert_inhabited::<[T; N]>();
842+
mem::transmute_copy(&mem::ManuallyDrop::new(self))
843+
}
844+
}
845+
}
846+
802847
/// Pulls `N` items from `iter` and returns them as an array. If the iterator
803848
/// yields fewer than `N` items, this function exhibits undefined behavior.
804849
///
@@ -896,7 +941,7 @@ where
896941

897942
mem::forget(guard);
898943
// SAFETY: All elements of the array were populated in the loop above.
899-
let output = unsafe { array.transpose().assume_init() };
944+
let output = unsafe { array.assume_init() };
900945
Ok(Try::from_output(output))
901946
}
902947

library/core/tests/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#![feature(alloc_layout_extra)]
22
#![feature(array_chunks)]
3+
#![feature(array_maybe_uninit_assume_init)]
34
#![feature(array_methods)]
45
#![feature(array_windows)]
56
#![feature(bigint_helper_methods)]
@@ -53,7 +54,6 @@
5354
#![feature(split_as_slice)]
5455
#![feature(maybe_uninit_uninit_array)]
5556
#![feature(maybe_uninit_write_slice)]
56-
#![feature(maybe_uninit_uninit_array_transpose)]
5757
#![feature(min_specialization)]
5858
#![feature(numfmt)]
5959
#![feature(step_trait)]

library/core/tests/mem.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -194,11 +194,11 @@ fn uninit_array_assume_init() {
194194
array[3].write(1);
195195
array[4].write(5);
196196

197-
let array = unsafe { array.transpose().assume_init() };
197+
let array = unsafe { array.assume_init() };
198198

199199
assert_eq!(array, [3, 1, 4, 1, 5]);
200200

201-
let [] = unsafe { [MaybeUninit::<!>::uninit(); 0].transpose().assume_init() };
201+
let [] = unsafe { [MaybeUninit::<!>::uninit(); 0].assume_init() };
202202
}
203203

204204
#[test]

0 commit comments

Comments
 (0)