]> git.proxmox.com Git - rustc.git/blob - src/doc/book/src/ch19-06-macros.md
New upstream version 1.43.0+dfsg1
[rustc.git] / src / doc / book / src / ch19-06-macros.md
1 ## Macros
2
3 We’ve used macros like `println!` throughout this book, but we haven’t fully
4 explored what a macro is and how it works. The term *macro* refers to a family
5 of features in Rust: *declarative* macros with `macro_rules!` and three kinds
6 of *procedural* macros:
7
8 * Custom `#[derive]` macros that specify code added with the `derive` attribute
9 used on structs and enums
10 * Attribute-like macros that define custom attributes usable on any item
11 * Function-like macros that look like function calls but operate on the tokens
12 specified as their argument
13
14 We’ll talk about each of these in turn, but first, let’s look at why we even
15 need macros when we already have functions.
16
17 ### The Difference Between Macros and Functions
18
19 Fundamentally, macros are a way of writing code that writes other code, which
20 is known as *metaprogramming*. In Appendix C, we discuss the `derive`
21 attribute, which generates an implementation of various traits for you. We’ve
22 also used the `println!` and `vec!` macros throughout the book. All of these
23 macros *expand* to produce more code than the code you’ve written manually.
24
25 Metaprogramming is useful for reducing the amount of code you have to write and
26 maintain, which is also one of the roles of functions. However, macros have
27 some additional powers that functions don’t.
28
29 A function signature must declare the number and type of parameters the
30 function has. Macros, on the other hand, can take a variable number of
31 parameters: we can call `println!("hello")` with one argument or
32 `println!("hello {}", name)` with two arguments. Also, macros are expanded
33 before the compiler interprets the meaning of the code, so a macro can, for
34 example, implement a trait on a given type. A function can’t, because it gets
35 called at runtime and a trait needs to be implemented at compile time.
36
37 The downside to implementing a macro instead of a function is that macro
38 definitions are more complex than function definitions because you’re writing
39 Rust code that writes Rust code. Due to this indirection, macro definitions are
40 generally more difficult to read, understand, and maintain than function
41 definitions.
42
43 Another important difference between macros and functions is that you must
44 define macros or bring them into scope *before* you call them in a file, as
45 opposed to functions you can define anywhere and call anywhere.
46
47 ### Declarative Macros with `macro_rules!` for General Metaprogramming
48
49 The most widely used form of macros in Rust is *declarative macros*. These are
50 also sometimes referred to as “macros by example,” “`macro_rules!` macros,” or
51 just plain “macros.” At their core, declarative macros allow you to write
52 something similar to a Rust `match` expression. As discussed in Chapter 6,
53 `match` expressions are control structures that take an expression, compare the
54 resulting value of the expression to patterns, and then run the code associated
55 with the matching pattern. Macros also compare a value to patterns that are
56 associated with particular code: in this situation, the value is the literal
57 Rust source code passed to the macro; the patterns are compared with the
58 structure of that source code; and the code associated with each pattern, when
59 matched, replaces the code passed to the macro. This all happens during
60 compilation.
61
62 To define a macro, you use the `macro_rules!` construct. Let’s explore how to
63 use `macro_rules!` by looking at how the `vec!` macro is defined. Chapter 8
64 covered how we can use the `vec!` macro to create a new vector with particular
65 values. For example, the following macro creates a new vector containing three
66 integers:
67
68 ```rust
69 let v: Vec<u32> = vec![1, 2, 3];
70 ```
71
72 We could also use the `vec!` macro to make a vector of two integers or a vector
73 of five string slices. We wouldn’t be able to use a function to do the same
74 because we wouldn’t know the number or type of values up front.
75
76 Listing 19-28 shows a slightly simplified definition of the `vec!` macro.
77
78 <span class="filename">Filename: src/lib.rs</span>
79
80 ```rust
81 {{#rustdoc_include ../listings/ch19-advanced-features/listing-19-28/src/lib.rs}}
82 ```
83
84 <span class="caption">Listing 19-28: A simplified version of the `vec!` macro
85 definition</span>
86
87 > Note: The actual definition of the `vec!` macro in the standard library
88 > includes code to preallocate the correct amount of memory up front. That code
89 > is an optimization that we don’t include here to make the example simpler.
90
91 The `#[macro_export]` annotation indicates that this macro should be made
92 available whenever the crate in which the macro is defined is brought into
93 scope. Without this annotation, the macro can’t be brought into scope.
94
95 We then start the macro definition with `macro_rules!` and the name of the
96 macro we’re defining *without* the exclamation mark. The name, in this case
97 `vec`, is followed by curly brackets denoting the body of the macro definition.
98
99 The structure in the `vec!` body is similar to the structure of a `match`
100 expression. Here we have one arm with the pattern `( $( $x:expr ),* )`,
101 followed by `=>` and the block of code associated with this pattern. If the
102 pattern matches, the associated block of code will be emitted. Given that this
103 is the only pattern in this macro, there is only one valid way to match; any
104 other pattern will result in an error. More complex macros will have more than
105 one arm.
106
107 Valid pattern syntax in macro definitions is different than the pattern syntax
108 covered in Chapter 18 because macro patterns are matched against Rust code
109 structure rather than values. Let’s walk through what the pattern pieces in
110 Listing 19-28 mean; for the full macro pattern syntax, see [the reference].
111
112 [the reference]: ../reference/macros-by-example.html
113
114 First, a set of parentheses encompasses the whole pattern. A dollar sign (`$`)
115 is next, followed by a set of parentheses that captures values that match the
116 pattern within the parentheses for use in the replacement code. Within `$()` is
117 `$x:expr`, which matches any Rust expression and gives the expression the name
118 `$x`.
119
120 The comma following `$()` indicates that a literal comma separator character
121 could optionally appear after the code that matches the code in `$()`. The `*`
122 specifies that the pattern matches zero or more of whatever precedes the `*`.
123
124 When we call this macro with `vec![1, 2, 3];`, the `$x` pattern matches three
125 times with the three expressions `1`, `2`, and `3`.
126
127 Now let’s look at the pattern in the body of the code associated with this arm:
128 `temp_vec.push()` within `$()*` is generated for each part that matches `$()`
129 in the pattern zero or more times depending on how many times the pattern
130 matches. The `$x` is replaced with each expression matched. When we call this
131 macro with `vec![1, 2, 3];`, the code generated that replaces this macro call
132 will be the following:
133
134 ```rust,ignore
135 {
136 let mut temp_vec = Vec::new();
137 temp_vec.push(1);
138 temp_vec.push(2);
139 temp_vec.push(3);
140 temp_vec
141 }
142 ```
143
144 We’ve defined a macro that can take any number of arguments of any type and can
145 generate code to create a vector containing the specified elements.
146
147 There are some strange edge cases with `macro_rules!`. In the future, Rust will
148 have a second kind of declarative macro that will work in a similar fashion but
149 fix some of these edge cases. After that update, `macro_rules!` will be
150 effectively deprecated. With this in mind, as well as the fact that most Rust
151 programmers will *use* macros more than *write* macros, we won’t discuss
152 `macro_rules!` any further. To learn more about how to write macros, consult
153 the online documentation or other resources, such as [“The Little Book of Rust
154 Macros”][tlborm].
155
156 [tlborm]: https://danielkeep.github.io/tlborm/book/index.html
157
158 ### Procedural Macros for Generating Code from Attributes
159
160 The second form of macros is *procedural macros*, which act more like functions
161 (and are a type of procedure). Procedural macros accept some code as an input,
162 operate on that code, and produce some code as an output rather than matching
163 against patterns and replacing the code with other code as declarative macros
164 do.
165
166 The three kinds of procedural macros (custom derive, attribute-like, and
167 function-like) all work in a similar fashion.
168
169 When creating procedural macros, the definitions must reside in their own crate
170 with a special crate type. This is for complex technical reasons that we hope
171 to eliminate in the future. Using procedural macros looks like the code in
172 Listing 19-29, where `some_attribute` is a placeholder for using a specific
173 macro.
174
175 <span class="filename">Filename: src/lib.rs</span>
176
177 ```rust,ignore
178 use proc_macro;
179
180 #[some_attribute]
181 pub fn some_name(input: TokenStream) -> TokenStream {
182 }
183 ```
184
185 <span class="caption">Listing 19-29: An example of using a procedural
186 macro</span>
187
188 The function that defines a procedural macro takes a `TokenStream` as an input
189 and produces a `TokenStream` as an output. The `TokenStream` type is defined by
190 the `proc_macro` crate that is included with Rust and represents a sequence of
191 tokens. This is the core of the macro: the source code that the macro is
192 operating on makes up the input `TokenStream`, and the code the macro produces
193 is the output `TokenStream`. The function also has an attribute attached to it
194 that specifies which kind of procedural macro we’re creating. We can have
195 multiple kinds of procedural macros in the same crate.
196
197 Let’s look at the different kinds of procedural macros. We’ll start with a
198 custom derive macro and then explain the small dissimilarities that make the
199 other forms different.
200
201 ### How to Write a Custom `derive` Macro
202
203 Let’s create a crate named `hello_macro` that defines a trait named
204 `HelloMacro` with one associated function named `hello_macro`. Rather than
205 making our crate users implement the `HelloMacro` trait for each of their
206 types, we’ll provide a procedural macro so users can annotate their type with
207 `#[derive(HelloMacro)]` to get a default implementation of the `hello_macro`
208 function. The default implementation will print `Hello, Macro! My name is
209 TypeName!` where `TypeName` is the name of the type on which this trait has
210 been defined. In other words, we’ll write a crate that enables another
211 programmer to write code like Listing 19-30 using our crate.
212
213 <span class="filename">Filename: src/main.rs</span>
214
215 ```rust,ignore,does_not_compile
216 {{#rustdoc_include ../listings/ch19-advanced-features/listing-19-30/src/main.rs}}
217 ```
218
219 <span class="caption">Listing 19-30: The code a user of our crate will be able
220 to write when using our procedural macro</span>
221
222 This code will print `Hello, Macro! My name is Pancakes!` when we’re done. The
223 first step is to make a new library crate, like this:
224
225 ```text
226 $ cargo new hello_macro --lib
227 ```
228
229 Next, we’ll define the `HelloMacro` trait and its associated function:
230
231 <span class="filename">Filename: src/lib.rs</span>
232
233 ```rust
234 {{#rustdoc_include ../listings/ch19-advanced-features/no-listing-20-impl-hellomacro-for-pancakes/hello_macro/src/lib.rs}}
235 ```
236
237 We have a trait and its function. At this point, our crate user could implement
238 the trait to achieve the desired functionality, like so:
239
240 ```rust,ignore
241 {{#rustdoc_include ../listings/ch19-advanced-features/no-listing-20-impl-hellomacro-for-pancakes/pancakes/src/main.rs}}
242 ```
243
244 However, they would need to write the implementation block for each type they
245 wanted to use with `hello_macro`; we want to spare them from having to do this
246 work.
247
248 Additionally, we can’t yet provide the `hello_macro` function with default
249 implementation that will print the name of the type the trait is implemented
250 on: Rust doesn’t have reflection capabilities, so it can’t look up the type’s
251 name at runtime. We need a macro to generate code at compile time.
252
253 The next step is to define the procedural macro. At the time of this writing,
254 procedural macros need to be in their own crate. Eventually, this restriction
255 might be lifted. The convention for structuring crates and macro crates is as
256 follows: for a crate named `foo`, a custom derive procedural macro crate is
257 called `foo_derive`. Let’s start a new crate called `hello_macro_derive` inside
258 our `hello_macro` project:
259
260 ```text
261 $ cargo new hello_macro_derive --lib
262 ```
263
264 Our two crates are tightly related, so we create the procedural macro crate
265 within the directory of our `hello_macro` crate. If we change the trait
266 definition in `hello_macro`, we’ll have to change the implementation of the
267 procedural macro in `hello_macro_derive` as well. The two crates will need to
268 be published separately, and programmers using these crates will need to add
269 both as dependencies and bring them both into scope. We could instead have the
270 `hello_macro` crate use `hello_macro_derive` as a dependency and re-export the
271 procedural macro code. However, the way we’ve structured the project makes it
272 possible for programmers to use `hello_macro` even if they don’t want the
273 `derive` functionality.
274
275 We need to declare the `hello_macro_derive` crate as a procedural macro crate.
276 We’ll also need functionality from the `syn` and `quote` crates, as you’ll see
277 in a moment, so we need to add them as dependencies. Add the following to the
278 *Cargo.toml* file for `hello_macro_derive`:
279
280 <span class="filename">Filename: hello_macro_derive/Cargo.toml</span>
281
282 ```toml
283 {{#include ../listings/ch19-advanced-features/listing-19-31/hello_macro/hello_macro_derive/Cargo.toml:7:12}}
284 ```
285
286 To start defining the procedural macro, place the code in Listing 19-31 into
287 your *src/lib.rs* file for the `hello_macro_derive` crate. Note that this code
288 won’t compile until we add a definition for the `impl_hello_macro` function.
289
290 <span class="filename">Filename: hello_macro_derive/src/lib.rs</span>
291
292 ```rust,ignore,does_not_compile
293 {{#rustdoc_include ../listings/ch19-advanced-features/listing-19-31/hello_macro/hello_macro_derive/src/lib.rs}}
294 ```
295
296 <span class="caption">Listing 19-31: Code that most procedural macro crates
297 will require in order to process Rust code</span>
298
299 Notice that we’ve split the code into the `hello_macro_derive` function, which
300 is responsible for parsing the `TokenStream`, and the `impl_hello_macro`
301 function, which is responsible for transforming the syntax tree: this makes
302 writing a procedural macro more convenient. The code in the outer function
303 (`hello_macro_derive` in this case) will be the same for almost every
304 procedural macro crate you see or create. The code you specify in the body of
305 the inner function (`impl_hello_macro` in this case) will be different
306 depending on your procedural macro’s purpose.
307
308 We’ve introduced three new crates: `proc_macro`, [`syn`], and [`quote`]. The
309 `proc_macro` crate comes with Rust, so we didn’t need to add that to the
310 dependencies in *Cargo.toml*. The `proc_macro` crate is the compiler’s API that
311 allows us to read and manipulate Rust code from our code.
312
313 [`syn`]: https://crates.io/crates/syn
314 [`quote`]: https://crates.io/crates/quote
315
316 The `syn` crate parses Rust code from a string into a data structure that we
317 can perform operations on. The `quote` crate turns `syn` data structures back
318 into Rust code. These crates make it much simpler to parse any sort of Rust
319 code we might want to handle: writing a full parser for Rust code is no simple
320 task.
321
322 The `hello_macro_derive` function will be called when a user of our library
323 specifies `#[derive(HelloMacro)]` on a type. This is possible because we’ve
324 annotated the `hello_macro_derive` function here with `proc_macro_derive` and
325 specified the name, `HelloMacro`, which matches our trait name; this is the
326 convention most procedural macros follow.
327
328 The `hello_macro_derive` function first converts the `input` from a
329 `TokenStream` to a data structure that we can then interpret and perform
330 operations on. This is where `syn` comes into play. The `parse` function in
331 `syn` takes a `TokenStream` and returns a `DeriveInput` struct representing the
332 parsed Rust code. Listing 19-32 shows the relevant parts of the `DeriveInput`
333 struct we get from parsing the `struct Pancakes;` string:
334
335 ```rust,ignore
336 DeriveInput {
337 // --snip--
338
339 ident: Ident {
340 ident: "Pancakes",
341 span: #0 bytes(95..103)
342 },
343 data: Struct(
344 DataStruct {
345 struct_token: Struct,
346 fields: Unit,
347 semi_token: Some(
348 Semi
349 )
350 }
351 )
352 }
353 ```
354
355 <span class="caption">Listing 19-32: The `DeriveInput` instance we get when
356 parsing the code that has the macro’s attribute in Listing 19-30</span>
357
358 The fields of this struct show that the Rust code we’ve parsed is a unit struct
359 with the `ident` (identifier, meaning the name) of `Pancakes`. There are more
360 fields on this struct for describing all sorts of Rust code; check the [`syn`
361 documentation for `DeriveInput`][syn-docs] for more information.
362
363 [syn-docs]: https://docs.rs/syn/1.0/syn/struct.DeriveInput.html
364
365 Soon we’ll define the `impl_hello_macro` function, which is where we’ll build
366 the new Rust code we want to include. But before we do, note that the output
367 for our derive macro is also a `TokenStream`. The returned `TokenStream` is
368 added to the code that our crate users write, so when they compile their crate,
369 they’ll get the extra functionality that we provide in the modified
370 `TokenStream`.
371
372 You might have noticed that we’re calling `unwrap` to cause the
373 `hello_macro_derive` function to panic if the call to the `syn::parse` function
374 fails here. It’s necessary for our procedural macro to panic on errors because
375 `proc_macro_derive` functions must return `TokenStream` rather than `Result` to
376 conform to the procedural macro API. We’ve simplified this example by using
377 `unwrap`; in production code, you should provide more specific error messages
378 about what went wrong by using `panic!` or `expect`.
379
380 Now that we have the code to turn the annotated Rust code from a `TokenStream`
381 into a `DeriveInput` instance, let’s generate the code that implements the
382 `HelloMacro` trait on the annotated type, as shown in Listing 19-33.
383
384 <span class="filename">Filename: hello_macro_derive/src/lib.rs</span>
385
386 ```rust,ignore
387 {{#rustdoc_include ../listings/ch19-advanced-features/listing-19-33/hello_macro/hello_macro_derive/src/lib.rs:here}}
388 ```
389
390 <span class="caption">Listing 19-33: Implementing the `HelloMacro` trait using
391 the parsed Rust code</span>
392
393 We get an `Ident` struct instance containing the name (identifier) of the
394 annotated type using `ast.ident`. The struct in Listing 19-32 shows that when
395 we run the `impl_hello_macro` function on the code in Listing 19-30, the
396 `ident` we get will have the `ident` field with a value of `"Pancakes"`. Thus,
397 the `name` variable in Listing 19-33 will contain an `Ident` struct instance
398 that, when printed, will be the string `"Pancakes"`, the name of the struct in
399 Listing 19-30.
400
401 The `quote!` macro lets us define the Rust code that we want to return. The
402 compiler expects something different to the direct result of the `quote!`
403 macro’s execution, so we need to convert it to a `TokenStream`. We do this by
404 calling the `into` method, which consumes this intermediate representation and
405 returns a value of the required `TokenStream` type.
406
407 The `quote!` macro also provides some very cool templating mechanics: we can
408 enter `#name`, and `quote!` will replace it with the value in the variable
409 `name`. You can even do some repetition similar to the way regular macros work.
410 Check out [the `quote` crate’s docs][quote-docs] for a thorough introduction.
411
412 [quote-docs]: https://docs.rs/quote
413
414 We want our procedural macro to generate an implementation of our `HelloMacro`
415 trait for the type the user annotated, which we can get by using `#name`. The
416 trait implementation has one function, `hello_macro`, whose body contains the
417 functionality we want to provide: printing `Hello, Macro! My name is` and then
418 the name of the annotated type.
419
420 The `stringify!` macro used here is built into Rust. It takes a Rust
421 expression, such as `1 + 2`, and at compile time turns the expression into a
422 string literal, such as `"1 + 2"`. This is different than `format!` or
423 `println!`, macros which evaluate the expression and then turn the result into
424 a `String`. There is a possibility that the `#name` input might be an
425 expression to print literally, so we use `stringify!`. Using `stringify!` also
426 saves an allocation by converting `#name` to a string literal at compile time.
427
428 At this point, `cargo build` should complete successfully in both `hello_macro`
429 and `hello_macro_derive`. Let’s hook up these crates to the code in Listing
430 19-30 to see the procedural macro in action! Create a new binary project in
431 your *projects* directory using `cargo new pancakes`. We need to add
432 `hello_macro` and `hello_macro_derive` as dependencies in the `pancakes`
433 crate’s *Cargo.toml*. If you’re publishing your versions of `hello_macro` and
434 `hello_macro_derive` to [crates.io](https://crates.io/), they would be regular
435 dependencies; if not, you can specify them as `path` dependencies as follows:
436
437 ```toml
438 {{#include ../listings/ch19-advanced-features/no-listing-21-pancakes/pancakes/Cargo.toml:7:9}}
439 ```
440
441 Put the code in Listing 19-30 into *src/main.rs*, and run `cargo run`: it
442 should print `Hello, Macro! My name is Pancakes!` The implementation of the
443 `HelloMacro` trait from the procedural macro was included without the
444 `pancakes` crate needing to implement it; the `#[derive(HelloMacro)]` added the
445 trait implementation.
446
447 Next, let’s explore how the other kinds of procedural macros differ from custom
448 derive macros.
449
450 ### Attribute-like macros
451
452 Attribute-like macros are similar to custom derive macros, but instead of
453 generating code for the `derive` attribute, they allow you to create new
454 attributes. They’re also more flexible: `derive` only works for structs and
455 enums; attributes can be applied to other items as well, such as functions.
456 Here’s an example of using an attribute-like macro: say you have an attribute
457 named `route` that annotates functions when using a web application framework:
458
459 ```rust,ignore
460 #[route(GET, "/")]
461 fn index() {
462 ```
463
464 This `#[route]` attribute would be defined by the framework as a procedural
465 macro. The signature of the macro definition function would look like this:
466
467 ```rust,ignore
468 #[proc_macro_attribute]
469 pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream {
470 ```
471
472 Here, we have two parameters of type `TokenStream`. The first is for the
473 contents of the attribute: the `GET, "/"` part. The second is the body of the
474 item the attribute is attached to: in this case, `fn index() {}` and the rest
475 of the function’s body.
476
477 Other than that, attribute-like macros work the same way as custom derive
478 macros: you create a crate with the `proc-macro` crate type and implement a
479 function that generates the code you want!
480
481 ### Function-like macros
482
483 Function-like macros define macros that look like function calls. Similarly to
484 `macro_rules!` macros, they’re more flexible than functions; for example, they
485 can take an unknown number of arguments. However, `macro_rules!` macros can be
486 defined only using the match-like syntax we discussed in the section
487 [“Declarative Macros with `macro_rules!` for General Metaprogramming”][decl]
488 earlier. Function-like macros take a `TokenStream` parameter and their
489 definition manipulates that `TokenStream` using Rust code as the other two
490 types of procedural macros do. An example of a function-like macro is an `sql!`
491 macro that might be called like so:
492
493 [decl]: #declarative-macros-with-macro_rules-for-general-metaprogramming
494
495 ```rust,ignore
496 let sql = sql!(SELECT * FROM posts WHERE id=1);
497 ```
498
499 This macro would parse the SQL statement inside it and check that it’s
500 syntactically correct, which is much more complex processing than a
501 `macro_rules!` macro can do. The `sql!` macro would be defined like this:
502
503 ```rust,ignore
504 #[proc_macro]
505 pub fn sql(input: TokenStream) -> TokenStream {
506 ```
507
508 This definition is similar to the custom derive macro’s signature: we receive
509 the tokens that are inside the parentheses and return the code we wanted to
510 generate.
511
512 ## Summary
513
514 Whew! Now you have some Rust features in your toolbox that you won’t use often,
515 but you’ll know they’re available in very particular circumstances. We’ve
516 introduced several complex topics so that when you encounter them in error
517 message suggestions or in other peoples’ code, you’ll be able to recognize
518 these concepts and syntax. Use this chapter as a reference to guide you to
519 solutions.
520
521 Next, we’ll put everything we’ve discussed throughout the book into practice
522 and do one more project!