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:
Crate
any_reader_context# Cargo.toml [package] name = "any_reader_context" version = "0.1.0" edition = "2021"// lib.rs pub trait AnyReaderContext { fn my_derived_function(); }Crate
any_reader_context_derive# Cargo.toml [package] name = "any_reader_context_derive" version = "0.1.0" edition = "2021" [lib] proc-macro = true [dependencies] syn = "2.0.26" quote = "1.0"// lib.rs use proc_macro::TokenStream; use quote::quote; use syn; #[proc_macro_derive(AnyReaderContext)] pub fn any_reader_context_derive(input: TokenStream) -> TokenStream { let ast = syn::parse(input).unwrap(); // Build the trait implementation impl_any_reader_context(&ast) } fn impl_any_reader_context(ast: &syn::DeriveInput) -> TokenStream { let name = &ast.ident; let gen = quote! { impl AnyReaderContext for #name { fn my_derived_function() { println!("Hello, Macro! My name is {}!", stringify!(#name)); } } }; gen.into() }Main crate
# Cargo.toml [package] name = "any_reader_test" version = "0.1.0" edition = "2021" [dependencies] any_reader_context = { path = "../any_reader_context" } any_reader_context_derive = { path = "../any_reader_context_derive" }// main.rs use any_reader_context_derive::AnyReaderContext; use any_reader_context::AnyReaderContext; #[derive(AnyReaderContext)] pub struct Reader<T> { value: T } impl<T> Reader<T> { fn new(value: T) -> Self { Self {value} } } fn main() { let readers: Vec<Box<dyn AnyReaderContext>> = vec![]; readers.push(Reader::<u32>::new(42)); }
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?
You completely ignore the generics which you simply can't do. You could simply forward them from the
ast: