Skip to content
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