project_uninit/
project.rs

1/// Obtain `&MaybeUninit<_>` references to fields of a struct wrapped in `MaybeUninit<_>`.
2///
3/// This must be used in an `unsafe` block or function when accessing fields of unions.
4///
5/// ## Syntax
6/// ```
7/// # use core::mem::MaybeUninit;
8/// # use project_uninit::project_uninit;
9/// # #[derive(PartialEq, Eq, Debug)]
10/// # struct Person { name: Name, age: u32, id: (usize, usize) }
11/// # #[derive(PartialEq, Eq, Debug)]
12/// # struct Name { first: &'static str, last: &'static str }
13/// # let mut bob = MaybeUninit::new(Person {
14/// #     name: Name { first: "Bob1", last: "Jones1" },
15/// #     age: 34, id: (111, 222),
16/// # });
17/// // Access a single field:
18/// let age: &MaybeUninit<u32> = project_uninit!(bob => age);
19///
20/// // Access multiple fields:
21/// let (age, id): (&MaybeUninit<_>, &MaybeUninit<_>) = project_uninit!(
22///     bob => { age, id }
23/// );
24///
25/// // Access fields of fields:
26/// let first: &MaybeUninit<&str> = project_uninit!(bob => name => first);
27///
28/// // Access fields of tuples (also works for tuple structs):
29/// let id0: &MaybeUninit<usize> = project_uninit!(bob => id => 0);
30///
31/// // Access multiple fields, including nested fields:
32/// let (first, last, age, id0, id1) = project_uninit!(bob => {
33///     name => first,
34///     name => last,
35///     age,
36///     id => 0,
37///     id => 1,
38/// });
39/// ```
40///
41/// # Example
42/// ```
43/// use core::mem::MaybeUninit;
44/// use project_uninit::project_uninit;
45///
46/// #[derive(PartialEq, Eq, Debug)]
47/// struct Person { name: Name, age: u32, id: (usize, usize) }
48/// #[derive(PartialEq, Eq, Debug)]
49/// struct Name { first: &'static str, last: &'static str }
50///
51/// let alice = MaybeUninit::new(Person {
52///     name: Name { first: "Alice", last: "Smith" },
53///     age: 22,
54///     id: (123, 456),
55/// });
56///
57/// let first = project_uninit!(alice => name => first);
58/// assert_eq!(unsafe { first.assume_init() }, "Alice");
59///
60/// let (last, age, id1) = project_uninit!(alice => {
61///     name => last,
62///     age,
63///     id => 1,
64/// });
65///
66/// assert_eq!(unsafe { last.assume_init() }, "Smith");
67/// assert_eq!(unsafe { age.assume_init() }, 22);
68/// assert_eq!(unsafe { id1.assume_init() }, 456);
69/// ```
70///
71#[macro_export]
72macro_rules! project_uninit {
73    // project mutliple fields
74    ($expr:expr => {$( $($props:tt)=>+ ),* $(,)?}) => {{
75        #[allow(unused_imports)]
76        use ::core::borrow::Borrow;
77        let _ref: &::core::mem::MaybeUninit<_> = $expr.borrow();
78        let ptr = ::core::mem::MaybeUninit::as_ptr(_ref);
79        let lt = $crate::utils::bind_ref_lt(_ref);
80
81        if false {
82            // this will never be executed
83            // it's only to assert that it is safe to access the fields
84            #[allow(unused_unsafe)]
85            let _x = unsafe { &*ptr };
86            let _y = ($(&_x.$($props).+,)*);
87        }
88
89        ($({
90            let ret;
91            #[allow(unused_unsafe)]
92            unsafe {
93                let prop_ptr = ::core::ptr::addr_of!((*ptr).$($props).+);
94                ret = $crate::utils::uninit_from_ptr(prop_ptr, lt);
95            }
96            ret
97        },)*)
98    }};
99
100    // project a single field
101    ($expr:expr => $($props:tt)=>+) => {
102        $crate::project_uninit!($expr => {$($props)=>+}).0
103    };
104}
105
106/// Obtain `&mut MaybeUninit<_>` references to fields of a struct wrapped in `MaybeUninit<_>`.
107///
108/// This statically ensures that multiple references to the same value are not returned.
109///
110/// This must be used in an `unsafe` block or function when accessing fields of unions.
111///
112/// ## Syntax
113/// ```
114/// # use core::mem::MaybeUninit;
115/// # use project_uninit::project_uninit_mut;
116/// # #[derive(PartialEq, Eq, Debug)]
117/// # struct Person { name: Name, age: u32, id: (usize, usize) }
118/// # #[derive(PartialEq, Eq, Debug)]
119/// # struct Name { first: &'static str, last: &'static str }
120/// # let mut bob = MaybeUninit::new(Person {
121/// #     name: Name { first: "Bob1", last: "Jones1" },
122/// #     age: 34, id: (111, 222),
123/// # });
124/// // Access a single field:
125/// let age: &mut MaybeUninit<u32> = project_uninit_mut!(bob => age);
126///
127/// // Access multiple fields:
128/// let (age, id): (&mut MaybeUninit<_>, &mut MaybeUninit<_>) = project_uninit_mut!(
129///     bob => { age, id }
130/// );
131///
132/// // Access fields of fields:
133/// let first: &mut MaybeUninit<&str> = project_uninit_mut!(bob => name => first);
134///
135/// // Access fields of tuples (also works for tuple structs):
136/// let id0: &mut MaybeUninit<usize> = project_uninit_mut!(bob => id => 0);
137///
138/// // Access multiple fields, including nested fields:
139/// let (first, last, age, id0, id1) = project_uninit_mut!(bob => {
140///     name => first,
141///     name => last,
142///     age,
143///     id => 0,
144///     id => 1,
145/// });
146/// ```
147///
148/// # Example
149/// ```
150/// use core::mem::MaybeUninit;
151/// use project_uninit::project_uninit_mut;
152///
153/// #[derive(PartialEq, Eq, Debug)]
154/// struct Person { name: Name, age: u32, id: (usize, usize) }
155/// #[derive(PartialEq, Eq, Debug)]
156/// struct Name { first: &'static str, last: &'static str }
157///
158/// let mut alice = MaybeUninit::<Person>::uninit();
159///
160/// let first = project_uninit_mut!(alice => name => first);
161/// *first = MaybeUninit::new("Alice");
162///
163/// let (last, age, id0, id1) = project_uninit_mut!(alice => {
164///     name => last,
165///     age,
166///     id => 0,
167///     id => 1,
168/// });
169///
170/// *last = MaybeUninit::new("Smith");
171/// *age = MaybeUninit::new(22);
172/// *id0 = MaybeUninit::new(123);
173/// *id1 = MaybeUninit::new(456);
174///
175/// assert_eq!(unsafe { alice.assume_init() }, Person {
176///     name: Name { first: "Alice", last: "Smith" },
177///     age: 22,
178///     id: (123, 456),
179/// });
180/// ```
181///
182#[macro_export]
183macro_rules! project_uninit_mut {
184    // project mutliple fields
185    ($expr:expr => {$( $($props:tt)=>+ ),* $(,)?}) => {{
186        // generate an error message if a field is used more than once
187        $crate::__assert_unique!($expr, [ $( [ $($props).+ ] )* ]);
188        #[allow(unused_imports)]
189        use ::core::borrow::BorrowMut;
190        let _ref: &mut ::core::mem::MaybeUninit<_> = $expr.borrow_mut();
191        let ptr = ::core::mem::MaybeUninit::as_mut_ptr(_ref);
192        let lt = $crate::utils::bind_mut_lt(_ref);
193
194        if false {
195            // this will never be executed
196            // it's only to assert that it is safe to access the fields
197            #[allow(unused_unsafe)]
198            let _x = unsafe { &mut *ptr };
199            let _y = ($(&mut _x.$($props).+,)*);
200        }
201        ($({
202            let ret;
203            #[allow(unused_unsafe)]
204            unsafe {
205                let prop_ptr = ::core::ptr::addr_of_mut!((*ptr).$($props).+);
206                ret = $crate::utils::uninit_from_mut_ptr(prop_ptr, lt);
207            }
208            ret
209        },)*)
210    }};
211
212    // project a single field
213    ($expr:expr => $($props:tt)=>+) => {
214        $crate::project_uninit_mut!($expr => {$($props)=>+}).0
215    };
216}
217
218/// **Unsafe:** Given a `*const` pointer to a struct, obtain `*const` pointers to one or more of its fields.
219///
220/// This does **not** statically check whether multiple pointers to the same data are returned.
221/// This must be used in an `unsafe` block or function.
222///
223/// ## Usage
224/// ```
225/// # use core::mem::MaybeUninit;
226/// # use project_uninit::project_ptr;
227/// # #[derive(PartialEq, Eq, Debug)]
228/// # struct Person { name: Name, age: u32, id: (usize, usize) }
229/// # #[derive(PartialEq, Eq, Debug)]
230/// # struct Name { first: &'static str, last: &'static str }
231///
232/// let bob = Person {
233///     name: Name { first: "Bob", last: "Jones" },
234///     age: 35,
235///     id: (111, 222),
236/// };
237/// let bob_ptr: *const Person = &bob;
238///
239/// unsafe {
240///     // Pointer to a single field:
241///     let age: *const u32 = project_ptr!(bob_ptr => age);
242///     assert_eq!(*age, 35);
243///
244///     // Pointers to multiple fields:
245///     let (first, name, id0): (*const &str, *const Name, *const usize) = project_ptr!(
246///         bob_ptr => { name => first, name, id => 0 }
247///     );
248///     assert_eq!(*first, "Bob");
249///     assert_eq!(*name, Name { first: "Bob", last: "Jones" });
250///     assert_eq!(*id0, 111);
251/// }
252///
253/// ```
254#[macro_export]
255macro_rules! project_ptr {
256    // project mutliple fields
257    ($expr:expr => {$( $($props:tt)=>+ ),* $(,)?}) => {{
258        let ptr: *const _ = $expr;
259        ($(
260            ::core::ptr::addr_of!((*ptr).$($props).+),
261        )*)
262    }};
263
264    // project a single field
265    ($expr:expr => $($props:tt)=>+) => {
266        $crate::project_ptr!($expr => {$($props)=>+}).0
267    };
268}
269
270/// **Unsafe:** Given a `*mut` pointer to a struct, obtain `*mut` pointers to one or more of its fields.
271///
272/// This does **not** statically check whether multiple pointers to the same data are returned.
273/// This must be used in an `unsafe` block or function.
274///
275/// ## Usage
276/// ```
277/// # use core::mem::MaybeUninit;
278/// # use project_uninit::project_ptr_mut;
279/// # #[derive(PartialEq, Eq, Debug)]
280/// # struct Person { name: Name, age: u32, id: (usize, usize) }
281/// # #[derive(PartialEq, Eq, Debug)]
282/// # struct Name { first: &'static str, last: &'static str }
283///
284/// let mut bob = Person {
285///     name: Name { first: "Bob", last: "Jones" },
286///     age: 35,
287///     id: (111, 222),
288/// };
289/// let bob_ptr: *mut Person = &mut bob;
290///
291/// unsafe {
292///     // Pointer to a single field:
293///     let age: *mut u32 = project_ptr_mut!(bob_ptr => age);
294///     *age = 36;
295///
296///     // Pointers to multiple fields:
297///     let (first, last, id0): (*mut &str, *mut &str, *mut usize) = project_ptr_mut!(
298///         bob_ptr => { name => first, name => last, id => 0 }
299///     );
300///     *first = "Robert";
301///     *last = "Johns";
302///     *id0 = 444;
303///     assert_eq!(bob, Person {
304///         name: Name { first: "Robert", last: "Johns" },
305///         age: 36,
306///         id: (444, 222),
307///     });
308/// }
309/// ```
310#[macro_export]
311macro_rules! project_ptr_mut {
312    // project mutliple fields
313    ($expr:expr => {$( $($props:tt)=>+ ),* $(,)?}) => {{
314        let ptr: *mut _ = $expr;
315        ($(
316            ::core::ptr::addr_of_mut!((*ptr).$($props).+),
317        )*)
318    }};
319
320    // project a single field
321    ($expr:expr => $($props:tt)=>+) => {
322        $crate::project_ptr_mut!($expr => {$($props)=>+}).0
323    };
324}
325
326///```compile_fail
327/// use project_uninit::project_uninit_mut;
328/// use core::mem::MaybeUninit;
329/// struct Foo { a: i32, b: u32 }
330/// let mut x = MaybeUninit::<Foo>::uninit();
331/// let (a, b, a2) = project_uninit_mut!(x => { a, b, a });
332///```
333fn _test_multiple_per_mut_macro_call_fails() {}
334
335///```compile_fail
336/// use project_uninit::{project_uninit, project_uninit_mut};
337/// use core::mem::MaybeUninit;
338/// struct Foo { a: i32, b: u32 }
339/// let mut x = MaybeUninit::<Foo>::uninit();
340/// let a = project_uninit!(x => a);
341/// let (a2, b) = project_uninit_mut!(x => { a, b });
342/// let aa = a;
343///```
344fn _project_mut_with_existing_borrow_fails() {}