0

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.

lesurp
  • 343
  • 4
  • 19
  • 1
    Possible duplicate of [Is it possible to store state within Rust's procedural macros?](https://stackoverflow.com/questions/52910783/is-it-possible-to-store-state-within-rusts-procedural-macros) – Stargateur Jul 21 '19 at 18:16
  • Note that the linked question is about storing state *between* macro calls, while I'm trying to save state *within* one (I basically want to do two passes over the arguments). – lesurp Jul 22 '19 at 08:15
  • Ah, actually, that is the kind of thing you could do with a proc macro (though not with `macro_rules`, and not with the syntax you're using). I'm retracting my close vote – trent Jul 22 '19 at 09:31

1 Answers1

0

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!

lesurp
  • 343
  • 4
  • 19