A fast code generation macro

Easily & efficiently generate code by quoting it:

```rust use procmacro2::TokenStream; use quoteinto::quote_into;

let mut stream = TokenStream::new(); quoteinto!(stream += println!("hello world!")); asserteq!(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 procmacro2::TokenStream; use quoteinto::quote_into;

let mut stream = TokenStream::new(); let variable = false; quoteinto!(stream += let boolean = #variable;); asserteq!(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 procmacro2::TokenStream; use quoteinto::quote_into;

let mut stream = TokenStream::new(); quoteinto!(stream += let array = [#{ for i in 0..3 { quoteinto!(stream += Some(#i),) } }];); asserteq!(stream.tostring(), "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 [].

Comparison with quote

The de-facto standard for code generation is the 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 TokenStreams, 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 quoteinto::quoteinto; use proc_macro2::TokenStream;

// Using quote: fn quoteboxwrap(levels: usize) -> TokenStream { match levels { 0 => quote!(bool), other => { let inner = quoteboxwrap(other - 1); quote!(Box<#inner>) } } }

// Using quoteinto: fn quoteintoboxwrap(levels: usize) -> TokenStream { fn inner(s: &mut TokenStream, levels: usize) { match levels { 0 => quoteinto!(s += bool), other => quoteinto! {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.