| 1 | //! Access fields of a [`MaybeUninit`] |
| 2 | |
| 3 | use std::{ |
| 4 | mem::MaybeUninit, |
| 5 | ops::{Deref, DerefMut}, |
| 6 | }; |
| 7 | |
| 8 | pub struct MaybeUninitField<'a, T, U> { |
| 9 | parent: &'a mut MaybeUninit<T>, |
| 10 | child: *mut U, |
| 11 | } |
| 12 | |
| 13 | impl<'a, T, U> MaybeUninitField<'a, T, U> { |
| 14 | #[doc(hidden)] |
| 15 | pub const fn new(parent: &'a mut MaybeUninit<T>, child: *mut U) -> Self { |
| 16 | MaybeUninitField { parent, child } |
| 17 | } |
| 18 | |
| 19 | /// Return a constant pointer to the containing object of the field. |
| 20 | /// |
| 21 | /// Because the `MaybeUninitField` remembers the containing object, |
| 22 | /// it is possible to use it in foreign APIs that initialize the |
| 23 | /// child. |
| 24 | pub const fn parent(f: &Self) -> *const T { |
| 25 | f.parent.as_ptr() |
| 26 | } |
| 27 | |
| 28 | /// Return a mutable pointer to the containing object. |
| 29 | /// |
| 30 | /// Because the `MaybeUninitField` remembers the containing object, |
| 31 | /// it is possible to use it in foreign APIs that initialize the |
| 32 | /// child. |
| 33 | pub const fn parent_mut(f: &mut Self) -> *mut T { |
| 34 | f.parent.as_mut_ptr() |
| 35 | } |
| 36 | } |
| 37 | |
| 38 | impl<T, U> Deref for MaybeUninitField<'_, T, U> { |
| 39 | type Target = MaybeUninit<U>; |
| 40 | |
| 41 | fn deref(&self) -> &MaybeUninit<U> { |
| 42 | // SAFETY: self.child was obtained by dereferencing a valid mutable |
| 43 | // reference; the content of the memory may be invalid or uninitialized |
| 44 | // but MaybeUninit<_> makes no assumption on it |
| 45 | unsafe { &*(self.child.cast()) } |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | impl<T, U> DerefMut for MaybeUninitField<'_, T, U> { |
| 50 | fn deref_mut(&mut self) -> &mut MaybeUninit<U> { |
| 51 | // SAFETY: self.child was obtained by dereferencing a valid mutable |
| 52 | // reference; the content of the memory may be invalid or uninitialized |
| 53 | // but MaybeUninit<_> makes no assumption on it |
| 54 | unsafe { &mut *(self.child.cast()) } |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | /// ``` |
| 59 | /// #[derive(Debug)] |
| 60 | /// struct S { |
| 61 | /// x: u32, |
| 62 | /// y: u32, |
| 63 | /// } |
| 64 | /// |
| 65 | /// # use std::mem::MaybeUninit; |
| 66 | /// # use common::{assert_match, uninit_field_mut}; |
| 67 | /// |
| 68 | /// let mut s: MaybeUninit<S> = MaybeUninit::zeroed(); |
| 69 | /// uninit_field_mut!(s, x).write(5); |
| 70 | /// let s = unsafe { s.assume_init() }; |
| 71 | /// assert_match!(s, S { x: 5, y: 0 }); |
| 72 | /// ``` |
| 73 | #[macro_export] |
| 74 | macro_rules! uninit_field_mut { |
| 75 | ($container:expr, $($field:tt)+) => {{ |
| 76 | let container__: &mut ::std::mem::MaybeUninit<_> = &mut $container; |
| 77 | let container_ptr__ = container__.as_mut_ptr(); |
| 78 | |
| 79 | // SAFETY: the container is not used directly, only through a MaybeUninit<>, |
| 80 | // so the safety is delegated to the caller and to final invocation of |
| 81 | // assume_init() |
| 82 | let target__ = unsafe { std::ptr::addr_of_mut!((*container_ptr__).$($field)+) }; |
| 83 | $crate::uninit::MaybeUninitField::new(container__, target__) |
| 84 | }}; |
| 85 | } |