Crate macro_rules_attribute
source · [−]Expand description
::macro_rules_attribute
Use declarative macros in attribute or derive position.
macro_rules! my_fancy_decorator { /* … */ }
#[apply(my_fancy_decorator!)]
struct Foo { /* … */ }
macro_rules! MyFancyDerive { /* … */ }
#[derive(MyFancyDerive!)]
struct Foo { /* … */ }
Motivation
macro_rules!
macros can be extremely powerful, but their call-site ergonomics
are sometimes not great, especially when decorating item definitions.
Indeed, compare:
foo! {
struct Struct {
some_field: SomeType,
}
}
to:
#[foo]
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 amacro_rules!
macro, it is definitely time to be using aproc
edural macro.Anything involving
ident
generation / derivation, for instance, will very often requireproc
edural macros, unless it is simple enough for::paste
to handle it.
-
Solution
With this crate’s #[apply]
and #[derive]
attributes, it is now possible to use proc_macro_attribute
syntax to apply a
macro_rules!
macro:
#[macro_use]
extern crate macro_rules_attribute;
macro_rules! foo {
// …
}
macro_rules! Bar {
// …
}
#[apply(foo)]
#[derive(Debug, Bar!)]
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
.
Example
Deriving getters for a (non-generic) struct
:
#[macro_use]
extern crate macro_rules_attribute;
macro_rules! make_getters {(
$(#[$struct_meta:meta])*
$struct_vis:vis
struct $StructName:ident {
$(
$(#[$field_meta:meta])*
$field_vis:vis // this visibility will be applied to the getters instead
$field_name:ident : $field_ty:ty
),* $(,)?
}
) => (
// First, generate the struct definition we have been given, but with
// private fields instead.
$(#[$struct_meta])*
$struct_vis
struct $StructName {
$(
$(#[$field_meta])*
// notice the lack of visibility => private fields
$field_name: $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 is_new_born (person: &'_ Person)
-> bool
{
// person.age == 0
// ^ error[E0616]: field `age` of struct `example::Person` is private
*person.age() == 0
}
Debugging
An optional compilation feature, "verbose-expansions"
can be used to print at
compile-time the exact output of each macro invocation from this crate:
[dependencies]
macro_rules_attribute.version = "..."
macro_rules_attribute.features = ["verbose-expansions"]
Bonus tricks
derive
aliases
#[macro_use]
extern crate macro_rules_attribute;
derive_alias! {
#[derive(Ord!)] = #[derive(PartialEq, Eq, PartialOrd, Ord)];
}
#[derive(Debug, Clone, Copy, Ord!)]
struct Foo {
// …
}
- See
derive_alias!
and#[derive]
for more info.
cfg
aliases
#[macro_use]
extern crate macro_rules_attribute;
attribute_alias! {
#[apply(complex_cfg!)] = #[cfg(
any(
any(
foo,
feature = "bar",
),
all(
target_os = "fenestrations",
not(target_arch = "Pear"),
),
),
)];
}
#[apply(complex_cfg!)]
mod some_item { /* … */ }
Macros
Convenience macro to define new attribute aliases.
Convenience macro to define new derive aliases.
Attribute Macros
Applies the given macro_rules!
macro to the decorated item.
Like #[macro_rules_derive]
, but for allowing to be
used to shadow the “built-in” #[derive]
attribute.
Legacy name for what is currently named #[apply]
Applies the given macro_rules!
macro to the decorated item.