Expand description
Macros for safe (and unsafe) access to and initialization of fields of structs wrapped in MaybeUninit<_>
This crate uses the
ptr::addr_of!
and ptr::addr_of_mut!
macros introduced in Rust 1.51 to avoid undefined behavior.
§Examples
§Initialize a struct one field at a time
use core::mem::MaybeUninit;
use project_uninit::partial_init;
#[derive(PartialEq, Eq, Debug)]
struct Inner { value1: u8, value2: (i32, bool) }
#[derive(PartialEq, Eq, Debug)]
struct MyStruct { name: &'static str, inner: Inner }
let mut target = MaybeUninit::<MyStruct>::uninit();
let name: &mut &str = partial_init!(target => name = "Foo");
assert_eq!(*name, "Foo");
*name = "Bar";
let (value1, value2_0): (&mut u8, &mut i32) = partial_init!(target => {
inner => value1: 0xff,
inner => value2 => 0: 1000,
});
assert_eq!(*value1, 0xff);
assert_eq!(*value2_0, 1000);
*value2_0 *= 2;
let value2_1: &mut bool = partial_init!(target => inner => value2 => 1 = true);
assert_eq!(*value2_1, true);
assert_eq!(unsafe { target.assume_init() }, MyStruct {
name: "Bar",
inner: Inner { value1: 0xff, value2: (2000, true) },
});
§Obtain references to fields of a MaybeUninit<_>
struct
use project_uninit::project_uninit;
#[derive(PartialEq, Eq, Debug)]
struct Person { name: &'static str, age: u32 }
let person = MaybeUninit::new(Person {
name: "Alice",
age: 22,
});
let (name, age): (&MaybeUninit<&str>, &MaybeUninit<u32>) = project_uninit!(
person => { name, age }
);
assert_eq!(unsafe { name.assume_init() }, "Alice");
assert_eq!(unsafe { age.assume_init() }, 22);
§Obtain mutable references to fields of a MaybeUninit<_>
struct
use project_uninit::project_uninit_mut;
let mut person = MaybeUninit::new(Person {
name: "Alice",
age: 22,
});
let (name, age): (&mut MaybeUninit<&str>, &mut MaybeUninit<u32>) = project_uninit_mut!(
person => { name, age }
);
*name = MaybeUninit::new("Alicia");
*age = MaybeUninit::new(24);
assert_eq!(unsafe { person.assume_init() }, Person {
name: "Alicia",
age: 24,
});
§Safety
It’s safe to mutably project multiple fields as long as they are distinct. For example, the following snippets do not compile:
ⓘ
let mut person = MaybeUninit::<Person>::uninit();
let (name1, name2) = partial_init!(person => { name: "Bob", name: "Robert" });
ⓘ
let mut person = MaybeUninit::<Person>::uninit();
let (name1, name2) = project_uninit_mut!(person => { name, name });
ⓘ
let mut person = MaybeUninit::<Person>::uninit();
let name1 = project_uninit_mut!(person => name);
let name2 = project_uninit_mut!(person => name);
drop(name1);
Additionally, lifetime rules are enforced just like any other borrow. The following will not compile:
ⓘ
let age: &MaybeUninit<u32>;
{
let person = MaybeUninit::<Person>::uninit();
age = project_uninit!(person => age);
} // person is dropped while still borrowed by age
drop(age);
However, this will:
fn get_uninit_age<'a>(person: &'a MaybeUninit<Person>) -> &'a MaybeUninit<u32> {
project_uninit!(person => age)
}
Macros§
- partial_
init - Partially initialize a struct wrapped in
MaybeUninit
. - project_
ptr - Unsafe: Given a
*const
pointer to a struct, obtain*const
pointers to one or more of its fields. - project_
ptr_ mut - Unsafe: Given a
*mut
pointer to a struct, obtain*mut
pointers to one or more of its fields. - project_
uninit - Obtain
&MaybeUninit<_>
references to fields of a struct wrapped inMaybeUninit<_>
. - project_
uninit_ mut - Obtain
&mut MaybeUninit<_>
references to fields of a struct wrapped inMaybeUninit<_>
.