grafix_toolbox_macros/
derives.rs1use syn::{Attribute, Item, Path, Token, parse, parse_quote, punctuated::Punctuated};
2use {proc_macro::TokenStream, quote::quote};
3type A = Vec<Attribute>;
4
5#[proc_macro_attribute]
6pub fn derive_as_obj(attrs: TokenStream, tgt_struct: TokenStream) -> TokenStream {
7 match_tgt(attrs, tgt_struct, add_object)
8}
9#[proc_macro_attribute]
10pub fn derive_as_val(attrs: TokenStream, tgt_struct: TokenStream) -> TokenStream {
11 match_tgt(attrs, tgt_struct, add_value)
12}
13#[proc_macro_attribute]
14pub fn derive_as_trivial(attrs: TokenStream, tgt_struct: TokenStream) -> TokenStream {
15 match_tgt(attrs, tgt_struct, add_trivial)
16}
17#[proc_macro_attribute]
18pub fn derive_as_ser(attrs: TokenStream, tgt_struct: TokenStream) -> TokenStream {
19 match_tgt(attrs, tgt_struct, pass)
20}
21
22fn match_tgt(a: TokenStream, tgt: TokenStream, add: fn(&mut A) -> &mut A) -> TokenStream {
23 let extra_derives = syn::parse_macro_input!(a as DerivesArgs);
24 match syn::parse_macro_input!(tgt as Item) {
25 Item::Struct(mut i) => {
26 add_serde(add(add_extra(&mut i.attrs, extra_derives.derives)));
27 quote!(#i)
28 }
29 Item::Enum(mut i) => {
30 add_serde(add(add_extra(&mut i.attrs, extra_derives.derives)));
31 quote!(#i)
32 }
33 o => syn::Error::new_spanned(o, "The #[derives_as_*] attribute can only be used on structs or enums").to_compile_error(),
34 }
35 .into()
36}
37
38fn add_extra(attrs: &mut A, derives: Punctuated<Path, Token![,]>) -> &mut A {
39 if derives.is_empty() {
40 return attrs;
41 }
42
43 attrs.push(parse_quote!(#[derive(#derives)]));
44 attrs
45}
46fn pass(attrs: &mut A) -> &mut A {
47 attrs
48}
49fn add_object(attrs: &mut A) -> &mut A {
50 attrs.push(parse_quote!(#[derive(Debug, Clone)]));
51 attrs
52}
53fn add_value(attrs: &mut A) -> &mut A {
54 attrs.push(parse_quote!(#[derive(Copy, PartialEq, PartialOrd)]));
55 add_object(attrs)
56}
57fn add_trivial(attrs: &mut A) -> &mut A {
58 attrs.push(parse_quote!(#[derive(Default)]));
59 add_value(attrs)
60}
61fn add_serde(attrs: &mut A) -> &mut A {
62 #[cfg(feature = "serde")]
63 {
64 attrs.push(parse_quote!(#[derive(serde::Serialize, serde::Deserialize)]));
65 attrs.push(parse_quote!(#[serde(crate = "serde")]));
66 }
67 attrs
68}
69
70struct DerivesArgs {
71 derives: Punctuated<Path, Token![,]>,
72}
73impl parse::Parse for DerivesArgs {
74 fn parse(input: parse::ParseStream) -> syn::Result<Self> {
75 let derives = Punctuated::<Path, Token![,]>::parse_terminated(input)?;
76 Ok(DerivesArgs { derives })
77 }
78}