From: Zhao Liu <zhao1.liu@intel.com>
To: Paolo Bonzini <pbonzini@redhat.com>
Cc: qemu-devel@nongnu.org, qemu-rust@nongnu.org,
manos.pitsidianakis@linaro.org
Subject: Re: [PATCH 5/7] rust: qemu-macros: add ToMigrationState derive macro
Date: Thu, 25 Sep 2025 20:35:22 +0800 [thread overview]
Message-ID: <aNU3Cgll0vETC2Az@intel.com> (raw)
In-Reply-To: <20250920142958.181910-6-pbonzini@redhat.com>
On Sat, Sep 20, 2025 at 04:29:56PM +0200, Paolo Bonzini wrote:
> Date: Sat, 20 Sep 2025 16:29:56 +0200
> From: Paolo Bonzini <pbonzini@redhat.com>
> Subject: [PATCH 5/7] rust: qemu-macros: add ToMigrationState derive macro
> X-Mailer: git-send-email 2.51.0
>
> Add a macro that recursively builds the "migrated" version
> of a struct.
>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
> rust/migration/meson.build | 2 +-
> rust/migration/src/lib.rs | 2 +
> rust/migration/src/migratable.rs | 12 +-
> rust/qemu-macros/src/lib.rs | 88 +++++++
> rust/qemu-macros/src/migration_state.rs | 296 ++++++++++++++++++++++++
> rust/qemu-macros/src/tests.rs | 112 ++++++++-
> 6 files changed, 507 insertions(+), 5 deletions(-)
> create mode 100644 rust/qemu-macros/src/migration_state.rs
...
> diff --git a/rust/migration/src/migratable.rs b/rust/migration/src/migratable.rs
> index d09eeb35f11..fa25317eea8 100644
> --- a/rust/migration/src/migratable.rs
> +++ b/rust/migration/src/migratable.rs
> @@ -79,6 +79,10 @@
> /// # dev2.restore_migrated_state_mut(*mig, 1).unwrap();
> /// # assert_eq!(dev2, dev);
> /// ```
> +///
> +/// More commonly, the trait is derived through the
> +/// [`derive(ToMigrationState)`](qemu_macros::ToMigrationState) procedural
> +/// macro.
> pub trait ToMigrationState {
> /// The type used to represent the migrated state.
> type Migrated: Default + VMState;
> @@ -305,13 +309,17 @@ fn restore_migrated_state(
> /// It manages the lifecycle of migration state and provides automatic
> /// conversion between runtime and migration representations.
> ///
> -/// ```ignore
> +/// ```
> /// # use std::sync::Mutex;
> -/// # use migration::Migratable;
> +/// # use migration::{Migratable, ToMigrationState, VMState, VMStateField};
> ///
> +/// #[derive(ToMigrationState)]
> /// pub struct DeviceRegs {
> /// status: u32,
> /// }
> +/// # unsafe impl VMState for DeviceRegsMigration {
> +/// # const BASE: VMStateField = ::common::Zeroable::ZERO;
> +/// # }
Outdated comment? Looks like the DeviceRegsMigration definition is
missing.
> /// pub struct SomeDevice {
> /// // ...
...
> +/// Derive macro for generating migration state structures and trait
> +/// implementations.
> +///
> +/// This macro generates a migration state struct and implements the
> +/// `ToMigrationState` trait for the annotated struct, enabling state
> +/// serialization and restoration. Note that defining a `VMStateDescription`
> +/// for the migration state struct is left to the user.
> +///
> +/// # Container attributes
> +///
> +/// The following attributes can be applied to the struct:
> +///
> +/// - `#[migration_state(rename = CustomName)]` - Customizes the name of the
> +/// generated migration struct. By default, the generated struct is named
> +/// `{OriginalName}Migration`.
> +///
> +/// # Field attributes
> +///
> +/// The following attributes can be applied to individual fields:
> +///
> +/// - `#[migration_state(omit)]` - Excludes the field from the migration state
> +/// entirely.
> +///
> +/// - `#[migration_state(into(Type))]` - Converts the field using `.into()`
> +/// during both serialization and restoration.
> +///
> +/// - `#[migration_state(try_into(Type))]` - Converts the field using
> +/// `.try_into()` during both serialization and restoration. Returns
> +/// `InvalidError` on conversion failure.
Good idea. These conversion modes are very useful, and inspiring.
It may be not necessary for #[property] to integrate into()/try_into()
mode, but the below conversion is ugly:
#[property(rename = "msi", bit = HPET_FLAG_MSI_SUPPORT_SHIFT as u8, default = false)]
conversion should happen within the macro parsing process. But unfortunately,
try_into() is not const, maybe I could do this for bit property:
diff --git a/rust/qemu-macros/src/lib.rs b/rust/qemu-macros/src/lib.rs
index c459f9bcb42f..e67df57c3712 100644
--- a/rust/qemu-macros/src/lib.rs
+++ b/rust/qemu-macros/src/lib.rs
@@ -275,7 +275,10 @@ macro_rules! str_to_c_str {
name: ::std::ffi::CStr::as_ptr(#prop_name),
info: #qdev_prop,
offset: ::core::mem::offset_of!(#name, #field_name) as isize,
- bitnr: #bitnr,
+ bitnr: {
+ const _: () = assert!(#bitnr <= u8::MAX as _, "bit exceeds u8 range");
+ #bitnr as u8
+ },
set_default: #set_default,
defval: ::hwcore::bindings::Property__bindgen_ty_1 { u: #defval as u64 },
..::common::Zeroable::ZERO
> +/// - `#[migration_state(clone)]` - Clones the field value.
How about emphasizing the use case?
"Clones the field value, especially for the types don't implement `Copy`."
> +/// Fields without any attributes use `ToMigrationState` recursively; note that
> +/// this is a simple copy for types that implement `Copy`.
> +///
> +/// # Attribute compatibility
> +///
> +/// - `omit` cannot be used with any other attributes
> +/// - only one of `into(Type)`, `try_into(Type)` can be used, but they can be
> +/// coupled with `clone`.
> +///
...
The implementation of the entire macro is great.
> +#[test]
> +fn test_derive_to_migration_state() {
...
> + quote! {
> + #[derive(Default)]
> + pub struct CustomMigration {
> + pub shared_data: String,
> + pub converted_field: Cow<'static, str>,
> + pub fallible_field: i8,
> + pub nested_field: <NestedStruct as ToMigrationState>::Migrated,
> + pub simple_field: <u32 as ToMigrationState>::Migrated,
> + }
In the production code, CustomMigration still needs to implement VMState
trait, so that String & Cow<'static, str> also need to implement VMState
trait. This seems like the thing that we are currently missing.
For test, it's enough to show how the macro works.
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
next prev parent reply other threads:[~2025-09-25 12:14 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-20 14:29 [RFC PATCH 0/7] rust: migration: add high-level migration wrappers Paolo Bonzini
2025-09-20 14:29 ` [PATCH 1/7] rust: bql: add BqlRefCell::get_mut() Paolo Bonzini
2025-09-23 15:12 ` Zhao Liu
2025-09-24 12:14 ` Paolo Bonzini
2025-09-20 14:29 ` [PATCH 2/7] rust: move VMState from bql to migration Paolo Bonzini
2025-09-23 14:46 ` Zhao Liu
2025-09-20 14:29 ` [PATCH 3/7] rust: migration: extract vmstate_fields_ref Paolo Bonzini
2025-09-24 15:21 ` Zhao Liu
2025-09-24 15:27 ` Zhao Liu
2025-09-25 9:24 ` Paolo Bonzini
2025-09-20 14:29 ` [PATCH 4/7] rust: migration: add high-level migration wrappers Paolo Bonzini
2025-09-25 9:05 ` Zhao Liu
2025-09-25 9:26 ` Paolo Bonzini
2025-09-20 14:29 ` [PATCH 5/7] rust: qemu-macros: add ToMigrationState derive macro Paolo Bonzini
2025-09-25 12:35 ` Zhao Liu [this message]
2025-09-25 16:56 ` Paolo Bonzini
2025-09-20 14:29 ` [PATCH 6/7] rust: migration: implement ToMigrationState for Timer Paolo Bonzini
2025-09-29 16:12 ` Zhao Liu
2025-09-29 16:11 ` Paolo Bonzini
2025-09-20 14:29 ` [PATCH 7/7] rust: migration: implement ToMigrationState as part of impl_vmstate_bitsized Paolo Bonzini
2025-09-30 6:53 ` 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=aNU3Cgll0vETC2Az@intel.com \
--to=zhao1.liu@intel.com \
--cc=manos.pitsidianakis@linaro.org \
--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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.