project_uninit/
partial_init.rs

1/// Partially initialize a struct wrapped in `MaybeUninit`.
2///
3/// The specified fields will be updated with the given values, and mutable references to those
4/// fields will be returned.
5/// This statically ensures that the same field is not set mutltiple times in the same macro call,
6/// and that multiple references to the same value are not returned.
7///
8/// This must be used in an `unsafe` block or function when accessing fields of unions.
9///
10/// ## Syntax
11/// ```
12/// # use core::mem::MaybeUninit;
13/// # use project_uninit::partial_init;
14/// # #[derive(PartialEq, Eq, Debug)]
15/// # struct Person { name: Name, age: u32, id: (usize, usize) }
16/// # #[derive(PartialEq, Eq, Debug)]
17/// # struct Name { first: &'static str, last: &'static str }
18/// # let mut bob = MaybeUninit::new(Person {
19/// #     name: Name { first: "Bob1", last: "Jones1" },
20/// #     age: 34, id: (111, 222),
21/// # });
22/// // Initialize a single field:
23/// let age: &mut u32 = partial_init!(bob => age = 35);
24/// assert_eq!(*age, 35);
25///
26/// // Initialize multiple fields:
27/// let (age, id) = partial_init!(bob => {
28///     age: 36,
29///     id: (111, 222),
30/// });
31/// assert_eq!(*age, 36);
32/// assert_eq!(*id, (111, 222));
33///
34/// // Initialize fields of fields:
35/// let first: &mut &'static str = partial_init!(bob => name => first = "Bob");
36/// assert_eq!(*first, "Bob");
37///
38/// // Initialize fields of tuples (also works for tuple structs):
39/// let id0: &mut usize = partial_init!(bob => id => 0 = 444);
40/// assert_eq!(*id0, 444);
41///
42/// // Initialize multiple fields, including nested fields:
43/// let (last, age, id1) = partial_init!(bob => {
44///     name => last: "Jones",
45///     age: 37,
46///     id => 1: 888,
47/// });
48///
49/// assert_eq!(*last, "Jones");
50/// assert_eq!(*age, 37);
51/// assert_eq!(*id1, 888);
52/// ```
53///
54///
55/// ## Example
56/// ```
57/// use core::mem::MaybeUninit;
58/// use project_uninit::partial_init;
59///
60/// #[derive(PartialEq, Eq, Debug)]
61/// struct Person { name: Name, age: u32, id: (usize, usize) }
62/// #[derive(PartialEq, Eq, Debug)]
63/// struct Name { first: &'static str, last: &'static str }
64///
65/// let mut alice = MaybeUninit::<Person>::uninit();
66///
67/// let age = partial_init!(alice => age = 20);
68/// assert_eq!(*age, 20);
69/// *age = 22;
70///
71/// let (first, last, id) = partial_init!(alice => {
72///     name => first: "Alice",
73///     name => last: "Smith",
74///     id: (123, 456),
75/// });
76/// assert_eq!(*first, "Alice");
77/// assert_eq!(*last, "Smith");
78/// assert_eq!(*id, (123, 456));
79///
80/// partial_init!(alice => id => 1 = 789);
81///
82/// assert_eq!(unsafe { alice.assume_init() }, Person {
83///     name: Name { first: "Alice", last: "Smith" },
84///     age: 22,
85///     id: (123, 789),
86/// });
87/// ```
88#[macro_export]
89macro_rules! partial_init {
90    // intialize multiple fields
91    ($expr:expr => {$($($props:tt)=>+ : $val:expr),* $(,)?}) => {{
92        // generate an error message if a field is used more than once
93        $crate::__assert_unique!($expr, [ $( [ $($props).+ ] )* ]);
94        #[allow(unused_imports)]
95        use ::core::borrow::BorrowMut;
96        let _ref: &mut ::core::mem::MaybeUninit<_> = $expr.borrow_mut();
97        let ptr = _ref.as_mut_ptr();
98        let lt = $crate::utils::bind_mut_lt(_ref);
99
100        if false {
101            // this will never be executed
102            // it's only to assert that it is safe to access the fields
103            #[allow(unused_unsafe)]
104            let _x = unsafe { &mut *ptr };
105            let _y = ($(&mut _x.$($props).+,)*);
106        }
107        ($({
108            let prop_ref;
109            #[allow(unused_unsafe)]
110            unsafe {
111                let prop_ptr = ::core::ptr::addr_of_mut!((*ptr).$($props).+);
112                ::core::ptr::write(prop_ptr, $val);
113                prop_ref = $crate::utils::deref_ptr_with_lt(prop_ptr, lt);
114            }
115            prop_ref
116        },)*)
117    }};
118
119    // initialize a single field
120    ($expr:expr => $($props:tt)=>+ = $val:expr) => {
121        $crate::partial_init!($expr => { $($props)=>+: $val }).0
122    };
123}
124
125///```compile_fail
126/// use project_uninit::partial_init;
127/// use core::mem::MaybeUninit;
128/// struct Foo { a: i32, b: u32 }
129/// let mut x = MaybeUninit::<Foo>::uninit();
130/// let _ = partial_init!(x => { a: 1, b: 6, a: -1 });
131///```
132fn _test_multiple_per_macro_call_fails() {}
133
134///```compile_fail
135/// use project_uninit::{partial_init, project_uninit};
136/// use core::mem::MaybeUninit;
137/// struct Foo { a: i32, b: u32 }
138/// let mut x = MaybeUninit::<Foo>::uninit();
139/// let a = project_uninit!(x => a);
140/// partial_init!(x => { b: 6 });
141/// let a1 = a;
142///```
143fn _partial_init_with_existing_field_borrow_fails() {}
144
145///```compile_fail
146/// use project_uninit::{partial_init, project_uninit_mut};
147/// use core::mem::MaybeUninit;
148/// struct Foo { a: i32, b: u32 }
149/// let mut x = MaybeUninit::<Foo>::uninit();
150/// let a = project_uninit_mut!(x => a);
151/// *a = MaybeUninit::new(1);
152/// partial_init!(x => { b: 6 });
153/// *a = MaybeUninit::new(3);
154///```
155fn _partial_init_with_existing_mut_field_borrow_fails() {}