[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PULL 05/24] rust: qemu_api: introduce MaybeUninit field projection
From: |
Paolo Bonzini |
Subject: |
[PULL 05/24] rust: qemu_api: introduce MaybeUninit field projection |
Date: |
Fri, 20 Jun 2025 18:40:33 +0200 |
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>
---
rust/qemu-api/meson.build | 1 +
rust/qemu-api/src/lib.rs | 1 +
rust/qemu-api/src/uninit.rs | 85 +++++++++++++++++++++++++++++++++++++
3 files changed, 87 insertions(+)
create mode 100644 rust/qemu-api/src/uninit.rs
diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build
index cac8595a148..33653b4a28e 100644
--- a/rust/qemu-api/meson.build
+++ b/rust/qemu-api/meson.build
@@ -28,6 +28,7 @@ _qemu_api_rs = static_library(
'src/qom.rs',
'src/sysbus.rs',
'src/timer.rs',
+ 'src/uninit.rs',
'src/vmstate.rs',
'src/zeroable.rs',
],
diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs
index 93902fc94bc..c78198f0f41 100644
--- a/rust/qemu-api/src/lib.rs
+++ b/rust/qemu-api/src/lib.rs
@@ -27,6 +27,7 @@
pub mod qom;
pub mod sysbus;
pub mod timer;
+pub mod uninit;
pub mod vmstate;
pub mod zeroable;
diff --git a/rust/qemu-api/src/uninit.rs b/rust/qemu-api/src/uninit.rs
new file mode 100644
index 00000000000..04123b4ae99
--- /dev/null
+++ b/rust/qemu-api/src/uninit.rs
@@ -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__)
+ }};
+}
--
2.49.0
- [PULL 00/24] i386 (TCG, TDX), Rust changes for 2025-06-20, Paolo Bonzini, 2025/06/20
- [PULL 01/24] meson: cleanup win32 library detection, Paolo Bonzini, 2025/06/20
- [PULL 03/24] hw: Fix type constant for DTB files, Paolo Bonzini, 2025/06/20
- [PULL 02/24] target/i386: fix TB exit logic in gen_movl_seg() when writing to SS, Paolo Bonzini, 2025/06/20
- [PULL 04/24] pc-bios/dtb/meson: Prefer target name to be outfile, not infile, Paolo Bonzini, 2025/06/20
- [PULL 06/24] rust: hpet: fully initialize object during instance_init, Paolo Bonzini, 2025/06/20
- [PULL 05/24] rust: qemu_api: introduce MaybeUninit field projection,
Paolo Bonzini <=
- [PULL 08/24] rust: qom: make ParentInit lifetime-invariant, Paolo Bonzini, 2025/06/20
- [PULL 09/24] rust: qom: change instance_init to take a ParentInit<>, Paolo Bonzini, 2025/06/20
- [PULL 10/24] rust: prepare variable definitions for multiple bindgen invocations, Paolo Bonzini, 2025/06/20
- [PULL 11/24] rust: move rust.bindgen to qemu-api crate, Paolo Bonzini, 2025/06/20
- [PULL 07/24] rust: qom: introduce ParentInit, Paolo Bonzini, 2025/06/20
- [PULL 12/24] rust/qemu-api: Add initial logging support based on C API, Paolo Bonzini, 2025/06/20
- [PULL 13/24] rust: pl011: Implement logging, Paolo Bonzini, 2025/06/20
- [PULL 14/24] rust: pl011: Add missing logging to match C version, Paolo Bonzini, 2025/06/20
- [PULL 15/24] rust: hpet: fix new warning, Paolo Bonzini, 2025/06/20
- [PULL 16/24] i386/cpu: Move adjustment of CPUID_EXT_PDCM before feature_dependencies[] check, Paolo Bonzini, 2025/06/20