Procedural macro for structs with/without lifetime annotations

I know how to write a basic procedural macro but I was stuck at how to make a procedural macro work for structs both with and without lifetime annotations. Is there any good and relatively simple example on this?

I'm currently using PhantomData with references inside to make all structs take the same number of lifetime annotations. However, this approach won't work on structs that are not implemented by me.

Can you show an example of the problem you're running into?

Maybe an example macro invocation and what you want it to expand into in the ideal case

I want to write a procedural macro

#[proc_macro_derive(MyTrait)]
pub fn my_trait_derive(input: TokenStream) -> TokenStream {
    let ast = syn::parse(input).unwrap();
    let name = &ast.ident;
    let gen = quote! {
        impl<'me> MyTrait for #name<'me> {
            ...
        }
    };
    gen.into()
}

so that I can use #[derive(MyTrait)] to auto implement MyTrait for some structs, e.g, StructA and StructB.

#[derive(MyTrait)]
struct StructA {
    ...
}

#[derive(MyTrait)]
struct StructB<'me> {
    ...
}

The thing is that StructA does not take lifetime annotations while StructB takes a lifetime annotation. Hard coding lifetime annotations in the implementation of my_trait_derive doesn't work. Neither does it work if I leave out lifetime annotations. What's the best practice here to address the above issue? I know that derive macros can take additional attribute parameters but it's not obvious to me how to use it.

I think you want to look at Generics::split_for_impl. The DeriveInput has a generics field where you can call that from. It is not needed to check for any generics that way, use it everywhere you do an impl and it will only produce tokens if there are generic params.

1 Like

How do I specify generic parameters when using #[derive(...)]?

They're defined on the struct itself

@semicoleon @jfrancis Thank you both very much for your help! I was able to make it work now.