macro_attr_2018/
lib.rs

1// Copyright (c) 2016 macro-attr contributors.
2// Copyright (c) 2020 Warlock <internalmike@gmail.com>.
3// Copyright (c) 2020 Clint Armstrong <clint@clintarmstrong.net>.
4//
5// Licensed under the MIT license (see LICENSE or <http://opensource.org
6// /licenses/MIT>) or the Apache License, Version 2.0 (see LICENSE of
7// <http://www.apache.org/licenses/LICENSE-2.0>), at your option. All
8// files in the project carrying such notice may not be copied, modified,
9// or distributed except according to those terms.
10
11#![deny(warnings)]
12#![doc(test(attr(deny(warnings))))]
13#![doc(test(attr(allow(dead_code))))]
14#![doc(test(attr(allow(unused_variables))))]
15#![doc(test(attr(allow(unused_macros))))]
16#![doc(test(attr(allow(unknown_lints, unused_macro_rules))))]
17
18//! This crate provides the `macro_attr!` macro that enables the use of custom,
19//! macro-based attributes and derivations.
20//!
21//! The `macro_attr!` macro should be used to wrap an entire *single* item
22//! (`enum`, `struct`, *etc.*) declaration, including its attributes (both `derive` and others).
23//! All attributes and derivations which whose names end with `!` will be assumed
24//! to be implemented by macros, and treated accordingly.
25//!
26//! ```rust
27//! use macro_attr_2018::macro_attr;
28//!
29//! // Define some traits to be derived.
30//!
31//! trait TypeName {
32//!     fn type_name() -> &'static str;
33//! }
34//!
35//! trait ReprType {
36//!     type Repr;
37//! }
38//!
39//! // Define macros which derive implementations of these macros.
40//!
41//! macro_rules! TypeName {
42//!     // We can support any kind of item we want.
43//!     (() $vis:vis enum $name:ident $($tail:tt)+) => { TypeName! { @impl $name } };
44//!     (() $vis:vis struct $name:ident $($tail:tt)+) => { TypeName! { @impl $name } };
45//!
46//!     // Inner rule to cut down on repetition.
47//!     (@impl $name:ident) => {
48//!         impl TypeName for $name {
49//!             fn type_name() -> &'static str { stringify!($name) }
50//!         }
51//!     };
52//! }
53//!
54//! macro_rules! ReprType {
55//!     // Note that we use a "derivation argument" here for the `$repr` type.
56//!     (($repr:ty) $vis:vis enum $name:ident $($tail:tt)+) => {
57//!         impl ReprType for $name {
58//!             type Repr = $repr;
59//!         }
60//!     };
61//! }
62//!
63//! // Derive.
64//!
65//! macro_attr! {
66//!     #[derive(TypeName!, ReprType!(u16))]
67//!     #[repr(u16)]
68//!     enum SomeEnum { A, B, C, D }
69//! }
70//!
71//! # fn main() {
72//! assert_eq!(SomeEnum::type_name(), "SomeEnum");
73//! assert_eq!(SomeEnum::A as <SomeEnum as ReprType>::Repr, 0u16);
74//! # }
75//! ```
76
77#![no_std]
78
79#[doc=include_str!("../README.md")]
80type _DocTestReadme = ();
81
82/// When given an item definition, including its attributes, this macro parses said attributes
83/// and dispatches any derivations suffixed with `!` to user-defined macros.
84///
85/// This allows multiple macros to process the same item.
86///
87/// Given the following input:
88///
89/// ```ignore
90/// #[derive(Copy, Name!(args...), Clone, Another!, Debug)]
91/// struct Foo;
92/// ```
93///
94/// `macro_attr!` will expand to the equivalent of:
95///
96/// ```ignore
97/// #[derive(Copy, Clone, Debug)]
98/// struct Foo;
99///
100/// Name!((args...) struct Foo;);
101/// Another!(() struct Foo;);
102/// ```
103///
104/// Note that macro derives may be mixed with regular derives,
105/// or put in their own `#[derive(...)]` attribute.
106/// Also note that macro derive invocations are *not* passed the other attributes on the item;
107/// input will consist of the arguments provided to the derivation (*i.e.* `(args...)`
108/// in this example), the item's visibility (if any), and the item definition itself.
109///
110/// A macro derivation invoked *without* arguments will be treated as though
111/// it was invoked with empty parentheses.  *i.e.* `#[derive(Name!)]` is equivalent to `#[derive(Name!())]`.
112///
113/// A derivation macro may expand to any number of new items derived from the provided input.
114#[macro_export]
115macro_rules! macro_attr {
116    (
117        $(#[$($attrs:tt)+])*
118        $(pub $(($($vis:tt)+))?)? enum $($it:tt)+
119    ) => {
120        $crate::macro_attr_impl! {
121            @split_attrs [$(pub $(($($vis)+))?)? enum $($it)+]
122            [] []
123            [$([$($attrs)+])*]
124        }
125    };
126    (
127        $(#[$($attrs:tt)+])*
128        $(pub $(($($vis:tt)+))?)? struct $($it:tt)+
129    ) => {
130        $crate::macro_attr_impl! {
131            @split_attrs [$(pub $(($($vis)+))?)? struct $($it)+]
132            [] []
133            [$([$($attrs)+])*]
134        }
135    };
136    (
137        $(#[$($attrs:tt)+])*
138        $(pub $(($($vis:tt)+))?)? trait $($it:tt)+
139    ) => {
140        $crate::macro_attr_impl! {
141            @split_attrs [$(pub ($($vis)+))? trait $($it)+]
142            [] []
143            [$([$($attrs)+])*]
144        }
145    };
146    (
147        $(#[$($attrs:tt)+])*
148        $vis:vis $keyword:ident $($it:tt)+
149    ) => {
150        $crate::macro_attr_impl! {
151            @split_attrs [$vis $keyword $($it)+]
152            [] []
153            [$([$($attrs)+])*]
154        }
155    };
156}
157
158#[doc(hidden)]
159#[macro_export]
160macro_rules! macro_attr_impl {
161    (
162        @split_attrs [$($it:tt)+]
163        [$($derive_attrs:tt)*] [$([$other_attrs:meta])*]
164        [[derive($($derive_attr:tt)+)] $([$($attrs:tt)+])*]
165    ) => {
166        $crate::macro_attr_impl! {
167            @split_attrs [$($it)+]
168            [$($derive_attrs)* [$($derive_attr)+]]
169            [$([$other_attrs])*]
170            [$([$($attrs)+])*]
171        }
172    };
173    (
174        @split_attrs [$($it:tt)+]
175        [$($derive_attrs:tt)*] [$([$other_attrs:meta])*]
176        [[$attr:meta] $([$($attrs:tt)+])*]
177    ) => {
178        $crate::macro_attr_impl! {
179            @split_attrs [$($it)+]
180            [$($derive_attrs)*]
181            [$([$other_attrs])* [$attr]]
182            [$([$($attrs)+])*]
183        }
184    };
185    (
186        @split_attrs [$($it:tt)+]
187        [$($derive_attrs:tt)*] [$([$other_attrs:meta])*]
188        []
189    ) => {
190        $crate::macro_attr_impl! {
191            @split_derive_attrs [$($it)+] [$([$other_attrs])*]
192            [] []
193            [$($derive_attrs)*]
194        }
195    };
196    (
197        @split_derive_attrs [$($it:tt)+] [$([$other_attrs:meta])*]
198        [$($macro_derives:tt)*] [$($std_derives:tt)*]
199        [
200            [$macro_derive:ident ! $(($($macro_derive_args:tt)*))? $(, $($other_inner_derives:tt)*)?]
201            $([$($other_derives:tt)*])*
202        ]
203    ) => {
204        $crate::macro_attr_impl! {
205            @split_derive_attrs [$($it)+] [$([$other_attrs])*]
206            [
207                $($macro_derives)*
208                [$macro_derive ( $($($macro_derive_args)*)? )]
209            ]
210            [
211                $($std_derives)*
212            ]
213            [
214                $([$($other_inner_derives)*])?
215                $([$($other_derives)*])*
216            ]
217        }
218    };
219    (
220        @split_derive_attrs [$($it:tt)+] [$([$other_attrs:meta])*]
221        [$($macro_derives:tt)*] [$($std_derives:tt)*]
222        [
223            [$std_derive:ident $(($($std_derive_args:tt)*))? $(, $($other_inner_derives:tt)*)?]
224            $([$($other_derives:tt)*])*
225        ]
226    ) => {
227        $crate::macro_attr_impl! {
228            @split_derive_attrs [$($it)+] [$([$other_attrs])*]
229            [
230                $($macro_derives)*
231            ]
232            [
233                $($std_derives)*
234                #[derive($std_derive $(($($std_derive_args)*))?)]
235            ]
236            [
237                $([$($other_inner_derives)*])?
238                $([$($other_derives)*])*
239            ]
240        }
241    };
242    (
243        @split_derive_attrs [$($it:tt)+] [$([$other_attrs:meta])*]
244        [$($macro_derives:tt)*] [$($std_derives:tt)*]
245        [
246            []
247            $([$($other_derives:tt)*])*
248        ]
249    ) => {
250        $crate::macro_attr_impl! {
251            @split_derive_attrs [$($it)+] [$([$other_attrs])*]
252            [
253                $($macro_derives)*
254            ]
255            [
256                $($std_derives)*
257            ]
258            [
259                $([$($other_derives)*])*
260            ]
261        }
262    };
263    (
264        @split_derive_attrs [$($it:tt)+] [$([$other_attrs:meta])*]
265        [$([$macro_derive:ident ( $($macro_derive_args:tt)* )])*]
266        [$($std_derives:tt)*]
267        []
268    ) => {
269        $crate::macro_attr_impl! {
270            @as_item
271            $($std_derives)*
272            $(#[$other_attrs])*
273            $($it)+
274        }
275        $crate::macro_attr_impl! {
276            @expand [$($it)+]
277            [$([$macro_derive ( $($macro_derive_args)* )])*]
278        }
279    };
280    (
281        @expand [$($it:tt)+]
282        [
283            [$macro_derive:ident ( $($macro_derive_args:tt)* )]
284            $([$other_macro_derives:ident ( $($other_macro_derives_args:tt)* )])*
285        ]
286    ) => {
287        $macro_derive! {
288            ( $($macro_derive_args)* )
289            $($it)+
290        }
291        $crate::macro_attr_impl! {
292            @expand [$($it)+]
293            [$([$other_macro_derives ( $($other_macro_derives_args)* )])*]
294        }
295    };
296    (
297        @expand [$($it:tt)+]
298        []
299    ) => {
300    };
301    (@as_item $($i:item)*) => {$($i)*};
302}