[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 13/17] rust/vmstate: Support vmstate_validate
From: |
Zhao Liu |
Subject: |
[PATCH 13/17] rust/vmstate: Support vmstate_validate |
Date: |
Mon, 17 Mar 2025 23:12:32 +0800 |
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>
---
rust/qemu-api/src/vmstate.rs | 57 +++++++++++++++++++++++++++++++++++-
1 file changed, 56 insertions(+), 1 deletion(-)
diff --git a/rust/qemu-api/src/vmstate.rs b/rust/qemu-api/src/vmstate.rs
index bb41bfd291c0..4eefd54ca120 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
@@ -292,6 +295,14 @@ pub const fn with_varray_multiply(mut self, num: u32) ->
VMStateField {
self.num = num as i32;
self
}
+
+ #[must_use]
+ pub const fn with_exist_check(mut self) -> Self {
+ assert!(self.flags.0 == 0);
+ self.flags = VMStateFlags(VMStateFlags::VMS_MUST_EXIST.0 |
VMStateFlags::VMS_ARRAY.0);
+ self.num = 0; // 0 elements: no data, only run test_fn callback
+ self
+ }
}
/// This macro can be used (by just passing it a type) to forward the `VMState`
@@ -510,6 +521,50 @@ 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),
+ // TODO: Use safe callback.
+ 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)))
+ },
+ ..$crate::zeroable::Zeroable::ZERO
+ }
+ .with_exist_check()
+ };
+}
+
/// A transparent wrapper type for the `subsections` field of
/// [`VMStateDescription`].
///
--
2.34.1
- [PATCH 07/17] rust/vmstate: Fix type check for varray in vmstate_struct, (continued)
- [PATCH 07/17] rust/vmstate: Fix type check for varray in vmstate_struct, Zhao Liu, 2025/03/17
- [PATCH 09/17] rust/vmstate: Fix unnecessary VMState bound of with_varray_flag(), Zhao Liu, 2025/03/17
- [PATCH 04/17] rust/vmstate: Use ident instead of expr to parse vmsd in vmstate_struct macro, Zhao Liu, 2025/03/17
- [PATCH 10/17] rust/vmstate: Relax array check when build varray in vmstate_struct, Zhao Liu, 2025/03/17
- [PATCH 12/17] rust/vmstate: Support version field in vmstate macros, Zhao Liu, 2025/03/17
- [PATCH 13/17] rust/vmstate: Support vmstate_validate,
Zhao Liu <=
- [PATCH 08/17] rust/vmstate: Fix "cannot infer type" error in vmstate_struct, Zhao Liu, 2025/03/17
- [PATCH 14/17] rust/vmstate: Add unit test for vmstate_of macro, Zhao Liu, 2025/03/17
- [PATCH 15/17] rust/vmstate: Add unit test for vmstate_{of|struct} macro, Zhao Liu, 2025/03/17
- [PATCH 11/17] rust/vmstate: Re-implement VMState trait for timer binding, Zhao Liu, 2025/03/17