When using the newtype pattern I often have lengthy derives:
extern crate derive_more;
use derive_more::*;
#[derive(Add, Sub, Mul, Div, ..., Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
struct Foo(i32);
Is there a way to shorten this to something like this:
#[derive(Num)]
struct Foo(i32);
Where Num
is a derive macro?
I found this, but it seems like one can't expand macros in attributes. This answer discusses how attributes must be attached to items, ruling this out:
#[proc_macro_derive(Num)]
pub fn num_derive(_: TokenStream) -> TokenStream {
let gen = quote! {
#[derive(Add, Sub, Mul, Div, ..., Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
};
gen.into()
}
As you mentioned, emitted attributes must be attached to an item, making a proc-macro like this impossible:
#[proc_macro_derive(Num)]
pub fn num_derive(_: TokenStream) -> TokenStream {
let gen = quote! {
#[derive(Eq, PartialEq, Ord, PartialOrd)]
};
gen.into()
}
proc-macros
also come with the hassle of having to be defined in a separate crate, so generating them, or creating simple ones for ergonomic reasons is not worth it.
With proc-macros ruled out, we can look to macro_rules
. They have the same restriction regarding attributes. However, it is possible to wrap an item definition in a proc-macro and attach attributes to it:
macro_rules! derive_stuff {
($i:item) => {
#[derive(Eq, PartialEq, Ord, PartialOrd)]
$i
}
}
derive_stuff! { struct Foo(i32); }
Given this, we can create a macro that generates a macro like above:
macro_rules! derive_alias {
($name:ident => #[derive($($derive:ident),*)]) => {
macro_rules! $name {
($i:item) => {
#[derive($($derive),*)]
$i
}
}
}
}
derive_alias! {
derive_stuff => #[derive(Eq, PartialEq, Ord, PartialOrd)]
}
derive_stuff! { struct Foo(i32); }
So I created a crate (derive_alias
) that does exactly that:
use derive_alias::derive_alias;
use derive_more::*;
derive_alias! {
derive_num => #[derive(Add, Sub, Mul, Div, ..., Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
}
derive_num! { struct Foo(i32); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With