rust: vmstate: add public utility macros to implement VMState

Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2024-12-21 13:42:41 +01:00
parent f2cb78bdbe
commit 00f89716a8

View file

@ -4,13 +4,18 @@
//! Helper macros to declare migration state for device models.
//!
//! This module includes three families of macros:
//! This module includes four families of macros:
//!
//! * [`vmstate_unused!`](crate::vmstate_unused) and
//! [`vmstate_of!`](crate::vmstate_of), which are used to express the
//! migration format for a struct. This is based on the [`VMState`] trait,
//! which is defined by all migrateable types.
//!
//! * [`impl_vmstate_forward`](crate::impl_vmstate_forward) and
//! [`impl_vmstate_bitsized`](crate::impl_vmstate_bitsized), which help with
//! the definition of the [`VMState`] trait (respectively for transparent
//! structs and for `bilge`-defined types)
//!
//! * helper macros to declare a device model state struct, in particular
//! [`vmstate_subsections`](crate::vmstate_subsections) and
//! [`vmstate_fields`](crate::vmstate_fields).
@ -134,7 +139,9 @@ macro_rules! info_enum_to_ref {
/// # Safety
///
/// The contents of this trait go straight into structs that are parsed by C
/// code and used to introspect into other structs. Be careful.
/// code and used to introspect into other structs. Generally, you don't need
/// to implement it except via macros that do it for you, such as
/// `impl_vmstate_bitsized!`.
pub unsafe trait VMState {
/// The `info` member of a `VMStateField` is a pointer and as such cannot
/// yet be included in the [`BASE`](VMState::BASE) associated constant;
@ -188,7 +195,9 @@ pub const fn vmstate_varray_flag<T: VMState>(_: PhantomData<T>) -> VMStateFlags
/// * an array of any of the above
///
/// In order to support other types, the trait `VMState` must be implemented
/// for them.
/// for them. The macros
/// [`impl_vmstate_bitsized!`](crate::impl_vmstate_bitsized)
/// and [`impl_vmstate_forward!`](crate::impl_vmstate_forward) help with this.
#[macro_export]
macro_rules! vmstate_of {
($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])? $(,)?) => {
@ -276,6 +285,32 @@ impl VMStateField {
}
}
/// This macro can be used (by just passing it a type) to forward the `VMState`
/// trait to the first field of a tuple. This is a workaround for lack of
/// support of nested [`offset_of`](core::mem::offset_of) until Rust 1.82.0.
///
/// # Examples
///
/// ```
/// # use qemu_api::vmstate::impl_vmstate_forward;
/// pub struct Fifo([u8; 16]);
/// impl_vmstate_forward!(Fifo);
/// ```
#[macro_export]
macro_rules! impl_vmstate_forward {
// This is similar to impl_vmstate_transparent below, but it
// uses the same trick as vmstate_of! to obtain the type of
// the first field of the tuple
($tuple:ty) => {
unsafe impl $crate::vmstate::VMState for $tuple {
const SCALAR_TYPE: $crate::vmstate::VMStateFieldType =
$crate::call_func_with_field!($crate::vmstate::vmstate_scalar_type, $tuple, 0);
const BASE: $crate::bindings::VMStateField =
$crate::call_func_with_field!($crate::vmstate::vmstate_base, $tuple, 0);
}
};
}
// Transparent wrappers: just use the internal type
macro_rules! impl_vmstate_transparent {
@ -296,6 +331,26 @@ impl_vmstate_transparent!(std::cell::UnsafeCell<T> where T: VMState);
impl_vmstate_transparent!(crate::cell::BqlCell<T> where T: VMState);
impl_vmstate_transparent!(crate::cell::BqlRefCell<T> where T: VMState);
#[macro_export]
macro_rules! impl_vmstate_bitsized {
($type:ty) => {
unsafe impl $crate::vmstate::VMState for $type {
const SCALAR_TYPE: $crate::vmstate::VMStateFieldType =
<<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt
as ::bilge::prelude::Number>::UnderlyingType
as $crate::vmstate::VMState>::SCALAR_TYPE;
const BASE: $crate::bindings::VMStateField =
<<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt
as ::bilge::prelude::Number>::UnderlyingType
as $crate::vmstate::VMState>::BASE;
const VARRAY_FLAG: $crate::bindings::VMStateFlags =
<<<$type as ::bilge::prelude::Bitsized>::ArbitraryInt
as ::bilge::prelude::Number>::UnderlyingType
as $crate::vmstate::VMState>::VARRAY_FLAG;
}
};
}
// Scalar types using predefined VMStateInfos
macro_rules! impl_vmstate_scalar {