mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-07-27 04:13:53 -06:00
rust/vmstate: Add support for field_exists checks
Unfortunately, at present it's not possible to have a const "with_exist_check" method to append test_fn after vmstate_struct (due to error on "constant functions cannot evaluate destructors" for `F`). Before the vmstate builder, the only way to support "test_fn" is to extend vmstate_struct macro to add the such new optional member (and fortunately, Rust can still parse the current expansion!). Abstract the previous callback implementation of vmstate_validate into a separate macro, and moves it before vmstate_struct for vmstate_struct to call. Note that there's no need to add any extra flag for a new test_fn added in the VMStateField. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> Link: https://lore.kernel.org/r/20250414144943.1112885-2-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
5134cf9b5d
commit
6f8e6aed81
1 changed files with 37 additions and 33 deletions
|
@ -200,13 +200,14 @@ pub const fn vmstate_varray_flag<T: VMState>(_: PhantomData<T>) -> VMStateFlags
|
||||||
/// and [`impl_vmstate_forward!`](crate::impl_vmstate_forward) help with this.
|
/// and [`impl_vmstate_forward!`](crate::impl_vmstate_forward) help with this.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! vmstate_of {
|
macro_rules! vmstate_of {
|
||||||
($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])? $(,)?) => {
|
($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])? $(, $test_fn:expr)? $(,)?) => {
|
||||||
$crate::bindings::VMStateField {
|
$crate::bindings::VMStateField {
|
||||||
name: ::core::concat!(::core::stringify!($field_name), "\0")
|
name: ::core::concat!(::core::stringify!($field_name), "\0")
|
||||||
.as_bytes()
|
.as_bytes()
|
||||||
.as_ptr() as *const ::std::os::raw::c_char,
|
.as_ptr() as *const ::std::os::raw::c_char,
|
||||||
offset: $crate::offset_of!($struct_name, $field_name),
|
offset: $crate::offset_of!($struct_name, $field_name),
|
||||||
$(num_offset: $crate::offset_of!($struct_name, $num),)?
|
$(num_offset: $crate::offset_of!($struct_name, $num),)?
|
||||||
|
$(field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),)?
|
||||||
// The calls to `call_func_with_field!` are the magic that
|
// The calls to `call_func_with_field!` are the magic that
|
||||||
// computes most of the VMStateField from the type of the field.
|
// computes most of the VMStateField from the type of the field.
|
||||||
info: $crate::info_enum_to_ref!($crate::call_func_with_field!(
|
info: $crate::info_enum_to_ref!($crate::call_func_with_field!(
|
||||||
|
@ -435,6 +436,38 @@ macro_rules! vmstate_unused {
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
// SAFETY: the opaque was passed as a reference to `T`.
|
||||||
|
let owner: &T = unsafe { &*(opaque.cast::<T>()) };
|
||||||
|
let version: u8 = version_id.try_into().unwrap();
|
||||||
|
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;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! vmstate_exist_fn {
|
||||||
|
($struct_name:ty, $test_fn:expr) => {{
|
||||||
|
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)))
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: including the `vmsd` field in a `const` is not possible without
|
// FIXME: including the `vmsd` field in a `const` is not possible without
|
||||||
// the const_refs_static feature (stabilized in Rust 1.83.0). Without it,
|
// the const_refs_static feature (stabilized in Rust 1.83.0). Without it,
|
||||||
// it is not possible to use VMS_STRUCT in a transparent manner using
|
// it is not possible to use VMS_STRUCT in a transparent manner using
|
||||||
|
@ -445,7 +478,7 @@ macro_rules! vmstate_unused {
|
||||||
#[doc(alias = "VMSTATE_STRUCT")]
|
#[doc(alias = "VMSTATE_STRUCT")]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! vmstate_struct {
|
macro_rules! vmstate_struct {
|
||||||
($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])?, $vmsd:expr, $type:ty $(,)?) => {
|
($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])?, $vmsd:expr, $type:ty $(, $test_fn:expr)? $(,)?) => {
|
||||||
$crate::bindings::VMStateField {
|
$crate::bindings::VMStateField {
|
||||||
name: ::core::concat!(::core::stringify!($field_name), "\0")
|
name: ::core::concat!(::core::stringify!($field_name), "\0")
|
||||||
.as_bytes()
|
.as_bytes()
|
||||||
|
@ -458,6 +491,7 @@ macro_rules! vmstate_struct {
|
||||||
size: ::core::mem::size_of::<$type>(),
|
size: ::core::mem::size_of::<$type>(),
|
||||||
flags: $crate::bindings::VMStateFlags::VMS_STRUCT,
|
flags: $crate::bindings::VMStateFlags::VMS_STRUCT,
|
||||||
vmsd: $vmsd,
|
vmsd: $vmsd,
|
||||||
|
$(field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),)?
|
||||||
..$crate::zeroable::Zeroable::ZERO
|
..$crate::zeroable::Zeroable::ZERO
|
||||||
} $(.with_varray_flag_unchecked(
|
} $(.with_varray_flag_unchecked(
|
||||||
$crate::call_func_with_field!(
|
$crate::call_func_with_field!(
|
||||||
|
@ -514,43 +548,13 @@ 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")]
|
#[doc(alias = "VMSTATE_VALIDATE")]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! vmstate_validate {
|
macro_rules! vmstate_validate {
|
||||||
($struct_name:ty, $test_name:expr, $test_fn:expr $(,)?) => {
|
($struct_name:ty, $test_name:expr, $test_fn:expr $(,)?) => {
|
||||||
$crate::bindings::VMStateField {
|
$crate::bindings::VMStateField {
|
||||||
name: ::std::ffi::CStr::as_ptr($test_name),
|
name: ::std::ffi::CStr::as_ptr($test_name),
|
||||||
field_exists: {
|
field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),
|
||||||
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(
|
flags: $crate::bindings::VMStateFlags(
|
||||||
$crate::bindings::VMStateFlags::VMS_MUST_EXIST.0
|
$crate::bindings::VMStateFlags::VMS_MUST_EXIST.0
|
||||||
| $crate::bindings::VMStateFlags::VMS_ARRAY.0,
|
| $crate::bindings::VMStateFlags::VMS_ARRAY.0,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue