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,
}