pfc_whitelist_derive/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, Attribute, DataEnum, DeriveInput};
4
5/// Merges the variants of two enums.
6///
7/// Adapted from DAO DAO:
8/// https://github.com/DA0-DA0/dao-contracts/blob/74bd3881fdd86829e5e8b132b9952dd64f2d0737/packages/dao-macros/src/lib.rs#L9
9// Merges the variants of two enums.
10fn merge_variants(metadata: TokenStream, left: TokenStream, right: TokenStream) -> TokenStream {
11    use syn::Data::Enum;
12
13    let args = parse_macro_input!(metadata with Attribute::parse_outer);
14    if let Some(first_arg) = args.first() {
15        return syn::Error::new_spanned(first_arg, "macro takes no arguments")
16            .to_compile_error()
17            .into();
18    }
19
20    let mut left: DeriveInput = parse_macro_input!(left);
21    let right: DeriveInput = parse_macro_input!(right);
22
23    if let (
24        Enum(DataEnum {
25            variants,
26            ..
27        }),
28        Enum(DataEnum {
29            variants: to_add,
30            ..
31        }),
32    ) = (&mut left.data, right.data)
33    {
34        variants.extend(to_add);
35
36        quote! { #left }.into()
37    } else {
38        syn::Error::new(left.ident.span(), "variants may only be added for enums")
39            .to_compile_error()
40            .into()
41    }
42}
43
44/// Append dust-collection execute messages variant(s) to an enum.
45///
46/// For example, apply the `pfc_dust_collect` macro to the following enum:
47///
48/// ```rust
49/// use cosmwasm_schema::cw_serde;
50/// use pfc_whitelist_derive::pfc_whitelist_exec;
51///
52/// #[pfc_whitelist_exec]
53/// #[cw_serde]
54/// enum ExecuteMsg {
55///     Foo {},
56///     Bar {},
57/// }
58/// ```
59///
60/// Is equivalent to:
61///
62/// ```rust
63/// use cosmwasm_schema::cw_serde;
64///
65/// #[cw_serde]
66/// enum ExecuteMsg {
67///     AddToWhiteList {
68///         address: String,
69///         reason: Option<String>,
70///     },
71///     RemoveFromWhiteList {
72///         address: String,
73///     },
74///     Foo {},
75///     Bar {},
76/// }
77/// ```
78///
79/// Note: `#[pfc_whitelist_exec]` must be applied _before_ `#[cw_serde]`.
80#[proc_macro_attribute]
81pub fn pfc_whitelist_exec(metadata: TokenStream, input: TokenStream) -> TokenStream {
82    merge_variants(
83        metadata,
84        input,
85        quote! {
86            enum Right {
87                ///  Add an entry
88                AddToWhiteList {address:String, reason:Option<String>},
89                /// Remove an Entry
90                RemoveFromWhitelist{address:String} ,
91            }
92        }
93        .into(),
94    )
95}
96#[proc_macro_attribute]
97pub fn pfc_whitelist_query(metadata: TokenStream, input: TokenStream) -> TokenStream {
98    merge_variants(
99        metadata,
100        input,
101        quote! {
102            enum Right {
103                #[returns(Option<::pfc_whitelist::Whitelist>)]
104                WhitelistEntry {address:String},
105                #[returns(::pfc_whitelist::WhitelistResponse<::pfc_whitelist::Whitelist>)]
106                Whitelist {start_after:Option<String>, limit: Option<u32>},
107            }
108        }
109        .into(),
110    )
111}