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() {}