Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add slice::align_to_uninit_mut #139072

Merged
merged 1 commit into from
Apr 6, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 51 additions & 2 deletions library/core/src/slice/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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]`.
///
Expand Down
Loading