Rollup merge of #139072 - nickkuk:align_to_uninit_mut, r=Mark-Simulacrum

Add `slice::align_to_uninit_mut`

Add new `slice::align_to_uninit_mut` method.

Tracking issue: https://github.com/rust-lang/rust/issues/139062

ACP: https://github.com/rust-lang/libs-team/issues/564
This commit is contained in:
Guillaume Gomez 2025-04-06 18:08:10 +02:00 committed by GitHub
commit d1da78b201
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -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;
@ -4579,7 +4579,7 @@ impl<T> [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
@ -4764,6 +4764,55 @@ impl<T> [T] {
}
}
impl<T> [MaybeUninit<T>] {
/// 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<u8>],
/// }
///
/// impl<'scope> BumpAllocator<'scope> {
/// pub fn new(memory: &'scope mut [MaybeUninit<u8>]) -> Self {
/// Self { memory }
/// }
/// pub fn try_alloc_uninit<T>(&mut self) -> Option<&'scope mut MaybeUninit<T>> {
/// let first_end = self.memory.as_ptr().align_offset(align_of::<T>()) + size_of::<T>();
/// let prefix = self.memory.split_off_mut(..first_end)?;
/// Some(&mut prefix.align_to_uninit_mut::<T>().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::<u8>::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<U>(&mut self) -> (&mut Self, &mut [MaybeUninit<U>], &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, const N: usize> [[T; N]] {
/// Takes a `&[[T; N]]`, and flattens it to a `&[T]`.
///