::macro_rules_attribute
Use declarative macros in attribute or derive position.
```rust ,ignore macrorules! myfancy_decorator { /* … */ }
struct Foo { /* … */ } ```
```rust ,ignore macro_rules! MyFancyDerive { /* … */ }
struct Foo { /* … */ } ```
macro_rules!
macros can be extremely powerful, but their call-site ergonomics
are sometimes not great, especially when decorating item definitions.
Indeed, compare:
rust ,ignore
foo! {
struct Struct {
some_field: SomeType,
}
}
to:
```rust ,ignore
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 this crate's #[[apply]]
and #[[derive]]
attributes, it is now possible to use proc_macro_attribute
syntax to apply a
macro_rules!
macro:
```rust
extern crate macrorulesattribute;
macro_rules! foo { // … # ( $($tt:tt)* ) => () }
macro_rules! Bar { // … # ( $($tt:tt)* ) => () }
struct Struct { some_field: SomeType, } #
```
without even depending on [::quote
], [::syn
] or [::proc-macro2
], for
fast compile times.
Note: for even faster compile times, feel free to disable the derive-alias
Cargo feature, should you not use it.
On my machine, that feature requires around 0.3s of extra compile-time,
which is not much, but still a 25% increase w.r.t. --no-default-features
.
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 { #[apply(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 output of each macro invocation from this crate:
toml
[dependencies]
macro_rules_attribute.version = "..."
macro_rules_attribute.features = ["verbose-expansions"]
derive
aliases```rust
extern crate macrorulesattribute;
derive_alias! { #[derive(Ord!)] = #[derive(PartialEq, Eq, PartialOrd, Ord)]; }
struct Foo { // … } ```
derive_alias!
] and #[[derive]]
for more info.cfg
aliases```rust
extern crate macrorulesattribute;
attributealias! { #[apply(complexcfg!)] = #[cfg( any( any( foo, feature = "bar", ), all( targetos = "fenestrations", not(targetarch = "Pear"), ), ), )]; }
mod some_item { /* … */ } ```