qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Zhao Liu <zhao1.liu@intel.com>
To: Paolo Bonzini <pbonzini@redhat.com>
Cc: qemu-devel@nongnu.org, qemu-rust@nongnu.org,
	Zhao Liu <zhao1.liu@intel.com>
Subject: [PATCH v3 10/15] rust/vmstate: Support vmstate_validate
Date: Tue, 18 Mar 2025 21:02:14 +0800	[thread overview]
Message-ID: <20250318130219.1799170-11-zhao1.liu@intel.com> (raw)
In-Reply-To: <20250318130219.1799170-1-zhao1.liu@intel.com>

In C version, VMSTATE_VALIDATE accepts the function pointer, which is
used to check if some conditions of structure could meet, although the
C version macro doesn't accept any structure as the opaque type.

But it's hard to integrate VMSTATE_VALIDAE into vmstate_struct, a new
macro has to be introduced to specifically handle the case corresponding
to VMSTATE_VALIDATE.

One of the difficulties is inferring the type of a callback by its name
`test_fn`. We can't directly use `test_fn` as a parameter of
test_cb_builder__() to get its type "F", because in this way, Rust
compiler will be too conservative on drop check and complain "the
destructor for this type cannot be evaluated in constant functions".

Fortunately, PhantomData<T> could help in this case, because it is
considered to never have a destructor, no matter its field type [*].

The `phantom__()` in the `call_func_with_field` macro provides a good
example of using PhantomData to infer type. So copy this idea and apply
it to the `vmstate_validate` macro.

[*]: https://doc.rust-lang.org/std/ops/trait.Drop.html#drop-check

Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
---
Changes since v1:
 * Rename `with_exist_check()` to `with_validate_flag()`.
 * Add a `with_exist_check()` method to help add field_exists callback,
   though it can't be used in static VMStateDescription definition but
   will be useful for vmstate builder.

Changes since v2:
 * Drop `with_exist_check()` and `with_validate_flag()`.
---
 rust/qemu-api/src/vmstate.rs | 52 +++++++++++++++++++++++++++++++++++-
 1 file changed, 51 insertions(+), 1 deletion(-)

diff --git a/rust/qemu-api/src/vmstate.rs b/rust/qemu-api/src/vmstate.rs
index 01f06ed7379e..9740931fb16a 100644
--- a/rust/qemu-api/src/vmstate.rs
+++ b/rust/qemu-api/src/vmstate.rs
@@ -25,9 +25,12 @@
 //!   functionality that is missing from `vmstate_of!`.
 
 use core::{marker::PhantomData, mem, ptr::NonNull};
+use std::os::raw::{c_int, c_void};
 
 pub use crate::bindings::{VMStateDescription, VMStateField};
-use crate::{bindings::VMStateFlags, prelude::*, qom::Owned, zeroable::Zeroable};
+use crate::{
+    bindings::VMStateFlags, callbacks::FnCall, prelude::*, qom::Owned, zeroable::Zeroable,
+};
 
 /// This macro is used to call a function with a generic argument bound
 /// to the type of a field.  The function must take a
@@ -508,6 +511,53 @@ macro_rules! vmstate_fields {
     }}
 }
 
