project_uninit/
lib.rs

1//! Macros for safe (and unsafe) access to and initialization of fields of structs wrapped in `MaybeUninit<_>`
2//! This crate uses the
3//! [`ptr::addr_of!`](core::ptr::addr_of)
4//! and [`ptr::addr_of_mut!`](core::ptr::addr_of_mut)
5//! macros introduced in Rust 1.51 to avoid undefined behavior.
6//!
7//!
8//! ## Examples
9//! ### Initialize a struct one field at a time
10//! ```
11//! use core::mem::MaybeUninit;
12//! use project_uninit::partial_init;
13//! #[derive(PartialEq, Eq, Debug)]
14//! struct Inner { value1: u8, value2: (i32, bool) }
15//! #[derive(PartialEq, Eq, Debug)]
16//! struct MyStruct { name: &'static str, inner: Inner }
17//!
18//! let mut target = MaybeUninit::<MyStruct>::uninit();
19//!
20//! let name: &mut &str = partial_init!(target => name = "Foo");
21//! assert_eq!(*name, "Foo");
22//! *name = "Bar";
23//!
24//! let (value1, value2_0): (&mut u8, &mut i32) = partial_init!(target => {
25//!     inner => value1: 0xff,
26//!     inner => value2 => 0: 1000,
27//! });
28//! assert_eq!(*value1, 0xff);
29//! assert_eq!(*value2_0, 1000);
30//! *value2_0 *= 2;
31//!
32//! let value2_1: &mut bool = partial_init!(target => inner => value2 => 1 = true);
33//! assert_eq!(*value2_1, true);
34//!
35//! assert_eq!(unsafe { target.assume_init() }, MyStruct {
36//!     name: "Bar",
37//!     inner: Inner { value1: 0xff, value2: (2000, true) },
38//! });
39//! ```
40//!
41//! ### Obtain references to fields of a `MaybeUninit<_>` struct
42//! ```
43//! # use core::mem::MaybeUninit;
44//! use project_uninit::project_uninit;
45//!
46//! #[derive(PartialEq, Eq, Debug)]
47//! struct Person { name: &'static str, age: u32 }
48//! let person = MaybeUninit::new(Person {
49//!     name: "Alice",
50//!     age: 22,
51//! });
52//! let (name, age): (&MaybeUninit<&str>, &MaybeUninit<u32>) = project_uninit!(
53//!     person => { name, age }
54//! );
55//!
56//! assert_eq!(unsafe { name.assume_init() }, "Alice");
57//! assert_eq!(unsafe { age.assume_init() }, 22);
58//!
59//! ```
60//!
61//! ### Obtain mutable references to fields of a `MaybeUninit<_>` struct
62//! ```
63//! # use core::mem::MaybeUninit;
64//! # #[derive(PartialEq, Eq, Debug)]
65//! # struct Person { name: &'static str, age: u32 }
66//! use project_uninit::project_uninit_mut;
67//!
68//! let mut person = MaybeUninit::new(Person {
69//!     name: "Alice",
70//!     age: 22,
71//! });
72//!
73//! let (name, age): (&mut MaybeUninit<&str>, &mut MaybeUninit<u32>) = project_uninit_mut!(
74//!     person => { name, age }
75//! );
76//!
77//! *name = MaybeUninit::new("Alicia");
78//! *age = MaybeUninit::new(24);
79//!
80//! assert_eq!(unsafe { person.assume_init() }, Person {
81//!     name: "Alicia",
82//!     age: 24,
83//! });
84//! ```
85//! ## Safety
86//!
87//! It's safe to mutably project multiple fields as long as they are distinct.
88//! For example, the following snippets do not compile:
89//!
90//! ```compile_fail
91//! # use core::mem::MaybeUninit;
92//! # #[derive(PartialEq, Eq, Debug)]
93//! # struct Person { name: &'static str, age: u32 }
94//! # use project_uninit::partial_init;
95//! let mut person = MaybeUninit::<Person>::uninit();
96//! let (name1, name2) = partial_init!(person => { name: "Bob", name: "Robert" });
97//! ```
98//!
99//! ```compile_fail
100//! # use core::mem::MaybeUninit;
101//! # #[derive(PartialEq, Eq, Debug)]
102//! # struct Person { name: &'static str, age: u32 }
103//! # use project_uninit::project_uninit_mut;
104//! let mut person = MaybeUninit::<Person>::uninit();
105//! let (name1, name2) = project_uninit_mut!(person => { name, name });
106//! ```
107//!
108//! ```compile_fail,E0499
109//! # use core::mem::MaybeUninit;
110//! # #[derive(PartialEq, Eq, Debug)]
111//! # struct Person { name: &'static str, age: u32 }
112//! # use project_uninit::project_uninit_mut;
113//! let mut person = MaybeUninit::<Person>::uninit();
114//! let name1 = project_uninit_mut!(person => name);
115//! let name2 = project_uninit_mut!(person => name);
116//! drop(name1);
117//! ```
118//!
119//! Additionally, lifetime rules are enforced just like any other borrow.
120//! The following will not compile:
121//! ```compile_fail,E0597
122//! # use core::mem::MaybeUninit;
123//! # #[derive(PartialEq, Eq, Debug)]
124//! # struct Person { name: &'static str, age: u32 }
125//! # use project_uninit::project_uninit;
126//! let age: &MaybeUninit<u32>;
127//! {
128//!     let person = MaybeUninit::<Person>::uninit();
129//!     age = project_uninit!(person => age);
130//! } // person is dropped while still borrowed by age
131//! drop(age);
132//! ```
133//!
134//! However, this will:
135//! ```
136//! # use core::mem::MaybeUninit;
137//! # #[derive(PartialEq, Eq, Debug)]
138//! # struct Person { name: &'static str, age: u32 }
139//! # use project_uninit::project_uninit;
140//! fn get_uninit_age<'a>(person: &'a MaybeUninit<Person>) -> &'a MaybeUninit<u32> {
141//!     project_uninit!(person => age)
142//! }
143//! ```
144#![no_std]
145
146mod assert_unique;
147mod partial_init;
148mod project;
149#[doc(hidden)]
150pub mod utils;