binius_utils/mem.rs
1// Copyright 2025 Irreducible Inc.
2
3use std::mem::MaybeUninit;
4
5/// Turn a given slice of `T` into a slice of `MaybeUninit<T>`.
6///
7/// # Panics
8///
9/// This function is going to panic in case `T` has a destructor.
10pub fn slice_uninit_mut<T>(slice: &mut [T]) -> &mut [MaybeUninit<T>] {
11 assert!(!std::mem::needs_drop::<T>());
12 unsafe {
13 // SAFETY:
14 //
15 // The `slice` is a valid mutable reference, so:
16 // - Its pointer is non-null and properly aligned
17 // - It points to `len` consecutive properly initialized values of type T
18 // - The memory region is valid for reads and writes
19 // - The memory belongs to a single allocated object
20 // - The total size is no larger than isize::MAX and doesn't wrap around the address space
21 //
22 // By casting the pointer to `*mut MaybeUninit<T>`, we're essentially forgetting that
23 // the values are initialized. This is safe because:
24 // 1. We've asserted that T doesn't have a destructor, so no cleanup is needed,
25 // 2. `MaybeUninit<T>` has the same memory layout as T,
26 // 3. We maintain the same length.
27 //
28 // The returned slice takes over the lifetime of the input slice making the lifetime
29 // correct.
30 std::slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut MaybeUninit<T>, slice.len())
31 }
32}
33
34/// This can be removed when MaybeUninit::slice_assume_init_mut is stabilized
35/// <https://github.com/rust-lang/rust/issues/63569>
36///
37/// # Safety
38///
39/// It is up to the caller to guarantee that the `MaybeUninit<T>` elements
40/// really are in an initialized state.
41/// Calling this when the content is not yet fully initialized causes undefined behavior.
42///
43/// See [`assume_init_mut`] for more details and examples.
44///
45/// [`assume_init_mut`]: MaybeUninit::assume_init_mut
46pub const unsafe fn slice_assume_init_mut<T>(slice: &mut [MaybeUninit<T>]) -> &mut [T] {
47 unsafe { std::mem::transmute(slice) }
48}
49
50/// This can be removed when MaybeUninit::slice_assume_init_ref is stabilized
51/// <https://github.com/rust-lang/rust/issues/63569>
52///
53/// # Safety
54///
55/// It is up to the caller to guarantee that the `MaybeUninit<T>` elements
56/// really are in an initialized state.
57/// Calling this when the content is not yet fully initialized causes undefined behavior.
58///
59/// See [`assume_init_ref`] for more details and examples.
60///
61/// [`assume_init_ref`]: MaybeUninit::assume_init_ref
62pub const unsafe fn slice_assume_init_ref<T>(slice: &[MaybeUninit<T>]) -> &[T] {
63 unsafe { std::mem::transmute(slice) }
64}