How to generate a new struct using a derive macro that inherits the parent struct's derive implementations of traits

Hi,

I'd like to generate structs from other structs using a derive macro. Specifically I'd like to generate AUpdate from A like in the example below.

#[derive(Copy, Clone, UpdateStruct)]
pub(crate) struct A {
    one: u32,
}

#[derive(Copy, Clone)]
pub(crate) struct B {
    a_update: AUpdate,
}

pub fn main() {
    let a = A { one: 10 };
    let a_update = AUpdate { one_update: 10 };
}

I have a macro to do this (see below) but the issue I'm having is implementing / inheriting the derived traits for A (in this case Copy and Clone) so that AUpdate also implements them.

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};

// Procedural macro definition
#[proc_macro_derive(UpdateStruct)]
pub fn derive_update(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);

    let name = input.ident;
    let visibility = input.vis;

    let update_name = syn::Ident::new(&format!("{}Update", name), name.span());

    // Extract the fields of the struct
    let fields = if let syn::Data::Struct(data_struct) = input.data {
        data_struct.fields
    } else {
        panic!("#[derive(UpdateStruct)] is only supported for structs");
    };

    let update_fields = fields.iter().filter_map(|field| {
        if let Some(field_name) = &field.ident {
            let field_type = &field.ty;
            let updated_field_name =
                syn::Ident::new(&format!("{}_update", field_name), field_name.span());
            Some(quote! {
                pub #updated_field_name : #field_type
            })
        } else {
            None
        }
    });

    let expanded = quote! {
        // The generated AUpdate struct
        #visibility struct #update_name {
            #(#update_fields),*
        }
    };

    expanded.into()
}

I can see that input has the attrs field but I haven't been able to make any progress in using them. Any help would be greatly appreciated!

Many thanks

I could be wrong, but if I recall correctly, this is very delicate regarding the attribute orders (thus I don't recommend it: rustfmt will break it). try to experiment with it yourself, e.g. compare the difference between something like:

#[derive(UpdateStruct)]
#[derive(Copy, Clone)]
struct A {}

#[derive(Copy, Clone)]
#[derive(UpdateStruct)]
struct A {}

#[derive(Copy)]
#[derive(UpdateStruct)]
#[derive(Clone)]
struct A {}

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.