How can we use vectors to generate code in quote macro while `ToTokens` implementation for it is not satisfied?

Imagine a simplest derive macro function:

fn bar_derive_macro(item: TokenStream) -> TokenStream {
  let elms = vec!["a", "b", "c"];

  quote! {
    impl Foo {
      fn bar(&self) -> Vec<&'static str>

This code might be wrong, just drafted something to prove my point.

Looking at ToTokens trait, many types are implemented but I cannot see Vec implementing ToTokens.

So, how does quote! turn each element into a Token in a Vec if it doesn't implement ToTokens?

Looking a bit closer, I have realized that it works because we actually unpack (?) elms inside quote! using #(#(elms),*). So, anything iterable can be unpacked, (Verify me if I'm on point please.)

But, what about HashMaps then? HashMap is also iterable, but its type is a little bit complicated since it has keys and values. So, how would this code look like if elms was a HashMap<&'static str, &'static str>?

Thanks in advance.

Have you looked into the options for creating an HashMap<K, V> and filling it with entries using.. just Rust code?

Welp, seems like I've written something about this before. My dummy brain.

Sorry, I'll go from there, thanks for reply.

You are explicitly adding a repeat expansion #(…)*. The Vec merely needs to be IntoIterator, only its items must be ToTokens.

Accordingly, this compiles, if you fix the syntax error in the repeat unquote expression.

Of course, all of this is clearly documented.

If you think about it: collections couldn't realistically be ToTokens, because repeat expressions can contain arbitrary interspersed tokens. If Vec appended the contents of every item in one go to the end of the target TokenStream, then how would it be possible to do something like your example, where items are comma-separated?

1 Like