but when I use this struct inside quote! of my proc macro, I got an error:
error[E0425]: cannot find value `fields_names` in this scope
--> proc_macro\src/lib.rs:91:24
|
91 | #(#fields_names: fields_values),*
| ^^^^^^^^^^^^ not found in this scope
You are mixing up macro compilation and macro expansion time.
When a #metavariable is encountered by quote!, it is substituted into the resulting token stream right away, from the surrounding macro code, when your macro is being compiled. That's the point of quoting.
But you have no fields_names or fields_values variables declared. Those declarations are inside the quote, so they'll be emitted to the expanded code, which is apparently not what you want.
You seem to be referring to all sorts of other variables only found in the generated code from within the quote, as if they were meta-variables (e.g. buffer). From this code alone, this looks like you are completely mixed up between compilation and expansion time, and I can't tell what you are actually trying to achieve.
Whatever code you want to generate, you'll need to emit outside the quote. To be clear, you can't have quote generate different code based on runtime differences in the code invoking the macro. Is that something you need?
That's exactly what I'm saying: you need to move the logic of the if statement out of the quote. You don't want to generate code that contains an if; you want to generate different snippets based on a condition that you macro knows. I.e., instead of
The buffer parameter only exists at the compilation time of the code invoking your macro. It's simply impossible to make code generation decisions based on it in your macro.
But you don't seem to need it, anyway. You seem to want to check if the particular field being expanded is marked. That's none of the business of the generated code. This decision must be made in your macro, while you are generating the code. You probably meant to write this:
As an aside, &Vec<_> as a parameter is harmful (it's no more powerful than &[_] and it forces the caller to allocate a new vector if they have something else that would coerce to a slice just fine). Make that argument a &[u8] instead.
This doesn't have anything to do with "how TokenStream works". A token stream is just a somewhat-lexed-and-parsed representation of text (the raw source string is broken up into lexemes and parenthesis balance is checked). You'd have encountered the exact same problem and solution if macros operated on raw Strings or fully-parsed AST nodes or whatever.
Instead, this has everything to do with the difference between the various phases at which your macro code is processed:
Your macro's code is compiled. It is compiled to code that emits code. It can't, obviously, access runtime values of code it is just about to emit.
Your macro's compiled code is invoked by the compiler. This results in the code that your macro emits.
The output of your macro (the generated code) is pasted into the source code that invoked your macro.
The source code containing the results of your macro expansion is compiled.
The compiled program, with the compiled version of the macro-emitted code is run by whoever you give the executable to.
At steps 4 and 5, your macro is long gone. It has already been compiled and invoked, and it hasn't the faintest choice of altering the emitted code at this point.