macro_rules_attribute

Macro derive_alias

Source
macro_rules! derive_alias {
    (
    $(
        #[derive($MacroName:ident !)] = #[derive($($derives:tt)*)];
    )*
) => { ... };
}
Expand description

Convenience macro to define new derive aliases.

The so-defined macros are intended to be used by #[macro_rules_derive] or this crate’s #[derive].

§Examples

#[macro_use]
extern crate macro_rules_attribute;

derive_alias! {
   #[derive(Copy!)] = #[derive(Clone, Copy)];
   #[derive(Eq!)] = #[derive(PartialEq, Eq)];
   #[derive(Ord!)] = #[derive(Eq!, PartialOrd, Ord)];
}

#[derive(Debug, Copy!, Ord!)]
struct Foo {
   // …
}

// Note: this defines `Copy!`, `Eq!` and `Ord!` as properly scoped
// `crate`-local macros.
mod example {
   use super::Copy;

   #[derive(Copy!, super::Eq!)]
   struct Bar;
}
#[macro_use]
extern crate macro_rules_attribute;

use ::core::{fmt::Debug, hash::Hash};

/// Trait alias pattern: `T : TheUsualSuspects ⇔ T : Debug + Copy + Ord + Hash`.
trait TheUsualSuspects
where // `⇒` direction
   Self : Debug + Copy + Ord + Hash,
{}
impl<T : ?Sized> TheUsualSuspects for T
where // `⇐` direction
   Self : Debug + Copy + Ord + Hash,
{}

derive_alias! {
   #[derive(TheUsualSuspects!)] = #[derive(
       Debug,
       Copy,   Clone,
       Ord,    PartialOrd, Eq, PartialEq,
       Hash,
   )];
}

#[derive(TheUsualSuspects!)]
struct KeyserSöze;

const _: () = {
   fn compile_time_assert_impls<T : ?Sized> ()
   where
       T : TheUsualSuspects,
   {}

   let _ = compile_time_assert_impls::<KeyserSöze>;
};

§Caveat regarding derive helpers (inert-made attributes)

Click to see

Some derive attributes (such as {De,}Serialize), can involve helper attributes (such as #[serde]). This yields inert derive-helper-attributes, which represent a semantic aspect of the derive that non-compiler-blessed macros such as this one cannot possibly know about.

This makes aliasing such derives problematic, since the derive aliases won’t be able to handle the helper attributes.

#[macro_use]
extern crate macro_rules_attribute;

derive_alias! {
   #[derive(Serde!)] = #[derive(::serde::Deserialize, ::serde::Serialize)];
}

#[derive(Serde!)]
#[serde(rename_all = "snake_case")] // Error, unknown `#[serde]` attribute
struct Mejrs {
   swaginess: u8,
}

The above, for instance, yields something along the lines of:

error: cannot find attribute "serde" in this scope
  --> src/lib.rs:11:3
   |
11 | #[serde(rename_all = "snake_case")]
   |   ^^^^^
   |
   = note: "serde" is in scope, but it is a crate, not an attribute

The only solution is to forgo the niceties of a derive_alias!, and define your own #[apply]-able macro_rules_attribute that aliases the #[derive(…)] attribute as a whole. attribute_alias! can come in handy in such situations:

#[macro_use]
extern crate macro_rules_attribute;

attribute_alias! {
   #[apply(derive_Serde)] = #[derive(::serde::Deserialize, ::serde::Serialize)];
}

#[apply(derive_Serde)]
#[serde(rename_all = "snake_case")] // OK
struct Mejrs {
   swaginess: u8,
}