I'd like to create a macro that operates on a given list of types, but I need to be able to store which other types are being processed.
A simple example of something I want to do:
struct Foo;
struct Bar {
foo: Foo,
data: u32,
}
baz!(Foo, Bar);
// outputs
struct OptFoo;
struct OptBar {
foo: OptFoo,
data: u32
}
The problem is that it doesn't seem like macro_rules
allows me to store a temporary state (i.e a HashSet
where I would tag which types are part of the macro invocation). The only workaround I have in mind is to write what I want as a proc_macro_derive
and manually adding a custom attribute for each type I need but that's obviously far from perfect...
Edit:
The question is similar to this one, but here I'mm trying to save a state locally and temporarily (basically doing two passes over the arguments while storing data about those) in a single macro call. However it seems it's also not possible.
As pointed by @trentcl, what I want to achieve is indeed possible with proc macro (I thought proc macros were limited to Derive
and attributes...)
#[proc_macro]
pub fn generate(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = proc_macro2::TokenStream::from(input);
println!("{:?}", input);
proc_macro::TokenStream::from(input)
}
generate!(struct Foo;);
// outputs its argument without changing anything, i.e:
// struct Foo ;
The previous example demonstrates a trivial macro that prints to sdout the parsed input: TokenStream [Ident { ident: "struct", span: #0 bytes(330..336) }, Ident { ident: "Foo", span: #0 bytes(337..340) }, Punct { ch: ';', spacing: Alone, span: #0 bytes(340..341) }]
Note that it parses the tokens but does not create an AST; we'll have to use syn
for that.
This repo has examples many of what can be done with proc macros, pretty helpful!