@@ -39,30 +39,17 @@ pub fn foo() {}
39
39
40
40
because the ` foo ` function is not a procedural macro. Procedural macros are
41
41
loaded dynamically by the compiler when they are needed during compilation.
42
- Cargo will naturally make procedural macro crates available to crates which
43
- depend on them, or you can use the ` --extern ` argument.
44
42
45
43
### The ` proc_macro ` crate
46
44
47
- Procedural macro crates almost always will link to the in-tree ` proc_macro `
48
- crate. The ` proc_macro ` crate is a compiler-provided crate which provides
45
+ Procedural macro crates almost always will link to the compiler-provided
46
+ ` proc_macro ` crate. The ` proc_macro ` crate is a crate which provides
49
47
facilities to working with the types of each procedural macro function. You can
50
- learn more about this crate by exploring [ the documentation] [ pm-dox ] .
51
-
52
- [ pm-dox ] : https://doc.rust-lang.org/stable/proc_macro/
53
-
54
- Linking to the ` proc_macro ` crate can currently be done with:
55
-
56
- ``` rust,ignore
57
- extern crate proc_macro;
58
- ```
59
-
60
- In the 2018 edition, however, this statement will not be necessary.
48
+ learn more about this crate by exploring [ its documentation] [ proc macro crate ] .
61
49
62
50
### The ` TokenStream ` Type
63
51
64
- One aspect you may notice about the ` proc_macro ` crate is that it doesn't
65
- contain any AST items! Instead, it primarily contains a ` TokenStream ` type.
52
+ It primarily contains a ` TokenStream ` type.
66
53
Procedural macros operate over * token streams* instead of AST nodes,
67
54
which is a far more stable interface over time for both the compiler and for
68
55
procedural macros to target.
@@ -72,13 +59,9 @@ can roughly be thought of as lexical token. For example `foo` is an `Ident`
72
59
token, ` . ` is a ` Punct ` token, and ` 1.2 ` is a ` Literal ` token. The ` TokenStream `
73
60
type, unlike ` Vec<TokenTree> ` , is cheap to clone (like ` Rc<T> ` ).
74
61
75
- To learn more about token streams, let's first dive into writing our first
76
- procedural macro.
77
-
78
62
### Bang Macros
79
63
80
- The first kind of procedural macro is the "procedural bang macro" macro. This
81
- flavor of procedural macro is like writing ` macro_rules! ` only you get to
64
+ This flavor of procedural macro is like writing ` macro_rules! ` only you get to
82
65
execute arbitrary code over the input tokens instead of being limited to
83
66
` macro_rules! ` syntax.
84
67
@@ -94,22 +77,7 @@ pub fn foo(input: TokenStream) -> TokenStream {
94
77
95
78
This item is defining a procedural bang macro (` #[proc_macro] ` ) which is called
96
79
` foo ` . The first argument is the input to the macro which explore in a second,
97
- and the return value is the tokens that it should expand to. Let's fill in all
98
- the pieces here with a noop macro.
99
-
100
- First up, let's generate a skeleton project:
101
-
102
- ``` sh
103
- $ cargo new foo
104
- $ cd foo
105
- $ cargo new my-macro --lib
106
- $ echo ' my-macro = { path = "my-macro" }' >> Cargo.toml
107
- $ echo ' [lib]' >> my-macro/Cargo.toml
108
- $ echo ' proc-macro = true' >> my-macro/Cargo.toml
109
- ```
110
-
111
- This'll set up a main binary project called ` foo ` along with a subcrate called
112
- ` my-macro ` which is declared as a procedural macro. Next up we'll fill in:
80
+ and the return value is the tokens that it should expand to.
113
81
114
82
``` rust,ignore
115
83
// my-macro/src/lib.rs
@@ -136,20 +104,6 @@ fn main() {
136
104
}
137
105
```
138
106
139
- and finally, build it!
140
-
141
- ``` sh
142
- $ cargo run
143
- Compiling my-macro v0.1.0 (file://.../foo/my-macro)
144
- Compiling foo v0.1.0 (file://.../foo)
145
- Finished dev [unoptimized + debuginfo] target(s) in 0.37s
146
- Running ` target/debug/foo`
147
- the answer was: 3
148
- ```
149
-
150
- Alright! This end-to-end example shows how we can create a macro that doesn't
151
- do anything, so let's do something a bit more useful.
152
-
153
107
First up, let's see what the input to our macro looks like by modifying our
154
108
macro:
155
109
@@ -162,39 +116,7 @@ pub fn foo(input: TokenStream) -> TokenStream {
162
116
}
163
117
```
164
118
165
- and reexecute (output edited slightly here):
166
-
167
- ``` sh
168
- $ cargo run
169
- Compiling my-macro v0.1.0 (file://.../foo/my-macro)
170
- Compiling foo v0.1.0 (file://.../foo)
171
- TokenStream [
172
- Ident { ident: " fn" , span: # 0 bytes(39..41) },
173
- Ident { ident: " answer" , span: # 0 bytes(42..48) },
174
- Group { delimiter: Parenthesis, stream: TokenStream [], span: # 0 bytes(48..50) },
175
- Punct { ch: ' -' , spacing: Joint, span: # 0 bytes(51..53) },
176
- Punct { ch: ' >' , spacing: Alone, span: # 0 bytes(51..53) },
177
- Ident { ident: " u32" , span: # 0 bytes(54..57) },
178
- Group {
179
- delimiter: Brace,
180
- stream: TokenStream [
181
- Literal { lit: Integer(3), suffix: None, span: # 0 bytes(60..61) }
182
- ],
183
- span: # 0 bytes(58..63)
184
- }
185
- ]
186
- Finished dev [unoptimized + debuginfo] target(s) in 0.37s
187
- Running ` target/debug/foo`
188
- the answer was: 3
189
- ` ` `
190
-
191
- Here we can see how a procedural bang macro' s input is a token stream (list) of
192
- all the tokens provided as input to the macro itself, excluding the delimiters
193
- used to invoke the macro. Notice how the braces and parentheses are using the
194
- `Group` token tree which is used to enforce that macros always have balanced
195
- delimiters.
196
-
197
- As you may have guessed by now the macro invocation is effectively replaced by
119
+ The macro invocation is effectively replaced by
198
120
the return value of the macro, creating the function that we provided as input.
199
121
We can see another example of this where we simply ignore the input:
200
122
@@ -206,26 +128,15 @@ pub fn foo(_input: TokenStream) -> TokenStream {
206
128
}
207
129
```
208
130
209
- and recompiling shows:
210
-
211
- ```sh
212
- $ cargo run
213
- Compiling my-macro v0.1.0 (file://.../foo/my-macro)
214
- Compiling foo v0.1.0 (file://.../foo)
215
- Finished dev [unoptimized + debuginfo] target(s) in 0.37s
216
- Running `target/debug/foo`
131
+ ```
217
132
the answer was: 4
218
133
```
219
134
220
- showing us how the input was ignored and the macro' s output was used instead.
221
-
222
135
### Derive macros
223
136
224
- [The book][procedural macros] has a tutorial on creating derive macros and here
225
- we' ll go into some of the nitty-gritty of how this works. The derive macro
226
- feature allows you to define a new `#[derive(Foo)]` mode which often makes it
227
- much easier to systematically implement traits, removing quite a lot of
228
- boilerplate.
137
+ The derive macro feature allows you to define a new ` #[derive(Foo)] ` mode which
138
+ often makes it much easier to systematically implement traits, removing quite a
139
+ lot of boilerplate.
229
140
230
141
Custom derives are defined like so:
231
142
@@ -274,17 +185,7 @@ fn main() {
274
185
275
186
and compiling it:
276
187
277
- ```sh
278
- $ cargo run
279
- Compiling my-macro v0.1.0 (file://.../foo/my-macro)
280
- Compiling foo v0.1.0 (file://.../foo)
281
- TokenStream [
282
- Ident { ident: "struct", span: #0 bytes(67..73) },
283
- Ident { ident: "Foo", span: #0 bytes(74..77) },
284
- Punct { ch: ' ; ' , spacing: Alone, span: #0 bytes(77..78) }
285
- ]
286
- Finished dev [unoptimized + debuginfo] target(s) in 0.34s
287
- Running `target/debug/foo`
188
+ ```
288
189
the answer was: 2
289
190
```
290
191
@@ -295,11 +196,7 @@ derive macros *append* items, they don't replace them.
295
196
296
197
Now this is a pretty wonky macro derive, and would likely be confusing to
297
198
users! Derive macros are primarily geared towards implementing traits, like
298
- ` Serialize` and ` Deserialize` . The ` syn` crate also has a [number of
299
- examples][synex] of defining derive macros.
300
-
301
- [procedural macros]: ../book/first-edition/procedural-macros.html
302
- [synex]: https://github.com/dtolnay/syn/tree/master/examples
199
+ ` Serialize ` and ` Deserialize ` .
303
200
304
201
#### Derive helper attributes
305
202
@@ -333,14 +230,13 @@ struct Foo;
333
230
you'll see that the ` #[my_attribute(hello)] ` attribute is fed through to the
334
231
macro for processing.
335
232
336
- Attributes are often used to customize the behavior of derive macros, such as
337
- the ` # [serde]` attribute for the ` serde` crate.
233
+ Attributes are often used to customize the behavior of derive macros.
338
234
339
235
### Attribute macros
340
236
341
- The third and final form of procedural macros is the attribute macro. Attribute
342
- macros allow you to define a new ` # [attr] ` -style attribute which can be
343
- attached to items and generate wrappers and such. These macros are defined like:
237
+ Attribute macros allow you to define a new ` #[attr] ` -style attribute which can
238
+ be attached to items and generate wrappers and such. These macros are defined
239
+ like:
344
240
345
241
``` rust,ignore
346
242
#[proc_macro_attribute]
@@ -353,9 +249,8 @@ The `#[proc_macro_attribute]` indicates that this macro is an attribute macro
353
249
and can only be invoked like ` #[foo] ` . The name of the function here will be the
354
250
name of the attribute as well.
355
251
356
- The first input, ` attr` , is the arguments to the attribute provided, which
357
- we' ll see in a moment. The second argument, `item`, is the item that the
358
- attribute is attached to.
252
+ The first input, ` attr ` , is the arguments to the attribute provided. The second
253
+ argument, ` item ` , is the item that the attribute is attached to.
359
254
360
255
Like with bang macros at the beginning (and unlike derive macros), the return
361
256
value here * replaces* the input ` item ` .
@@ -402,9 +297,7 @@ fn main() {
402
297
403
298
compiled as:
404
299
405
- ` ` ` sh
406
- $ cargo run
407
- Compiling foo v0.1.0 (file://.../foo)
300
+ ```
408
301
attr:
409
302
input: fn invoke1() { }
410
303
attr: bar
@@ -413,8 +306,6 @@ attr: crazy custom syntax
413
306
input: fn invoke3() { }
414
307
attr: delimiters
415
308
input: fn invoke4() { }
416
- Finished dev [unoptimized + debuginfo] target(s) in 0.12s
417
- Running ` target/debug/foo`
418
309
```
419
310
420
311
Here we can see how the arguments to the attribute show up in the ` attr `
@@ -452,31 +343,6 @@ pub fn swap_spans(input: TokenStream) -> TokenStream {
452
343
}
453
344
```
454
345
455
- We can see what' s going on here by feeding invalid syntax into the macro and
456
- seeing what the compiler reports. Let' s start off by seeing what the compiler
457
- does normally:
458
-
459
- ` ` ` rust,ignore
460
- // src/main.rs
461
- fn _ () {}
462
- ` ` `
463
-
464
- is compiled as:
465
-
466
- ` ` ` sh
467
- $ cargo run
468
- Compiling foo v0.1.0 (file://.../foo)
469
- error: expected identifier, found reserved identifier ` _`
470
- --> src/main.rs:1:4
471
- |
472
- 1 | fn _ () {}
473
- | ^ expected identifier, found reserved identifier
474
-
475
- error: aborting due to previous error
476
- ` ` `
477
-
478
- but when we feed it through our macro:
479
-
480
346
``` rust,ignore
481
347
extern crate my_macro;
482
348
@@ -505,9 +371,6 @@ notice how the error message is pointing to the wrong span! This is because we
505
371
swapped the spans of the first two tokens, giving the compiler false information
506
372
about where the tokens came from.
507
373
508
- Controlling spans is quite a powerful feature and needs to be used with care,
509
- misuse can lead to some excessively confusing error messages!
510
-
511
374
### Procedural macros and hygiene
512
375
513
376
Currently all procedural macros are "unhygienic". This means that all procedural
@@ -551,4 +414,5 @@ macros in some respects. These limitations include:
551
414
exists on stable your only option is to ` panic! ` or to in some cases expand to
552
415
an invocation of the ` compile_error! ` macro with a custom message.
553
416
554
- [crate type]: linkage.html
417
+ [ crate type ] : linkage.html
418
+ [ proc_macro crate ] : ../proc_macro/index.html
0 commit comments