Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option<T> repetitions do not work #213

Open
lroux-at-jellysmack opened this issue Mar 24, 2022 · 3 comments
Open

Option<T> repetitions do not work #213

lroux-at-jellysmack opened this issue Mar 24, 2022 · 3 comments

Comments

@lroux-at-jellysmack
Copy link

Hello,

While trying to do the following thing,

fn test(option: Option<TokenStream>) -> TokenStream {
    quote! {
        #(#option)*
    }
}

it gives me the following error:

expected struct `HasIterator`, found struct `ThereIsNoIteratorInRepetition`

The type Option<T> does not work in repetitions (#()*), while stated otherwise in the README.md here, since Option<T> implements IntoIterator.

I also found something stating the inverse here:

The variables in an interpolation may be a Vec, slice, BTreeSet, or any Iterator.

I ended up fixing my code by doing this:

 fn test(option: Option<TokenStream>) -> TokenStream {
+    let option = option.iter();
     quote! {
         #(#option)*
     }
 }

Also I have a few questions:

  • What could I do to recreate the optional behavior of declarative macros using $()?, since #()* does not work out of the box ?
  • Could this IntoIterator mechanism be introduced in order to achieve this without requiring .iter() everywhere ?

Thanks :)

@ahl
Copy link

ahl commented Aug 10, 2022

This may not address your actual use, but you can just do

fn test(option: Option<TokenStream>) -> TokenStream {
    quote! {
        #option
    }
}

This precludes other fancy stuff you might want to do inside the #( ... )* repetition specifier.

Agreed that the docs appear to be inaccurate based on the current implementation:

/// Extension trait providing the `quote_into_iter` method on iterators.

@coolreader18
Copy link

This might count as a breaking change, but what if there was a #( #var )? optionality specifier? Basically the same as #()* but expecting the variable to be an option

@cyqsimon
Copy link

cyqsimon commented Nov 6, 2023

Ran into this problem today with a vector of options. Confused the heck out of me. Ended up doing this. Not particularly pretty but it works.

let vec_of_options: Vec<Option<String>> = vec![/* stuff */];
let vec_of_options_tokenised: Vec<TokenStream> = vec_of_options
    .into_iter()
    .map(|opt| match opt {
        Some(text) => quote! { Some(#text) },
        None => quote! { None },
    })
    .collect();
// in quote macro, use `vec_of_options_tokenised` instead of `vec_of_options`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants