mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-01 23:03:54 -06:00
rust: vmstate: add new type safe implementation
The existing translation of the C macros for vmstate does not make any attempt to type-check vmstate declarations against the struct, so introduce a new system that computes VMStateField based on the actual struct declaration. Macros do not have full access to the type system, therefore a full implementation of this scheme requires a helper trait to analyze the type and produce a VMStateField from it; a macro "vmstate_of!" accepts arguments similar to "offset_of!" and tricks the compiler into looking up the trait for the right type. The patch introduces not just vmstate_of!, but also the slightly too clever enabling macro call_func_with_field!. The particular trick used here was proposed on the users.rust-lang.org forum, so I take no merit and all the blame. Introduce the trait and some functions to access it; the actual implementation comes later. Reviewed-by: Zhao Liu <zhao1.liu@intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
57f9d9c84a
commit
0d43ddae35
2 changed files with 109 additions and 6 deletions
|
@ -18,3 +18,5 @@ pub use crate::qom::ObjectType;
|
||||||
pub use crate::qom_isa;
|
pub use crate::qom_isa;
|
||||||
|
|
||||||
pub use crate::sysbus::SysBusDeviceMethods;
|
pub use crate::sysbus::SysBusDeviceMethods;
|
||||||
|
|
||||||
|
pub use crate::vmstate::VMState;
|
||||||
|
|
|
@ -4,13 +4,114 @@
|
||||||
|
|
||||||
//! Helper macros to declare migration state for device models.
|
//! Helper macros to declare migration state for device models.
|
||||||
//!
|
//!
|
||||||
//! Some macros are direct equivalents to the C macros declared in
|
//! This module includes three families of macros:
|
||||||
//! `include/migration/vmstate.h` while
|
//!
|
||||||
//! [`vmstate_subsections`](crate::vmstate_subsections) and
|
//! * [`vmstate_unused!`](crate::vmstate_unused) and
|
||||||
//! [`vmstate_fields`](crate::vmstate_fields) are meant to be used when
|
//! [`vmstate_of!`](crate::vmstate_of), which are used to express the
|
||||||
//! declaring a device model state struct.
|
//! migration format for a struct. This is based on the [`VMState`] trait,
|
||||||
|
//! which is defined by all migrateable types.
|
||||||
|
//!
|
||||||
|
//! * helper macros to declare a device model state struct, in particular
|
||||||
|
//! [`vmstate_subsections`](crate::vmstate_subsections) and
|
||||||
|
//! [`vmstate_fields`](crate::vmstate_fields).
|
||||||
|
//!
|
||||||
|
//! * direct equivalents to the C macros declared in
|
||||||
|
//! `include/migration/vmstate.h`. These are not type-safe and should not be
|
||||||
|
//! used if the equivalent functionality is available with `vmstate_of!`.
|
||||||
|
|
||||||
pub use crate::bindings::VMStateDescription;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
pub use crate::bindings::{VMStateDescription, VMStateField};
|
||||||
|
|
||||||
|
/// This macro is used to call a function with a generic argument bound
|
||||||
|
/// to the type of a field. The function must take a
|
||||||
|
/// [`PhantomData`]`<T>` argument; `T` is the type of
|
||||||
|
/// field `$field` in the `$typ` type.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use qemu_api::call_func_with_field;
|
||||||
|
/// # use core::marker::PhantomData;
|
||||||
|
/// const fn size_of_field<T>(_: PhantomData<T>) -> usize {
|
||||||
|
/// std::mem::size_of::<T>()
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// struct Foo {
|
||||||
|
/// x: u16,
|
||||||
|
/// };
|
||||||
|
/// // calls size_of_field::<u16>()
|
||||||
|
/// assert_eq!(call_func_with_field!(size_of_field, Foo, x), 2);
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! call_func_with_field {
|
||||||
|
// Based on the answer by user steffahn (Frank Steffahn) at
|
||||||
|
// https://users.rust-lang.org/t/inferring-type-of-field/122857
|
||||||
|
// and used under MIT license
|
||||||
|
($func:expr, $typ:ty, $($field:tt).+) => {
|
||||||
|
$func(loop {
|
||||||
|
#![allow(unreachable_code)]
|
||||||
|
const fn phantom__<T>(_: &T) -> ::core::marker::PhantomData<T> { ::core::marker::PhantomData }
|
||||||
|
// Unreachable code is exempt from checks on uninitialized values.
|
||||||
|
// Use that trick to infer the type of this PhantomData.
|
||||||
|
break ::core::marker::PhantomData;
|
||||||
|
break phantom__(&{ let value__: $typ; value__.$($field).+ });
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A trait for types that can be included in a device's migration stream. It
|
||||||
|
/// provides the base contents of a `VMStateField` (minus the name and offset).
|
||||||
|
///
|
||||||
|
/// # 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.
|
||||||
|
pub unsafe trait VMState {
|
||||||
|
/// The base contents of a `VMStateField` (minus the name and offset) for
|
||||||
|
/// the type that is implementing the trait.
|
||||||
|
const BASE: VMStateField;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Internal utility function to retrieve a type's `VMStateField`;
|
||||||
|
/// used by [`vmstate_of!`](crate::vmstate_of).
|
||||||
|
pub const fn vmstate_base<T: VMState>(_: PhantomData<T>) -> VMStateField {
|
||||||
|
T::BASE
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the `VMStateField` for a field of a struct. The field must be
|
||||||
|
/// visible in the current scope.
|
||||||
|
///
|
||||||
|
/// In order to support other types, the trait `VMState` must be implemented
|
||||||
|
/// for them.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! vmstate_of {
|
||||||
|
($struct_name:ty, $field_name:ident $(,)?) => {
|
||||||
|
$crate::bindings::VMStateField {
|
||||||
|
name: ::core::concat!(::core::stringify!($field_name), "\0")
|
||||||
|
.as_bytes()
|
||||||
|
.as_ptr() as *const ::std::os::raw::c_char,
|
||||||
|
offset: $crate::offset_of!($struct_name, $field_name),
|
||||||
|
// Compute most of the VMStateField from the type of the field.
|
||||||
|
..$crate::call_func_with_field!(
|
||||||
|
$crate::vmstate::vmstate_base,
|
||||||
|
$struct_name,
|
||||||
|
$field_name
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a couple builder-style methods to VMStateField, allowing
|
||||||
|
// easy derivation of VMStateField constants from other types.
|
||||||
|
impl VMStateField {
|
||||||
|
#[must_use]
|
||||||
|
pub const fn with_version_id(mut self, version_id: i32) -> Self {
|
||||||
|
assert!(version_id >= 0);
|
||||||
|
self.version_id = version_id;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[doc(alias = "VMSTATE_UNUSED_BUFFER")]
|
#[doc(alias = "VMSTATE_UNUSED_BUFFER")]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue