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