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}