diff options
| author | Guillaume Gomez <guillaume1.gomez@gmail.com> | 2025-04-06 18:08:10 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-04-06 18:08:10 +0200 |
| commit | d1da78b2011e95dc6289bacf99f4804b540c584e (patch) | |
| tree | bdd6f89d1379efee4c69ec798dbee9bd00cf01bb /library/core/src | |
| parent | 962fa98eeb7da843d0f2dc4d2f3ac0a27ed267b2 (diff) | |
| parent | ed35b9be289ba91771d218bd9debc8e30ecd8d83 (diff) | |
| download | rust-d1da78b2011e95dc6289bacf99f4804b540c584e.tar.gz rust-d1da78b2011e95dc6289bacf99f4804b540c584e.zip | |
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
Diffstat (limited to 'library/core/src')
| -rw-r--r-- | library/core/src/slice/mod.rs | 53 |
1 files changed, 51 insertions, 2 deletions
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index e54840c8fcc..c7e8d5f989d 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; @@ -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]`. /// |
