Attribute Macro macro_rules_attribute::apply

source ·
#[apply]
Expand description

Applies the given macro_rules! macro to the decorated item.

This, as with any proc_macro_attribute, consumes the item it decorates: it is the macro_rules! macro job to generate it (it is thus able to modify it!).

For a version with “read-only” access to the item it decorates, see macro_rules_derive.

Examples

Deriving getters for a (non-generic) struct

Imagine having define the following handy make_getters! (macro_rules!) macro:

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
           }
       )*
   }
)}

Basically allowing you to write:

use example::Person;
mod example {
   make_getters! {
       /// The macro handles meta attributes such as docstrings
       pub
       struct Person {
           pub
           name: String,

           pub
           age: u8,
       }
   }
}

fn is_new_born (person: &'_ mut Person)
 -> bool
{
   // Reading the value through the getter is fine…
   return *person.age() == 0;
   // But trying to mutate it by skipping the getter is not 💪
   person.age = 0;
// ^ error[E0616]: field `age` of struct `example::Person` is private
}

This is fine, etc., but that rightward drift on make_getters! { syntax problematic:

  • Incurs in extra rightward drift and thus, noise.

  • Worse, it leads to a non-escalable / composable pattern: if we had a second macro, say make_setters!, our syntax is unable to handle both macros being called on the same type definition.

Hence ::macro_rules_attribute’s #[apply] (formerly called #[macro_rules_attribute] itself) helper:

#[macro_use]
extern crate macro_rules_attribute;

use example::Person;
mod example {
   #[apply(make_getters!)] // or `#[apply(make_getters)]`: the final `!` is not mandatory
   /// The macro handles meta attributes such as docstrings
   pub
   struct Person {
       pub
       name: String,

       pub
       age: u8,
   }

}

fn is_new_born (person: &'_ Person)
 -> bool
{
   // Reading the value through the getter is fine…
   *person.age() == 0
   // But trying to mutate it by skipping the getter is not 💪
   // person.age == 0
   // ^ error[E0616]: field `age` of struct `example::Person` is private
}