1Rust Quasi-Quoting 2================== 3 4[<img alt="github" src="https://img.shields.io/badge/github-dtolnay/quote-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/dtolnay/quote) 5[<img alt="crates.io" src="https://img.shields.io/crates/v/quote.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/quote) 6[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-quote-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/quote) 7[<img alt="build status" src="https://img.shields.io/github/actions/workflow/status/dtolnay/quote/ci.yml?branch=master&style=for-the-badge" height="20">](https://github.com/dtolnay/quote/actions?query=branch%3Amaster) 8 9This crate provides the [`quote!`] macro for turning Rust syntax tree data 10structures into tokens of source code. 11 12[`quote!`]: https://docs.rs/quote/1.0/quote/macro.quote.html 13 14Procedural macros in Rust receive a stream of tokens as input, execute arbitrary 15Rust code to determine how to manipulate those tokens, and produce a stream of 16tokens to hand back to the compiler to compile into the caller's crate. 17Quasi-quoting is a solution to one piece of that — producing tokens to 18return to the compiler. 19 20The idea of quasi-quoting is that we write *code* that we treat as *data*. 21Within the `quote!` macro, we can write what looks like code to our text editor 22or IDE. We get all the benefits of the editor's brace matching, syntax 23highlighting, indentation, and maybe autocompletion. But rather than compiling 24that as code into the current crate, we can treat it as data, pass it around, 25mutate it, and eventually hand it back to the compiler as tokens to compile into 26the macro caller's crate. 27 28This crate is motivated by the procedural macro use case, but is a 29general-purpose Rust quasi-quoting library and is not specific to procedural 30macros. 31 32```toml 33[dependencies] 34quote = "1.0" 35``` 36 37*Version requirement: Quote supports rustc 1.56 and up.*<br> 38[*Release notes*](https://github.com/dtolnay/quote/releases) 39 40<br> 41 42## Syntax 43 44The quote crate provides a [`quote!`] macro within which you can write Rust code 45that gets packaged into a [`TokenStream`] and can be treated as data. You should 46think of `TokenStream` as representing a fragment of Rust source code. 47 48[`TokenStream`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.TokenStream.html 49 50Within the `quote!` macro, interpolation is done with `#var`. Any type 51implementing the [`quote::ToTokens`] trait can be interpolated. This includes 52most Rust primitive types as well as most of the syntax tree types from [`syn`]. 53 54[`quote::ToTokens`]: https://docs.rs/quote/1.0/quote/trait.ToTokens.html 55[`syn`]: https://github.com/dtolnay/syn 56 57```rust 58let tokens = quote! { 59 struct SerializeWith #generics #where_clause { 60 value: &'a #field_ty, 61 phantom: core::marker::PhantomData<#item_ty>, 62 } 63 64 impl #generics serde::Serialize for SerializeWith #generics #where_clause { 65 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 66 where 67 S: serde::Serializer, 68 { 69 #path(self.value, serializer) 70 } 71 } 72 73 SerializeWith { 74 value: #value, 75 phantom: core::marker::PhantomData::<#item_ty>, 76 } 77}; 78``` 79 80<br> 81 82## Repetition 83 84Repetition is done using `#(...)*` or `#(...),*` similar to `macro_rules!`. This 85iterates through the elements of any variable interpolated within the repetition 86and inserts a copy of the repetition body for each one. The variables in an 87interpolation may be a `Vec`, slice, `BTreeSet`, or any `Iterator`. 88 89- `#(#var)*` — no separators 90- `#(#var),*` — the character before the asterisk is used as a separator 91- `#( struct #var; )*` — the repetition can contain other things 92- `#( #k => println!("{}", #v), )*` — even multiple interpolations 93 94Note that there is a difference between `#(#var ,)*` and `#(#var),*`—the latter 95does not produce a trailing comma. This matches the behavior of delimiters in 96`macro_rules!`. 97 98<br> 99 100## Returning tokens to the compiler 101 102The `quote!` macro evaluates to an expression of type 103`proc_macro2::TokenStream`. Meanwhile Rust procedural macros are expected to 104return the type `proc_macro::TokenStream`. 105 106The difference between the two types is that `proc_macro` types are entirely 107specific to procedural macros and cannot ever exist in code outside of a 108procedural macro, while `proc_macro2` types may exist anywhere including tests 109and non-macro code like main.rs and build.rs. This is why even the procedural 110macro ecosystem is largely built around `proc_macro2`, because that ensures the 111libraries are unit testable and accessible in non-macro contexts. 112 113There is a [`From`]-conversion in both directions so returning the output of 114`quote!` from a procedural macro usually looks like `tokens.into()` or 115`proc_macro::TokenStream::from(tokens)`. 116 117[`From`]: https://doc.rust-lang.org/std/convert/trait.From.html 118 119<br> 120 121## Examples 122 123### Combining quoted fragments 124 125Usually you don't end up constructing an entire final `TokenStream` in one 126piece. Different parts may come from different helper functions. The tokens 127produced by `quote!` themselves implement `ToTokens` and so can be interpolated 128into later `quote!` invocations to build up a final result. 129 130```rust 131let type_definition = quote! {...}; 132let methods = quote! {...}; 133 134let tokens = quote! { 135 #type_definition 136 #methods 137}; 138``` 139 140### Constructing identifiers 141 142Suppose we have an identifier `ident` which came from somewhere in a macro 143input and we need to modify it in some way for the macro output. Let's consider 144prepending the identifier with an underscore. 145 146Simply interpolating the identifier next to an underscore will not have the 147behavior of concatenating them. The underscore and the identifier will continue 148to be two separate tokens as if you had written `_ x`. 149 150```rust 151// incorrect 152quote! { 153 let mut _#ident = 0; 154} 155``` 156 157The solution is to build a new identifier token with the correct value. As this 158is such a common case, the `format_ident!` macro provides a convenient utility 159for doing so correctly. 160 161```rust 162let varname = format_ident!("_{}", ident); 163quote! { 164 let mut #varname = 0; 165} 166``` 167 168Alternatively, the APIs provided by Syn and proc-macro2 can be used to directly 169build the identifier. This is roughly equivalent to the above, but will not 170handle `ident` being a raw identifier. 171 172```rust 173let concatenated = format!("_{}", ident); 174let varname = syn::Ident::new(&concatenated, ident.span()); 175quote! { 176 let mut #varname = 0; 177} 178``` 179 180### Making method calls 181 182Let's say our macro requires some type specified in the macro input to have a 183constructor called `new`. We have the type in a variable called `field_type` of 184type `syn::Type` and want to invoke the constructor. 185 186```rust 187// incorrect 188quote! { 189 let value = #field_type::new(); 190} 191``` 192 193This works only sometimes. If `field_type` is `String`, the expanded code 194contains `String::new()` which is fine. But if `field_type` is something like 195`Vec<i32>` then the expanded code is `Vec<i32>::new()` which is invalid syntax. 196Ordinarily in handwritten Rust we would write `Vec::<i32>::new()` but for macros 197often the following is more convenient. 198 199```rust 200quote! { 201 let value = <#field_type>::new(); 202} 203``` 204 205This expands to `<Vec<i32>>::new()` which behaves correctly. 206 207A similar pattern is appropriate for trait methods. 208 209```rust 210quote! { 211 let value = <#field_type as core::default::Default>::default(); 212} 213``` 214 215<br> 216 217## Hygiene 218 219Any interpolated tokens preserve the `Span` information provided by their 220`ToTokens` implementation. Tokens that originate within a `quote!` invocation 221are spanned with [`Span::call_site()`]. 222 223[`Span::call_site()`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.Span.html#method.call_site 224 225A different span can be provided explicitly through the [`quote_spanned!`] 226macro. 227 228[`quote_spanned!`]: https://docs.rs/quote/1.0/quote/macro.quote_spanned.html 229 230<br> 231 232## Non-macro code generators 233 234When using `quote` in a build.rs or main.rs and writing the output out to a 235file, consider having the code generator pass the tokens through [prettyplease] 236before writing. This way if an error occurs in the generated code it is 237convenient for a human to read and debug. 238 239Be aware that no kind of hygiene or span information is retained when tokens are 240written to a file; the conversion from tokens to source code is lossy. 241 242Example usage in build.rs: 243 244```rust 245let output = quote! { ... }; 246let syntax_tree = syn::parse2(output).unwrap(); 247let formatted = prettyplease::unparse(&syntax_tree); 248 249let out_dir = env::var_os("OUT_DIR").unwrap(); 250let dest_path = Path::new(&out_dir).join("out.rs"); 251fs::write(dest_path, formatted).unwrap(); 252``` 253 254[prettyplease]: https://github.com/dtolnay/prettyplease 255 256<br> 257 258#### License 259 260<sup> 261Licensed under either of <a href="LICENSE-APACHE">Apache License, Version 2622.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option. 263</sup> 264 265<br> 266 267<sub> 268Unless you explicitly state otherwise, any contribution intentionally submitted 269for inclusion in this crate by you, as defined in the Apache-2.0 license, shall 270be dual licensed as above, without any additional terms or conditions. 271</sub> 272