> It seems the generated migration_state_struct needs a complete VMSD:
> collect all its fields and build a VMSD.
> 
> And then apply impl_vmstate_struct! to this  migration_state_struct.
> 
> If we zero the BASE, then `vmstate_of!(Self, migration_state)` seems
> can't migrate its fields.

I think the following generated vmstate implementation should be what we
need:

diff --git a/rust/qemu-macros/src/migration_state.rs 
b/rust/qemu-macros/src/migration_state.rs
index 5edf0efe687f..cb047638e3da 100644
--- a/rust/qemu-macros/src/migration_state.rs
+++ b/rust/qemu-macros/src/migration_state.rs
@@ -1,6 +1,6 @@
 use std::borrow::Cow;

-use proc_macro2::TokenStream;
+use proc_macro2::{Literal, TokenStream};
 use quote::{format_ident, quote, ToTokens};
 use syn::{spanned::Spanned, DeriveInput, Error, Field, Ident, Result, Type};

@@ -236,6 +236,43 @@ pub struct #name {
         }
     }

+    fn generate_vmstate_impl(&self) -> TokenStream {
+        let name = self.migration_state_name();
+        let name_str = name.to_string();
+        // Most of the time, const variables use uppercase snake case style,
+        // while VMStateDescription.name uses lowercase snake case. But we're
+        // not strictly following the usual snake case conventions here because
+        // what we have is good enough for the generated code right now.
+        //
+        // QEMU struct names are typically in camel case, but there are 
exceptions
+        // - like non-standard camel case such as HPETState. So converting from
+        // camel to snake case would need an extra helper.
+        let vmsd_name = format_ident!("VMSTATE_{}", name_str);
+        // C-string literal "c" can't be used in quote! directly.
+        let vmsd_c_name = 
Literal::c_string(&std::ffi::CString::new(name_str).unwrap());
+
+        let vmstate_fields = self.fields.iter().map(|field| {
+            let field_name = &field.name;
+            quote! {
+                vmstate_of!(#name, #field_name),
+            }
+        });
+
+        quote! {
+            const #vmsd_name: VMStateDescription<#name> =
+                VMStateDescriptionBuilder::<#name>::new()
+                    .name(#vmsd_c_name)
+                    .version_id(0)
+                    .minimum_version_id(0)
+                    .fields(vmstate_fields! {
+                        #(#vmstate_fields)*
+                    })
+                    .build();
+
+            impl_vmstate_struct!(#name, #vmsd_name);
+        }
+    }
+
     fn generate_snapshot_migration_state(&self) -> TokenStream {
         let fields = self
             .fields
@@ -275,12 +312,15 @@ fn generate(&self) -> TokenStream {
         let (impl_generics, ty_generics, where_clause) = 
generics.split_for_impl();
         let name = self.migration_state_name();
         let migration_state_struct = self.generate_migration_state_struct();
+        let vmstate_impl = self.generate_vmstate_impl();
         let snapshot_impl = self.generate_snapshot_migration_state();
         let restore_impl = self.generate_restore_migrated_state();

         quote! {
             #migration_state_struct

+            #vmstate_impl
+
             impl #impl_generics ToMigrationState for #struct_name #ty_generics 
#where_clause {
                 type Migrated = #name;

diff --git a/rust/qemu-macros/src/tests.rs b/rust/qemu-macros/src/tests.rs
index 65691412ff57..d70ebf23c273 100644
--- a/rust/qemu-macros/src/tests.rs
+++ b/rust/qemu-macros/src/tests.rs
@@ -408,6 +408,20 @@ pub struct CustomMigration {
                 pub nested_field: <NestedStruct as ToMigrationState>::Migrated,
                 pub simple_field: <u32 as ToMigrationState>::Migrated,
             }
+            const VMSTATE_CustomMigration: VMStateDescription 
<CustomMigration> =
+                VMStateDescriptionBuilder::<CustomMigration>::new()
+                    .name(c"CustomMigration")
+                    .version_id(0)
+                    .minimum_version_id(0)
+                    .fields(vmstate_fields! {
+                        vmstate_of!(CustomMigration, shared_data),
+                        vmstate_of!(CustomMigration, converted_field),
+                        vmstate_of!(CustomMigration, fallible_field),
+                        vmstate_of!(CustomMigration, nested_field),
+                        vmstate_of!(CustomMigration, simple_field),
+                    })
+                    .build();
+            impl_vmstate_struct!(CustomMigration, VMSTATE_CustomMigration);
             impl ToMigrationState for MyStruct {
                 type Migrated = CustomMigration;
                 fn snapshot_migration_state(



Reply via email to