1
Fork 0

Add slice::align_to_uninit_mut

This commit is contained in:
Nikolai Kuklin 2025-03-28 18:12:18 +01:00
parent 2a06022951
commit ed35b9be28
No known key found for this signature in database

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;
@ -4589,7 +4589,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
@ -4774,6 +4774,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]`.
///