diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 5bb7243c4491b..058515efdfd74 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -8,7 +8,7 @@ use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::intrinsics::{exact_div, unchecked_sub}; -use crate::mem::{self, SizedTypeProperties}; +use crate::mem::{self, MaybeUninit, SizedTypeProperties}; use crate::num::NonZero; use crate::ops::{OneSidedRange, OneSidedRangeBound, Range, RangeBounds, RangeInclusive}; use crate::panic::const_panic; @@ -4589,7 +4589,7 @@ impl [T] { // or generate worse code otherwise. This is also why we need to go // through a raw pointer here. let slice: *mut [T] = self; - let mut arr: mem::MaybeUninit<[&mut I::Output; N]> = mem::MaybeUninit::uninit(); + let mut arr: MaybeUninit<[&mut I::Output; N]> = MaybeUninit::uninit(); let arr_ptr = arr.as_mut_ptr(); // SAFETY: We expect `indices` to contain disjunct values that are @@ -4774,6 +4774,55 @@ impl [T] { } } +impl [MaybeUninit] { + /// Transmutes the mutable uninitialized slice to a mutable uninitialized slice of + /// another type, ensuring alignment of the types is maintained. + /// + /// This is a safe wrapper around [`slice::align_to_mut`], so inherits the same + /// guarantees as that method. + /// + /// # Examples + /// + /// ``` + /// #![feature(align_to_uninit_mut)] + /// use std::mem::MaybeUninit; + /// + /// pub struct BumpAllocator<'scope> { + /// memory: &'scope mut [MaybeUninit], + /// } + /// + /// impl<'scope> BumpAllocator<'scope> { + /// pub fn new(memory: &'scope mut [MaybeUninit]) -> Self { + /// Self { memory } + /// } + /// pub fn try_alloc_uninit(&mut self) -> Option<&'scope mut MaybeUninit> { + /// let first_end = self.memory.as_ptr().align_offset(align_of::()) + size_of::(); + /// let prefix = self.memory.split_off_mut(..first_end)?; + /// Some(&mut prefix.align_to_uninit_mut::().1[0]) + /// } + /// pub fn try_alloc_u32(&mut self, value: u32) -> Option<&'scope mut u32> { + /// let uninit = self.try_alloc_uninit()?; + /// Some(uninit.write(value)) + /// } + /// } + /// + /// let mut memory = [MaybeUninit::::uninit(); 10]; + /// let mut allocator = BumpAllocator::new(&mut memory); + /// let v = allocator.try_alloc_u32(42); + /// assert_eq!(v, Some(&mut 42)); + /// ``` + #[unstable(feature = "align_to_uninit_mut", issue = "139062")] + #[inline] + #[must_use] + pub fn align_to_uninit_mut(&mut self) -> (&mut Self, &mut [MaybeUninit], &mut Self) { + // SAFETY: `MaybeUninit` is transparent. Correct size and alignment are guaranteed by + // `align_to_mut` itself. Therefore the only thing that we have to ensure for a safe + // `transmute` is that the values are valid for the types involved. But for `MaybeUninit` + // any values are valid, so this operation is safe. + unsafe { self.align_to_mut() } + } +} + impl [[T; N]] { /// Takes a `&[[T; N]]`, and flattens it to a `&[T]`. ///