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:16 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).