Skip to content

Commit bb61e7e

Browse files
committed
Attribute macros
1 parent a1ccd19 commit bb61e7e

File tree

1 file changed

+60
-55
lines changed

1 file changed

+60
-55
lines changed

src/procedural-macros.md

Lines changed: 60 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,7 @@ define new items given the token stream of a [struct], [enum], or [union]. They
157157
also define derive mode helper attributes.
158158

159159
Custom derivers are defined by a [public] [function] with the `proc_maco_derive`
160-
attribute that takes a single input of the type [`TokenStream`] and returns a
161-
[`TokenStream`].
160+
attribute and a signature of `(TokenStream) -> TokenStream`.
162161

163162
The input [`TokenStream`] is the token stream of the item that has the `derive`
164163
attribute on it. The output [`TokenStream`] must be a set of items that are
@@ -230,85 +229,91 @@ struct Struct {
230229

231230
### Attribute macros
232231

233-
Attribute macros allow you to define a new `#[attr]`-style attribute which can
234-
be attached to items and generate wrappers and such. These macros are defined
235-
like:
232+
*Attribute macros* define new [attributes] which can be attached to [items].
236233

237-
```rust,ignore
238-
#[proc_macro_attribute]
239-
pub fn foo(attr: TokenStream, input: TokenStream) -> TokenStream {
240-
// ...
241-
}
242-
```
234+
Attribute macros are defined by a [public] [function] with the
235+
`proc_macro_attribute` attribute that a signature of `(TokenStream, TokenStream)
236+
-> TokenStream`. The first [`TokenStream`] is the attribute's metaitems, not
237+
including the delimiters. If the attribute is written without a metaitem, the
238+
attribute [`TokenStream`] is empty. The second [`TokenStream`] is of the rest of
239+
the item including other attributes on the item. The returned [`TokenStream`]
240+
replaces the item. It may contain an arbitrary number of items. The returned
241+
[`TokenStream`] cannot include any [macro] definitions.
242+
243+
For example, this attribute macro takes the input stream and returns it as is,
244+
effectively being the no-op of attributes.
245+
246+
```rust
247+
#![crate_type = "proc_macro"]
243248

244-
The `#[proc_macro_attribute]` indicates that this macro is an attribute macro
245-
and can only be invoked like `#[foo]`. The name of the function here will be the
246-
name of the attribute as well.
249+
extern crate proc_macro;
247250

248-
The first input, `attr`, is the arguments to the attribute provided. The second
249-
argument, `item`, is the item that the attribute is attached to.
251+
use proc_macro::TokenStream;
250252

251-
Like with bang macros at the beginning (and unlike derive macros), the return
252-
value here *replaces* the input `item`.
253+
#[proc_macro_attribute]
254+
pub fn return_as_is(_attr: TokenStream, item: TokenStream) -> TokenStream {
255+
item
256+
}
257+
```
253258

254-
Let's see this attribute in action:
259+
This following example shows the stringified [`TokenStream`s] that the attribute
260+
macros see. The output will show in the output of the compiler. The output is
261+
shown in the comments after the function prefixed with "out:".
255262

256263
```rust,ignore
257264
// my-macro/src/lib.rs
258-
extern crate proc_macro;
259-
use proc_macro::*;
265+
# extern crate proc_macro;
266+
# use proc_macro::TokenStream;
260267
261268
#[proc_macro_attribute]
262-
pub fn foo(attr: TokenStream, input: TokenStream) -> TokenStream {
263-
println!("attr: {}", attr.to_string());
264-
println!("input: {}", input.to_string());
269+
pub fn show_streams(attr: TokenStream, input: TokenStream) -> TokenStream {
270+
println!("attr: \"{}\"", attr.to_string());
271+
println!("item: \"{}\"', input.to_string());
265272
item
266273
}
267274
```
268275

269-
and invoke it as:
270-
271276
```rust,ignore
272-
// src/main.rs
277+
// src/lib.rs
273278
extern crate my_macro;
274279
275-
use my_macro::foo;
280+
use my_macro::show_streams;
276281
277-
#[foo]
282+
// Example: Basic function
283+
#[show_streams]
278284
fn invoke1() {}
285+
// out: attr: ""
286+
// out: item: "fn invoke1() { }"
279287
280-
#[foo(bar)]
288+
// Example: Attribute has a metaitem
289+
#[show_streams(bar)]
281290
fn invoke2() {}
291+
// out: attr: "bar"
292+
// out: item: "fn invoke2() {}"
282293
283-
#[foo(crazy custom syntax)]
294+
// Example: Multiple words in metaitem
295+
#[show_streams(multiple words)]
284296
fn invoke3() {}
297+
// out: attr: "multiple words"
298+
// out: item: "fn invoke3() {}"
285299
286-
#[foo { delimiters }]
300+
// Example:
301+
#[show_streams { delimiters }]
287302
fn invoke4() {}
288-
289-
fn main() {
290-
// ...
291-
}
303+
// out: "delimiters"
304+
// out: "fn invoke4() {}"
292305
```
293306

294-
compiled as:
295-
296-
```
297-
attr:
298-
input: fn invoke1() { }
299-
attr: bar
300-
input: fn invoke2() { }
301-
attr: crazy custom syntax
302-
input: fn invoke3() { }
303-
attr: delimiters
304-
input: fn invoke4() { }
305-
```
306-
307-
Here we can see how the arguments to the attribute show up in the `attr`
308-
argument. Notably these arguments do not include the delimiters used to enclose
309-
the arguments (like procedural bang macros. Furthermore we can see the item
310-
continue to operate on it, either replacing it or augmenting it.
311-
312307
[`TokenStream`]: ../proc_macro/struct.TokenStream.html
308+
[`TokenStream`s]: ../proc_macro/struct.TokenStream.html
309+
[`derive`]: attributes.html#derive
313310
[`proc_macro` crate]: ../proc_macro/index.html
314-
[crate type]: linkage.html
311+
[attributes]: attributes.html
312+
[custom attributes]: attributes.html
313+
[crate type]: linkage.html
314+
[item]: items.html
315+
[function]: items/functions.html
316+
[macro]: macros.html
317+
[module]: items/modules.html
318+
[procedural macro tutorial]: ../book/2018-edition/appendix-04-macros.html#procedural-macros-for-custom-derive
319+
[public]: visibility-and-privacy.html

0 commit comments

Comments
 (0)