diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2024-12-11 11:48:44 +0100 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2025-01-10 23:34:43 +0100 |
commit | e3ff5a17aa9fc2420197403e69876db48e390ee4 (patch) | |
tree | 232600e01639e974f51173eeb1a337f6876c52b0 /rust | |
parent | 20f0b8e98b4851bfd52bbb4edd4b602d08b9b817 (diff) | |
download | qemu-e3ff5a17aa9fc2420197403e69876db48e390ee4.zip qemu-e3ff5a17aa9fc2420197403e69876db48e390ee4.tar.gz qemu-e3ff5a17aa9fc2420197403e69876db48e390ee4.tar.bz2 |
rust: macros: check that the first field of a #[derive(Object)] struct is a ParentField
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'rust')
-rw-r--r-- | rust/qemu-api-macros/src/lib.rs | 46 |
1 files changed, 27 insertions, 19 deletions
diff --git a/rust/qemu-api-macros/src/lib.rs b/rust/qemu-api-macros/src/lib.rs index 160b283..0f04cca 100644 --- a/rust/qemu-api-macros/src/lib.rs +++ b/rust/qemu-api-macros/src/lib.rs @@ -19,6 +19,27 @@ impl From<CompileError> for proc_macro2::TokenStream { } } +fn get_fields<'a>( + input: &'a DeriveInput, + msg: &str, +) -> Result<&'a Punctuated<Field, Comma>, CompileError> { + if let Data::Struct(s) = &input.data { + if let Fields::Named(fs) = &s.fields { + Ok(&fs.named) + } else { + Err(CompileError( + format!("Named fields required for {}", msg), + input.ident.span(), + )) + } + } else { + Err(CompileError( + format!("Struct required for {}", msg), + input.ident.span(), + )) + } +} + fn is_c_repr(input: &DeriveInput, msg: &str) -> Result<(), CompileError> { let expected = parse_quote! { #[repr(C)] }; @@ -36,7 +57,12 @@ fn derive_object_or_error(input: DeriveInput) -> Result<proc_macro2::TokenStream is_c_repr(&input, "#[derive(Object)]")?; let name = &input.ident; + let parent = &get_fields(&input, "#[derive(Object)]")?[0].ident; + Ok(quote! { + ::qemu_api::assert_field_type!(#name, #parent, + ::qemu_api::qom::ParentField<<#name as ::qemu_api::qom::ObjectImpl>::ParentType>); + ::qemu_api::module_init! { MODULE_INIT_QOM => unsafe { ::qemu_api::bindings::type_register_static(&<#name as ::qemu_api::qom::ObjectImpl>::TYPE_INFO); @@ -53,30 +79,12 @@ pub fn derive_object(input: TokenStream) -> TokenStream { TokenStream::from(expanded) } -fn get_fields(input: &DeriveInput) -> Result<&Punctuated<Field, Comma>, CompileError> { - if let Data::Struct(s) = &input.data { - if let Fields::Named(fs) = &s.fields { - Ok(&fs.named) - } else { - Err(CompileError( - "Cannot generate offsets for unnamed fields.".to_string(), - input.ident.span(), - )) - } - } else { - Err(CompileError( - "Cannot generate offsets for union or enum.".to_string(), - input.ident.span(), - )) - } -} - #[rustfmt::skip::macros(quote)] fn derive_offsets_or_error(input: DeriveInput) -> Result<proc_macro2::TokenStream, CompileError> { is_c_repr(&input, "#[derive(offsets)]")?; let name = &input.ident; - let fields = get_fields(&input)?; + let fields = get_fields(&input, "#[derive(offsets)]")?; let field_names: Vec<&Ident> = fields.iter().map(|f| f.ident.as_ref().unwrap()).collect(); let field_types: Vec<&Type> = fields.iter().map(|f| &f.ty).collect(); let field_vis: Vec<&Visibility> = fields.iter().map(|f| &f.vis).collect(); |