::macro_rules_attribute
Use declarative macros as proc_macro attributes or derives.
macro_rules!
macros can be extremely powerful, but their call-site ergonomics
are sometimes not great, especially when decorating item definitions.
Indeed, compare:
```rust
foo! { struct Struct { some_field: SomeType, } } ```
```rust
struct Struct { some_field: SomeType, } ```
The former does not scale well, since it leads to rightward drift and "excessive" braces.
But on the other hand, the latter requires setting up a dedicated crate for
the compiler, a proc-macro
crate. And 99% of the time this will pull the
[::syn
] and [::quote
] dependencies, which have a
non-negligible compile-time overhead (the first time they are compiled).
note: these crates are a wonderful piece of technology, and can lead to
extremely powerful macros. When the logic of the macro is so complicated
that it requires a recursive tt
muncher when implemented as a
macro_rules!
macro, it is definitely time to be using a proc
edural
macro.
Anything involving ident
generation / derivation, for instance, will very
often require proc
edural macros, unless it is simple enough for
[::paste
] to handle it.
With the [macro_rules_attribute
] and [macro_rules_derive
] attributes, it is
now possible to use proc_macro_attribute
syntax to apply a macro_rules!
macro:
```rust
#
struct Struct { some_field: SomeType, } ```
without even depending on [::quote
], [::syn
] or [::proc-macro2
], for
fast compile times.
Deriving getters for a (non-generic) struct
:
```rust
extern crate macrorulesattribute;
macrorules! makegetters {( $(#[$structmeta:meta])* $structvis:vis struct $StructName:ident { $( $(#[$fieldmeta:meta])* $fieldvis:vis // this visibility will be applied to the getters instead $fieldname:ident : $fieldty:ty ),* $(,)? } ) => ( // First, generate the struct definition we have been given, but with // private fields instead. $(#[$structmeta])* $structvis struct $StructName { $( $(#[$fieldmeta])* // notice the lack of visibility => private fields $fieldname: $field_ty, )* }
// Then, implement the getters:
impl $StructName {
$(
#[inline]
$field_vis
fn $field_name (self: &'_ Self)
-> &'_ $field_ty
{
&self.$field_name
}
)*
}
)}
mod example {
#[macro_rules_attribute(make_getters!)]
/// The macro handles meta attributes such as docstrings
pub
struct Person {
pub
name: String,
pub
age: u8,
}
} use example::Person;
fn isnewborn (person: &'_ Person)
-> bool
{
// person.age == 0
// ^ error[E0616]: field age
of struct example::Person
is private
*person.age() == 0
}
```
An optional compilation feature, "verbose-expansions"
can be used to print at
compile_time the exact macro call:
toml
[dependencies]
macro_rules_attribute = { version = "...", features = ["verbose-expansions"] }
#[apply(macro!)]
shorthandJust a convenient shorthand for #[macro_rules_attribute(macro!)]
:
```rust,ignore
extern crate macrorulesattribute;
macrorules! complexcfg {( $item:item ) => ( #[cfg(any( any( foo, feature = "bar", ), all( targetos = "fenestrations", not(targetarch = "Pear"), ), ))] $item )}
mod some_item { /* … */ } ```