+pub extern "C" fn rust_vms_test_field_exists<T, F: for<'a> FnCall<(&'a T, u8), bool>>(
+    opaque: *mut c_void,
+    version_id: c_int,
+) -> bool {
+    let owner: &T = unsafe { &*(opaque.cast::<T>()) };
+    let version: u8 = version_id.try_into().unwrap();
+    // SAFETY: the opaque was passed as a reference to `T`.
+    F::call((owner, version))
+}
+
+pub type VMSFieldExistCb = unsafe extern "C" fn(
+    opaque: *mut std::os::raw::c_void,
+    version_id: std::os::raw::c_int,
+) -> bool;
+
+#[doc(alias = "VMSTATE_VALIDATE")]
+#[macro_export]
+macro_rules! vmstate_validate {
+    ($struct_name:ty, $test_name:expr, $test_fn:expr $(,)?) => {
+        $crate::bindings::VMStateField {
+            name: ::std::ffi::CStr::as_ptr($test_name),
+            field_exists: {
+                const fn test_cb_builder__<
+                    T,
+                    F: for<'a> $crate::callbacks::FnCall<(&'a T, u8), bool>,
+                >(
+                    _phantom: ::core::marker::PhantomData<F>,
+                ) -> $crate::vmstate::VMSFieldExistCb {
+                    let _: () = F::ASSERT_IS_SOME;
+                    $crate::vmstate::rust_vms_test_field_exists::<T, F>
+                }
+
+                const fn phantom__<T>(_: &T) -> ::core::marker::PhantomData<T> {
+                    ::core::marker::PhantomData
+                }
+                Some(test_cb_builder__::<$struct_name, _>(phantom__(&$test_fn)))
+            },
+            flags: $crate::bindings::VMStateFlags(
+                $crate::bindings::VMStateFlags::VMS_MUST_EXIST.0
+                    | $crate::bindings::VMStateFlags::VMS_ARRAY.0,
+            ),
+            num: 0, // 0 elements: no data, only run test_fn callback
+            ..$crate::zeroable::Zeroable::ZERO
+        }
+    };
+}
+
 /// A transparent wrapper type for the `subsections` field of
 /// [`VMStateDescription`].
 ///
-- 
2.34.1



  parent reply	other threads:[~2025-03-18 12:48 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-03-18 13:02 [PATCH v3 00/15] rust/vmstate: Clean up, fix, enhance & test Zhao Liu
2025-03-18 13:02 ` [PATCH v3 01/15] rust/vmstate: Remove unnecessary unsafe Zhao Liu
2025-03-18 13:02 ` [PATCH v3 02/15] rust/vmstate: Fix num_offset in vmstate macros Zhao Liu
2025-03-18 13:02 ` [PATCH v3 03/15] rust/vmstate: Fix num field when varray flags are set Zhao Liu
2025-03-18 13:02 ` [PATCH v3 04/15] rust/vmstate: Fix size field of VMStateField with VMS_ARRAY_OF_POINTER flag Zhao Liu
2025-03-18 13:02 ` [PATCH v3 05/15] rust/vmstate: Fix type check for varray in vmstate_struct Zhao Liu
2025-03-18 13:02 ` [PATCH v3 06/15] rust/vmstate: Fix "cannot infer type" error " Zhao Liu
2025-03-18 13:02 ` [PATCH v3 07/15] rust/vmstate: Fix unnecessary VMState bound of with_varray_flag() Zhao Liu
2025-03-18 13:02 ` [PATCH v3 08/15] rust/vmstate: Relax array check when build varray in vmstate_struct Zhao Liu
2025-03-18 13:02 ` [PATCH v3 09/15] rust/vmstate: Re-implement VMState trait for timer binding Zhao Liu
2025-03-18 13:02 ` Zhao Liu [this message]
2025-03-18 13:02 ` [PATCH v3 11/15] rust/vmstate: Add unit test for vmstate_of macro Zhao Liu
2025-03-18 13:02 ` [PATCH v3 12/15] rust/vmstate: Add unit test for vmstate_{of|struct} macro Zhao Liu
2025-03-18 13:02 ` [PATCH v3 13/15] rust/vmstate: Add unit test for pointer case Zhao Liu
2025-03-18 13:02 ` [PATCH v3 14/15] rust/vmstate: Add unit test for vmstate_validate Zhao Liu
2025-03-18 13:02 ` [PATCH v3 15/15] rust/vmstate: Include complete crate path of VMStateFlags in vmstate_clock Zhao Liu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250318130219.1799170-11-zhao1.liu@intel.com \
    --to=zhao1.liu@intel.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-rust@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).