dtolnay / quote

Rust quasi-quoting
Apache License 2.0
1.32k stars 90 forks source link

How to do nested interpolation for vectors? #227

Closed ozgunozerk closed 1 year ago

ozgunozerk commented 2 years ago

I'm unable to do nested interpolation for vectors.

let types: Vec<proc_macro2::Ident> = vec![
    syn::parse_str("u8").unwrap(),
    syn::parse_str("u16").unwrap(),
    syn::parse_str("u32").unwrap(),
];
let names: Vec<proc_macro2::Ident> = vec![
    syn::parse_str("Hi").unwrap(),
    syn::parse_str("Hey").unwrap(),
    syn::parse_str("Yo").unwrap(),
];

and using these, I'm trying to generate the following:

pub enum Trial {
    Hi(u8, u16, u32),
    Hey(u8, u16, u32),
    Yo(u8, u16, u32),
    Finished,
    Cancelled,
}

The code I'm using to generate this:

quote! {
    pub enum Trial {
        #(#names(#(#types),*)),*,
        Finished,
        Cancelled,
    }
}

Which does not work, and gives the error mismatched types -> expected struct `HasIterator`, found struct `ThereIsNoIteratorInRepetition`

I'm able to do a single interpolation for both the types, and the names, here is the code:

quote! {
    pub enum Trial {
        Hmm(#(#types),*,),  // -> successful: generates Hmm(u8, u16, u32)
        #(#names()),*,      // -> successful: generates Hi(), Hey(), Yo()
        Finished,
        Cancelled,
    }
}

any help/idea on how to accomplish my goal?

dtolnay commented 1 year ago

You can implement this as:

let types = std::iter::repeat(types);
quote! {
    pub enum Trial {
        #(
            #names(#(#types),*),
        )*
        Finished,
        Cancelled,
    }
}

or as:

let fields = quote!(#(#types),*);
quote! {
    pub enum Trial {
        #(
            #names(#fields),
        )*
        Finished,
        Cancelled,
    }
}