• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

.github/H03-May-2022-5144

benches/H03-May-2022-193189

src/H03-May-2022-2,2921,217

tests/H03-May-2022-646522

.cargo-checksum.jsonH A D03-May-202289 11

.cargo_vcs_info.jsonH A D01-Jan-197094 66

.clippy.tomlH A D29-Nov-197316 21

.gitignoreH A D29-Nov-197320 32

Cargo.tomlH A D01-Jan-19701.2 KiB4036

Cargo.toml.orig-cargoH A D29-Nov-1973911 3025

LICENSE-APACHEH A D29-Nov-197310.6 KiB202169

LICENSE-MITH A D29-Nov-19731 KiB2622

README.mdH A D29-Nov-19739.8 KiB262195

README.md

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&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K" height="20">](https://docs.rs/quote)
7[<img alt="build status" src="https://img.shields.io/github/workflow/status/dtolnay/quote/CI/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 &mdash; 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.31 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 anything that implements `IntoIterator`, including `Vec` or
88a pre-existing iterator.
89
90- `#(#var)*` — no separators
91- `#(#var),*` — the character before the asterisk is used as a separator
92- `#( struct #var; )*` — the repetition can contain other things
93- `#( #k => println!("{}", #v), )*` — even multiple interpolations
94
95Note that there is a difference between `#(#var ,)*` and `#(#var),*`—the latter
96does not produce a trailing comma. This matches the behavior of delimiters in
97`macro_rules!`.
98
99<br>
100
101## Returning tokens to the compiler
102
103The `quote!` macro evaluates to an expression of type
104`proc_macro2::TokenStream`. Meanwhile Rust procedural macros are expected to
105return the type `proc_macro::TokenStream`.
106
107The difference between the two types is that `proc_macro` types are entirely
108specific to procedural macros and cannot ever exist in code outside of a
109procedural macro, while `proc_macro2` types may exist anywhere including tests
110and non-macro code like main.rs and build.rs. This is why even the procedural
111macro ecosystem is largely built around `proc_macro2`, because that ensures the
112libraries are unit testable and accessible in non-macro contexts.
113
114There is a [`From`]-conversion in both directions so returning the output of
115`quote!` from a procedural macro usually looks like `tokens.into()` or
116`proc_macro::TokenStream::from(tokens)`.
117
118[`From`]: https://doc.rust-lang.org/std/convert/trait.From.html
119
120<br>
121
122## Examples
123
124### Combining quoted fragments
125
126Usually you don't end up constructing an entire final `TokenStream` in one
127piece. Different parts may come from different helper functions. The tokens
128produced by `quote!` themselves implement `ToTokens` and so can be interpolated
129into later `quote!` invocations to build up a final result.
130
131```rust
132let type_definition = quote! {...};
133let methods = quote! {...};
134
135let tokens = quote! {
136    #type_definition
137    #methods
138};
139```
140
141### Constructing identifiers
142
143Suppose we have an identifier `ident` which came from somewhere in a macro
144input and we need to modify it in some way for the macro output. Let's consider
145prepending the identifier with an underscore.
146
147Simply interpolating the identifier next to an underscore will not have the
148behavior of concatenating them. The underscore and the identifier will continue
149to be two separate tokens as if you had written `_ x`.
150
151```rust
152// incorrect
153quote! {
154    let mut _#ident = 0;
155}
156```
157
158The solution is to build a new identifier token with the correct value. As this
159is such a common case, the `format_ident!` macro provides a convenient utility
160for doing so correctly.
161
162```rust
163let varname = format_ident!("_{}", ident);
164quote! {
165    let mut #varname = 0;
166}
167```
168
169Alternatively, the APIs provided by Syn and proc-macro2 can be used to directly
170build the identifier. This is roughly equivalent to the above, but will not
171handle `ident` being a raw identifier.
172
173```rust
174let concatenated = format!("_{}", ident);
175let varname = syn::Ident::new(&concatenated, ident.span());
176quote! {
177    let mut #varname = 0;
178}
179```
180
181### Making method calls
182
183Let's say our macro requires some type specified in the macro input to have a
184constructor called `new`. We have the type in a variable called `field_type` of
185type `syn::Type` and want to invoke the constructor.
186
187```rust
188// incorrect
189quote! {
190    let value = #field_type::new();
191}
192```
193
194This works only sometimes. If `field_type` is `String`, the expanded code
195contains `String::new()` which is fine. But if `field_type` is something like
196`Vec<i32>` then the expanded code is `Vec<i32>::new()` which is invalid syntax.
197Ordinarily in handwritten Rust we would write `Vec::<i32>::new()` but for macros
198often the following is more convenient.
199
200```rust
201quote! {
202    let value = <#field_type>::new();
203}
204```
205
206This expands to `<Vec<i32>>::new()` which behaves correctly.
207
208A similar pattern is appropriate for trait methods.
209
210```rust
211quote! {
212    let value = <#field_type as core::default::Default>::default();
213}
214```
215
216<br>
217
218## Hygiene
219
220Any interpolated tokens preserve the `Span` information provided by their
221`ToTokens` implementation. Tokens that originate within a `quote!` invocation
222are spanned with [`Span::call_site()`].
223
224[`Span::call_site()`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.Span.html#method.call_site
225
226A different span can be provided explicitly through the [`quote_spanned!`]
227macro.
228
229[`quote_spanned!`]: https://docs.rs/quote/1.0/quote/macro.quote_spanned.html
230
231<br>
232
233## Non-macro code generators
234
235When using `quote` in a build.rs or main.rs and writing the output out to a
236file, consider having the code generator pass the tokens through [rustfmt]
237before writing (either by shelling out to the `rustfmt` binary or by pulling in
238the `rustfmt` library as a dependency). This way if an error occurs in the
239generated code it is convenient for a human to read and debug.
240
241Be aware that no kind of hygiene or span information is retained when tokens are
242written to a file; the conversion from tokens to source code is lossy.
243
244[rustfmt]: https://github.com/rust-lang/rustfmt
245
246<br>
247
248#### License
249
250<sup>
251Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
2522.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
253</sup>
254
255<br>
256
257<sub>
258Unless you explicitly state otherwise, any contribution intentionally submitted
259for inclusion in this crate by you, as defined in the Apache-2.0 license, shall
260be dual licensed as above, without any additional terms or conditions.
261</sub>
262