1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
//! What `#[announce(..)]` does, as functions that another proc-macro crate can call.
//!
//! A library that builds or rewrites items in its own proc macros can announce
//! them without emitting the attribute `#[announce(..)]`. It calls [`announce`] on
//! the tokens of the item and returns the result, which is exactly what the
//! attribute produces. The options are those of the
//! [`#[announce]`](macro@crate::announce#options) attribute. A derive macro cannot do
//! this, because a derive cannot change its item: ask your users for `#[announce]`, or
//! make an attribute macro.
//!
//! This module needs the feature `proc-macro-api` of `announce`, which is on by
//! default (`default-features = false` leaves it out, for `no_std` definitions).
//!
//! ```toml
//! # Cargo.toml of the library's proc-macro crate
//! announce = "0.2"
//! ```
//!
//! ```ignore
//! #[proc_macro_attribute]
//! pub fn my_attr(attr: TokenStream, item: TokenStream) -> TokenStream {
//! // Parse and rewrite the item ...
//! let item: proc_macro2::TokenStream = rewrite(item.into());
//!
//! // ... then announce it, with the options of `#[announce(..)]`.
//! let mut opts: announce::machinery::Options = syn::parse(attr).unwrap();
//! opts.krate = Some(syn::parse_quote!(::my_lib::announce));
//! announce::machinery::announce(quote::ToTokens::to_token_stream(&opts), item).into()
//! }
//! ```
//!
//! # The path to the `announce` crate
//!
//! The generated code names the `announce` crate: for the hidden derive and
//! attribute that capture the item (`announce::__private`), and for the
//! [`Announce`](crate::Announce) impl. That path is the `crate = ..` option
//! ([`Options::krate()`]). Without the option it is read from the `Cargo.toml` of
//! the crate being compiled, which is the crate that uses the library's macro. It
//! is the name that crate gives to its `announce` dependency, or `::announce` if
//! there is none.
//!
//! So a library whose users do not depend on `announce` must pass the option, with
//! a path that its users can reach. The library re-exports the crate
//! (`#[doc(hidden)] pub use announce;`, next to the re-export of its macros), and
//! the macro passes `crate = ::my_lib::announce`. If the users do depend on
//! `announce`, nothing is needed.
//!
//! # Output
//!
//! The output is the output of the attribute, token for token. If the item has no other
//! outer attribute, nothing can expand after the attribute: the output is the item as given
//! (unless `emit_item = false` or `mock`), followed by a hidden `#[derive]` on a dummy
//! enum that carries the item and emits the trampoline. The derive runs after rustc has
//! evaluated the `#[cfg]` attributes in the item, in the crate that expands the macro. So
//! the item may hold `#[cfg]` attributes, and the macro must be expanded in item position.
//!
//! ```
//! use announce::machinery::announce;
//! use proc_macro2::TokenStream;
//!
//! let attr: TokenStream = "crate = ::my_lib::announce, macro_name = Hello".parse().unwrap();
//! let item: TokenStream = "pub struct S { pub a: u8 }".parse().unwrap();
//! let out = announce(attr, item).to_string();
//! assert!(out.contains(":: my_lib :: announce :: __private :: Capture"));
//! ```
//!
//! # Several announcements
//!
//! [`announce`] goes the way of the attribute in this as well. If the item has other outer
//! attributes, the output is the item with the hidden attribute
//! `#[<crate path>::__private::__announce_runner(..)]`, the *runner*, as its last
//! attribute, and, after the item, a *sentinel* (an item that fails at the definition if the
//! runner never runs, for example because a macro below returned the item without its
//! attributes). The runner holds the options (and the version of its encoding), and when it
//! expands, after everything else on the item, it makes the trampoline. If the item has a
//! runner already, because another announcement was expanded first, the options are merged
//! into it, with no sentinel. The output of a macro that calls [`announce`] must be an item
//! (or items) that the compiler expands, so that the runner is expanded. An announcement
//! with `mock` or `emit_item = false` goes the same way (the runner drops the item). See
//! [Several announcements on one
//! item](macro@crate::announce#several-announcements-on-one-item).
//!
//! ```
//! use announce::machinery::announce;
//! use proc_macro2::TokenStream;
//!
//! let attr: TokenStream = "crate = ::my_lib::announce, meta = my_lib::info".parse().unwrap();
//! let item: TokenStream = "#[derive(Debug)] pub struct S;".parse().unwrap();
//! let out = announce(attr, item).to_string();
//! assert!(out.contains("__private ::__announce_runner"));
//! assert!(out.contains("__announce_format_version = \"1\""));
//! assert!(out.contains("__announce_sentinel = \"impl\""));
//! assert!(out.contains("__AnnounceSentinel"));
//! assert!(!out.contains("Capture"));
//! ```
//!
//! # Checks
//!
//! With checks in the options (`my_lib::check`), the output is not that yet. It is
//! a call of the first check, with the attribute *query* that asks each check
//! which attributes it owns (the protocol is in
//! [`announce::helper::attrs`][attrs]). The last element of the query's list is
//! `<crate path>::__private::finish!`, a hidden macro of the `announce` crate. The
//! path in `crate = ..` must reach it, which a library that re-exports `announce`
//! does. `finish!` expands to the output above, without the attributes that the
//! checks own. [`finish`] is the function behind that macro; a library does not
//! call it.
//!
//! ```
//! use announce::machinery::announce;
//! use proc_macro2::TokenStream;
//!
//! let attr: TokenStream = "crate = ::my_lib::announce, ::my_lib::check".parse().unwrap();
//! let item: TokenStream = "pub struct S { #[my_lib(skip)] pub a: u8 }".parse().unwrap();
//! let out = announce(attr, item).to_string();
//! assert!(out.starts_with(":: my_lib :: check ! { @ announce_format \"1\" @ __announce_attrs"));
//! // The list starts with the macro that is called, and ends with `finish!`.
//! assert!(out.contains("[:: my_lib :: check ! , :: my_lib :: announce :: __private :: finish !]"));
//! ```
//!
//! # The repeater trait
//!
//! [`define_repeater`] does what [`announce::define_repeater!`](macro@crate::define_repeater)
//! does. Use it in a library whose own macro defines the repeater trait in the
//! users' crates. It needs Rust 1.59 where it is expanded.
//!
//! # Errors
//!
//! [`announce`] returns an error as a `compile_error!` invocation in the tokens, which a
//! proc macro can return as it is. [`try_announce`] returns the `syn::Error`, to combine
//! it with others or to report it with another span. The API uses the types of
//! `proc-macro2` 1 and `syn` 2.
//!
//! [attrs]: crate::helper::attrs
pub use ;