::macro_rules_attribute

Use declarative macros as proc_macro attributes or derives.

Latest version Documentation License

Motivation

macro_rules! macros can be extremely powerful, but their call-site ergonomics are sometimes not great, especially when decorating item definitions.

Indeed, compare:

  1. ```rust

    #[cfg(any())]

    foo! { struct Struct { some_field: SomeType, } } ```

  2. ```rust

    #[cfg(any())]

    [foo]

    struct Struct { some_field: SomeType, } ```


  1. The former does not scale well, since it leads to rightward drift and "excessive" braces.

  2. 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).


Solution

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

use ::macrorulesattribute::macrorulesattribute;

macro_rules! foo {($($tt:tt)*) => ()}

#

[macrorulesattribute(foo!)]

struct Struct { some_field: SomeType, } ```

without even depending on [::quote], [::syn] or [::proc-macro2], for fast compile times.

Example

Deriving getters for a (non-generic) struct:

```rust

macro_rules! ignore {($($tt:tt)*) => () }

ignore! {

[macro_use]

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 {

use ::macrorulesattribute::macrorulesattribute;

#[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 } ```

Debugging

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"] }

The #[apply(macro!)] shorthand

Just a convenient shorthand for #[macro_rules_attribute(macro!)]:

Example

```rust,ignore

[macro_use]

extern crate macrorulesattribute;

macrorules! complexcfg {( $item:item ) => ( #[cfg(any( any( foo, feature = "bar", ), all( targetos = "fenestrations", not(targetarch = "Pear"), ), ))] $item )}

[apply(complex_cfg!)]

mod some_item { /* … */ } ```