diff mbox series

[RFC,2/2] rust/qemu-api: Bind PropertyInfo to type

Message ID 20241017143245.1248589-3-zhao1.liu@intel.com (mailing list archive)
State New
Headers show
Series rust/qemu-api: Rethink property definition macro | expand

Commit Message

Zhao Liu Oct. 17, 2024, 2:32 p.m. UTC
For traditional property definitions implemented in C, since the C
language cannot bind variable types to specific methods or variables,
user must specify the concrete PropertyInfo and variable type in the
DEFINE_PROP macro and its variants. Then the property macro effectively
associate PropertyInfo with variable type through clever check.

However, in Rust, this process can be more elegant. By introducing the
PropertyType trait, QAPI (in Rust) can associate PropertyInfo with
specific types, allowing Rust to infer the predefined PropertyInfo from
the variable type.

This avoids user errors in passing incorrect PropertyInfo and simplifies
property definitions. And based on this enhancement, the property
definition macro can eliminate the need for the type and prop parameters.

Co-developed-by: Junjie Mao <junjie.mao@hotmail.com>
Signed-off-by: Junjie Mao <junjie.mao@hotmail.com>
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
---
 rust/hw/char/pl011/src/device_class.rs |  4 ---
 rust/qemu-api/src/device_class.rs      | 48 +++++++++++++++++++++++---
 rust/qemu-api/src/tests.rs             |  4 ---
 3 files changed, 43 insertions(+), 13 deletions(-)
diff mbox series

Patch

diff --git a/rust/hw/char/pl011/src/device_class.rs b/rust/hw/char/pl011/src/device_class.rs
index b7ab31af02d7..295e970e8564 100644
--- a/rust/hw/char/pl011/src/device_class.rs
+++ b/rust/hw/char/pl011/src/device_class.rs
@@ -21,15 +21,11 @@ 
         c"chardev",
         PL011State,
         char_backend,
-        unsafe { &qdev_prop_chr },
-        CharBackend
     ),
     qemu_api::define_property!(
         c"migrate-clk",
         PL011State,
         migrate_clock,
-        unsafe { &qdev_prop_bool },
-        bool
     ),
 }
 
diff --git a/rust/qemu-api/src/device_class.rs b/rust/qemu-api/src/device_class.rs
index be363fd63223..0b9d6ca705d3 100644
--- a/rust/qemu-api/src/device_class.rs
+++ b/rust/qemu-api/src/device_class.rs
@@ -4,7 +4,7 @@ 
 
 use std::sync::OnceLock;
 
-use crate::bindings::Property;
+use crate::bindings::{CharBackend, Property, PropertyInfo, qdev_prop_chr, qdev_prop_bool};
 
 #[macro_export]
 macro_rules! device_class_init {
@@ -24,16 +24,54 @@  macro_rules! device_class_init {
     };
 }
 
+pub trait PropertyType {
+    fn get_prop_info() -> *const PropertyInfo;
+}
+
+pub trait PropertyTypeImpl<T: PropertyType> {
+    fn get_prop_info(_: *const T) -> *const PropertyInfo;
+}
+
+impl<T: PropertyType> PropertyTypeImpl<T> for () {
+    fn get_prop_info(_: *const T) -> *const PropertyInfo {
+        T::get_prop_info()
+    }
+}
+
+impl PropertyType for CharBackend {
+    fn get_prop_info() -> *const PropertyInfo {
+        // SAFETY: Access to a defined c-structure, no other operation is performed.
+        unsafe { std::ptr::addr_of!(qdev_prop_chr) }
+    }
+}
+
+impl PropertyType for bool {
+    fn get_prop_info() -> *const PropertyInfo {
+        // SAFETY: Access to a defined c-structure, no other operation is performed.
+        unsafe { std::ptr::addr_of!(qdev_prop_bool) }
+    }
+}
+
+#[macro_export]
+macro_rules! get_prop_info {
+    ($state:ty, $field:ident) => {{
+    use $crate::device_class::PropertyTypeImpl;
+    let base = std::mem::MaybeUninit::<$state>::uninit().as_ptr();
+    <()>::get_prop_info(unsafe { std::ptr::addr_of!((*base).$field) })
+    }};
+}
+
+
 #[macro_export]
 macro_rules! define_property {
-    ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty, default = $defval:expr$(,)*) => {
+    ($name:expr, $state:ty, $field:ident, default = $defval:expr$(,)*) => {
         $crate::bindings::Property {
             name: {
                 #[used]
                 static _TEMP: &::core::ffi::CStr = $name;
                 _TEMP.as_ptr()
             },
-            info: $prop,
+            info: $crate::get_prop_info!($state, $field),
             offset: ::core::mem::offset_of!($state, $field)
                 .try_into()
                 .expect("Could not fit offset value to type"),
@@ -47,14 +85,14 @@  macro_rules! define_property {
             link_type: ::core::ptr::null(),
         }
     };
-    ($name:expr, $state:ty, $field:ident, $prop:expr, $type:ty$(,)*) => {
+    ($name:expr, $state:ty, $field:ident$(,)*) => {
         $crate::bindings::Property {
             name: {
                 #[used]
                 static _TEMP: &::core::ffi::CStr = $name;
                 _TEMP.as_ptr()
             },
-            info: $prop,
+            info: $crate::get_prop_info!($state, $field),
             offset: ::core::mem::offset_of!($state, $field)
                 .try_into()
                 .expect("Could not fit offset value to type"),
diff --git a/rust/qemu-api/src/tests.rs b/rust/qemu-api/src/tests.rs
index df54edbd4e27..d2b7451ef707 100644
--- a/rust/qemu-api/src/tests.rs
+++ b/rust/qemu-api/src/tests.rs
@@ -27,15 +27,11 @@  pub struct DummyState {
                 c"chardev",
                 DummyState,
                 char_backend,
-                unsafe { &qdev_prop_chr },
-                CharBackend
             ),
             define_property!(
                 c"migrate-clk",
                 DummyState,
                 migrate_clock,
-                unsafe { &qdev_prop_bool },
-                bool
             ),
     }