In procedural macro quote!(a == b) produces a = = b.
This can be fixed by using a.eq(b) instead.
The other thing is that compiler disallows usage of if at all:
macro expansion ignores token `if` and any following
Only if used in match pattern.
// macro
#[proc_macro]
pub fn foo(input: TokenStream) -> TokenStream {
return quote::quote!(_ if a == b).into();
}
// usage
let a = 1;
let b = 2;
match 1 {
//expands to: _ if a = = b
// if fixed, gives error: "macro expansion ignores token `if` and any following"
foo!() => {
println!("matched");
}
}
A macro invocation expands a macro at compile time and replaces the invocation with the result of the macro. Macros may be invoked in the following situations:
I would assume that the observation that quote!(a == b) appear to result in two not joined tokens = = is probably only a side-effect of the above-mentioned main issue, and that in context where an expression is actually expected, a quote’d a == b should work fine and as expected.
Ok. Thank you for the clear explanation of what is going on.
Every time I use Rust macros I always stumble upon some unexpected limitations.
I have a enum like this:
pub enum Element {
Str(Cow<'static, str>),
Num(i32),
}
I want to match against a slice of such elements and also be able to capture variables. That's hard because of the Cow. But also I would like syntax to be even shorter, like ["foo", 10, Str(name), Id(id)] or ["foo", 10, $name, @id].
The initial plan was to generate code like this:
[Str(str0), Num(10), Str(name), Num(id)] if str0 == "foo"
It’s solvable if the macro expands to the whole match. Or for an even more advanced solution, an attribute macro that handles a whole block or function and re-writes all matches containing foo!().
Maybe a bit too much effort though for a small use-case; I’ve just thought a bit about what would go into a general framework (for the latter approach) for more easily defining macros like that – maybe I’ll try giving implementing a helper crate a go, in case I get back to this on the weekend.