How do I create a custom attribute that will be consumed by a custom derive macro?

Hello,
I have a struct with a custom derive macro. In the derive macro, I would like to inject slightly different code based on a custom attribute set to the fields of my struct. I think I have the generation part, but rustc complains that my attribute doesn't exist, so I think I also need to somehow register that this attribute exists.

The following code is a simplification of what I wrote, but the idea is the same.

trait MyDerive {
    fn foo(&self) -> usize;
}

#[derive(Debug, MyDeriveMacro)]
struct MyStruct {
    #[MyAttribute = 1]
    pub field_1: usize,
    #[MyAttribute = 2]
    pub field_2: usize,
}

I have a trait, and I want to automatically get an implementation by just adding #[derive(MyDeriveMacro) to a struct. I already managed to do this. However, I also want to be able to do something special based on the value of a custom attribute MyAttribute when generating the implementation of MyDerive::foo(). How do I tell rustc that MyAttribute is a valid attribute?

bin/main.rs|50 col 7 error| cannot find attribute `MyAttribute` in this scope
||    |
|| 50 |     #[MyAttribute = 1]
||    |       ^^^^^^^^^^^

For reference, the derive code I wrote is (more or less, I hope I didn't mess-up things when simplifying it):

fn impl_my_derive(ast: &syn::DeriveInput) -> TokenStream {
    let name = &ast.ident;

    let data_struct = match &ast.data {
        syn::Data::Struct(data_struct) => data_struct,
        _ => unimplemented!()
    };

    let mut generated_code = quote!();
    match &data_struct.fields {
        syn::Fields::Named(named) => for field in named.named.iter() {
            let name = field.ident.as_ref().unwrap();
            let number = field.attrs.iter().filter_map(|attr| {
                match attr.parse_meta() {
                    Result::Ok(syn::Meta::NameValue(attr)) if attr.path.is_ident("MyAttribute") => Some(attr.lit),
                    _ => None,
                }
            }).nth(0);
            generated_code.extend(quote!(
                #number,
            ));
        }
        _ => unimplemented!()
    }

    let gen = quote! {
        impl MyDeriveMacro for #name {
            fn foo(&self) -> usize {
                vec![#number].iter().sum()
            }
        }
    };
    gen.into()
}

I found it by reading the serde_derive source code!

At the top of your entry point for the derive macro, in addition to

#[proc_macro_derive(RuleSystem, attributes(Dice))]

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.