When working with quote, I have code similar to this quite often:
let values = some_iter.map(|x| x.fn_returning_result()).collect::<Result<Box<_>, _>()?;
quote!({
// some stuff omitted
#(#values),*
})
It seems a bit wasteful to allocate a Box here, just to throw it away again immediately after quote! is done. This would work, but panic instead of returning the Err:
let values = some_iter.map(|x| x.fn_returning_result().unwrap());
quote!({
// some stuff omitted
#(#values),*
})
I understand that iterators are lazy and therefore, returning from the let values ... line is not possible for the second example - but is there something that would allow me to do this when playing together with quote?
I see. You want to collect into a Result of iterators, or something like this. But collect() can only be done into a collection that it allocates, and that's a boxed slice Box<[...]> in the OP sample code.
The problem is that ToToken is only implemented on a few primitive types, and Result is not one of them.
Since you are allocating a TokenStream anyway, you can use a loop and "collect" into it by appending tokens while parsing [1]:
let mut quoted = TokenStream::new();
// some stuff omitted
for value in values {
let value = value?;
quoted.append_all(quote!(#value,));
}
In other words, use an explicit loop instead of the implicit loop with the #(...)* repetition syntax. Then you can trivially use the ? operator.
This example expects an iterator has been created elsewhere, and it does the parsing internally. You might as well inline the parsing instead, if you can. ↩︎
Hrm, yeah, that would work - it's not the most pretty because there's also a bit of nesting going on etc. I wonder if there even could be another way? Probably not without a change to quote?