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()
}