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