genericsruststructrust-proc-macros

How can I use derive macro on a generic struct?


I'm working on implementing dynamic listeners for the communication layer of my embedded program. I want to store a Vec<ReaderContext<T>> in my Reader structure. Since T can change, I need to hide it behind a trait: Vec<Box<dyn AnyReaderContext>> (following this SO question.)

I tried to follow the how-to-write-a-custom-derive-macro guide of the rust book, and I have the following minimal code:

any_reader_context and any_reader_context_derive crates compile properly.

Main crate has the following cryptic compilation error:

$ cargo build
   Compiling any_reader_context v0.1.0 (rust-sandbox/any_reader_context)
   Compiling any_reader_test v0.1.0 (rust-sandbox/any_reader_test)
error[E0107]: missing generics for struct `Reader`
 --> src/main.rs:5:12
  |
5 | pub struct Reader<T> {
  |            ^^^^^^ expected 1 generic argument
  |
note: struct defined here, with 1 generic parameter: `T`
 --> src/main.rs:5:12
  |
5 | pub struct Reader<T> {
  |            ^^^^^^ -
help: add missing generic argument
  |
5 | pub struct Reader<T><T> {
  |                  +++

I tried to add a second <T>, but obviously, the compiler didn't like it:

$ cargo build
   Compiling any_reader_test v0.1.0 (/home/tcravic/workspace/avionics/prototypes/rust-sandbox/any_reader_test)
error: expected `where`, `{`, `(`, or `;` after struct name, found `<`
 --> src/main.rs:5:21
  |
5 | pub struct Reader<T><T> {
  |                     ^ expected `where`, `{`, `(`, or `;` after struct name

Can anyone help with this one?


Solution

  • You completely ignore the generics which you simply can't do. You could simply forward them from the ast :

    fn impl_any_reader_context(ast: &syn::DeriveInput) -> TokenStream {
        let name = &ast.ident;
        let (impl_generics, type_generics, where_clause) = ast.generics.split_for_impl();
        let gen = quote! {
            impl #impl_generics AnyReaderContext for #name #type_generics #where_clause {
                fn my_derived_function() {
                    println!("Hello, Macro! My name is {}!", stringify!(#name));
                }
            }
        };
        gen.into()
    }