# A fast code generation macro
Easily & efficiently generate code by quoting it:
```rust
use proc_macro2::TokenStream;
use quote_into::quote_into;
let mut stream = TokenStream::new();
quote_into!(stream += println!("hello world!"));
assert_eq!(stream.to_string(), "println ! (\"hello world!\")");
```
## Variable interpolation
You can interpolate any value that implements `ToTokens` using the variable's name prefixed with `#`:
```rust
use proc_macro2::TokenStream;
use quote_into::quote_into;
let mut stream = TokenStream::new();
let variable = false;
quote_into!(stream += let boolean = #variable;);
assert_eq!(stream.to_string(), "let boolean = false ;");
```
## Interpolation blocks
You can insert a block of Rust code using `#{}`. Inside, you can make function calls, use conditionals, or loops, or anything else allowed in a code block.
```rust
use proc_macro2::TokenStream;
use quote_into::quote_into;
let mut stream = TokenStream::new();
quote_into!(stream += let array = [#{
for i in 0..3 {
quote_into!(stream += Some(#i),)
}
}];);
assert_eq!(stream.to_string(), "let array = [Some (0i32) , Some (1i32) , Some (2i32) ,] ;");
```
Note: if you have a group in the quoted tokens (such as `{}`, `()`, or `[]`), a new `TokenStream` is created. In the example above, the outer `stream` is not the same as the `stream` inside the `#{}` interpolation, since it is wrapped in `[]`.
## Expression interpolation
You can also interpolate any Rust expression using `#()`:
```rust
use proc_macro2::TokenStream;
use quote_into::quote_into;
let mut s = TokenStream::new();
quote_into!(s += const ANSWER: u32 = #(7 * 6););
assert_eq!(s.to_string(), "const ANSWER : u32 = 42i32 ;");
```
# Comparison with `quote`
The de-facto standard for code generation is the [`quote`](https://crates.io/crates/quote) crate. This crate proposes small improvements to its API and performance.
## API
Quote seems to be largely inspired by `macro_rules` when it comes to loop interpolations. While expressive and concise, they are a bit hard to learn and read in my opinion.
Instead, `quote_into` provides a simple "interpolation block" `#{ }` where you can write regular Rust code. Since there is basically no additional syntax, using interpolation blocks should feel more intuitive.
## Performance
`quote` returns a new `TokenStream`, while `quote_into` accepts a `TokenStream` to append tokens to. While this makes `quote` a bit less verbose, it's also slightly less efficient when it comes to combining quoted fragments. Often, code generation happens in different functions which are then combined. The recommended way to do this is to create intermediate `TokenStream`s, and interpolate them using `#`:
```rust
use quote::quote;
let type_definition = quote! {...};
let methods = quote! {...};
let tokens = quote! {
#type_definition
#methods
};
```
The additional allocations have a small performance impact even if you only create a few `TokenStreams` and combine them. A more extreme case is a deeply recursive function, which repeatedly constructs and interpolates many token streams. For example, consider the below functions, which generate code of the form `Box<Box<...<bool>>>`:
```rust
use quote::quote;
use quote_into::quote_into;
use proc_macro2::TokenStream;
// Using quote:
fn quote_box_wrap(levels: usize) -> TokenStream {
match levels {
0 => quote!(bool),
other => {
let inner = quote_box_wrap(other - 1);
quote!(Box<#inner>)
}
}
}
// Using quote_into:
fn quote_into_box_wrap(levels: usize) -> TokenStream {
fn inner(s: &mut TokenStream, levels: usize) {
match levels {
0 => quote_into!(s += bool),
other => quote_into! {s += Box < #{
inner(s, other - 1)
} >},
}
}
// there's a bit of boilerplate, but only once per macro
let mut s = TokenStream::new();
inner(&mut s, levels);
s
}
```
Results for `levels=100`:
```text
quote: 591.14 µs
quote_into: 17.247 µs
```
Since the version using `quote` has to create many intermediate `TokenStreams`, it is much slower in this case. Again, this is an extreme example. It's unlikely your code generation will actually be 30x faster if you switch to `quote_into`, unless you're inefficiently nesting interpolated `TokenStreams` several levels deep as above.
# Status: prototype
While you can technically use `quote_into` in your projects, it's only in the prototype stage.
- The API is subject to change, as there are a few things I'm unsure about
- It's implemented using `quote`... I'm not sure how "bad" this is (it might increase compile times), but I have a feeling it should be rewritten using manual token generation code at some point.