mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-07-27 04:13:53 -06:00
rust: qemu_api: introduce MaybeUninit field projection
Add a macro that makes it possible to convert a MaybeUninit<> into another MaybeUninit<> for a single field within it. Furthermore, it is possible to use the resulting MaybeUninitField<> in APIs that take the parent object, such as memory_region_init_io(). This allows removing some of the undefined behavior from instance_init() functions, though this may not be the definitive implementation. Reviewed-by: Zhao Liu <zhao1.liu@intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
6c2888dd0f
commit
abf1832424
3 changed files with 87 additions and 0 deletions
|
@ -27,6 +27,7 @@ pub mod qdev;
|
|||
pub mod qom;
|
||||
pub mod sysbus;
|
||||
pub mod timer;
|
||||
pub mod uninit;
|
||||
pub mod vmstate;
|
||||
pub mod zeroable;
|
||||
|
||||
|
|
85
rust/qemu-api/src/uninit.rs
Normal file
85
rust/qemu-api/src/uninit.rs
Normal file
|
@ -0,0 +1,85 @@
|
|||
//! Access fields of a [`MaybeUninit`]
|
||||
|
||||
use std::{
|
||||
mem::MaybeUninit,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
|
||||
pub struct MaybeUninitField<'a, T, U> {
|
||||
parent: &'a mut MaybeUninit<T>,
|
||||
child: *mut U,
|
||||
}
|
||||
|
||||
impl<'a, T, U> MaybeUninitField<'a, T, U> {
|
||||
#[doc(hidden)]
|
||||
pub fn new(parent: &'a mut MaybeUninit<T>, child: *mut U) -> Self {
|
||||
MaybeUninitField { parent, child }
|
||||
}
|
||||
|
||||
/// Return a constant pointer to the containing object of the field.
|
||||
///
|
||||
/// Because the `MaybeUninitField` remembers the containing object,
|
||||
/// it is possible to use it in foreign APIs that initialize the
|
||||
/// child.
|
||||
pub fn parent(f: &Self) -> *const T {
|
||||
f.parent.as_ptr()
|
||||
}
|
||||
|
||||
/// Return a mutable pointer to the containing object.
|
||||
///
|
||||
/// Because the `MaybeUninitField` remembers the containing object,
|
||||
/// it is possible to use it in foreign APIs that initialize the
|
||||
/// child.
|
||||
pub fn parent_mut(f: &mut Self) -> *mut T {
|
||||
f.parent.as_mut_ptr()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, U> Deref for MaybeUninitField<'a, T, U> {
|
||||
type Target = MaybeUninit<U>;
|
||||
|
||||
fn deref(&self) -> &MaybeUninit<U> {
|
||||
// SAFETY: self.child was obtained by dereferencing a valid mutable
|
||||
// reference; the content of the memory may be invalid or uninitialized
|
||||
// but MaybeUninit<_> makes no assumption on it
|
||||
unsafe { &*(self.child.cast()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, U> DerefMut for MaybeUninitField<'a, T, U> {
|
||||
fn deref_mut(&mut self) -> &mut MaybeUninit<U> {
|
||||
// SAFETY: self.child was obtained by dereferencing a valid mutable
|
||||
// reference; the content of the memory may be invalid or uninitialized
|
||||
// but MaybeUninit<_> makes no assumption on it
|
||||
unsafe { &mut *(self.child.cast()) }
|
||||
}
|
||||
}
|
||||
|
||||
/// ```
|
||||
/// #[derive(Debug)]
|
||||
/// struct S {
|
||||
/// x: u32,
|
||||
/// y: u32,
|
||||
/// }
|
||||
///
|
||||
/// # use std::mem::MaybeUninit;
|
||||
/// # use qemu_api::{assert_match, uninit_field_mut};
|
||||
///
|
||||
/// let mut s: MaybeUninit<S> = MaybeUninit::zeroed();
|
||||
/// uninit_field_mut!(s, x).write(5);
|
||||
/// let s = unsafe { s.assume_init() };
|
||||
/// assert_match!(s, S { x: 5, y: 0 });
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! uninit_field_mut {
|
||||
($container:expr, $($field:tt)+) => {{
|
||||
let container__: &mut ::std::mem::MaybeUninit<_> = &mut $container;
|
||||
let container_ptr__ = container__.as_mut_ptr();
|
||||
|
||||
// SAFETY: the container is not used directly, only through a MaybeUninit<>,
|
||||
// so the safety is delegated to the caller and to final invocation of
|
||||
// assume_init()
|
||||
let target__ = unsafe { std::ptr::addr_of_mut!((*container_ptr__).$($field)+) };
|
||||
$crate::uninit::MaybeUninitField::new(container__, target__)
|
||||
}};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue