pfc_dust_collector_derive/lib.rs
1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, AttributeArgs, 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 as AttributeArgs);
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 cw_ownable::cw_ownable_execute;
51/// use pfc_dust_collector_derive::pfc_dust_collect;
52///
53/// #[pfc_dust_collect]
54/// #[cw_serde]
55/// enum ExecuteMsg {
56/// Foo {},
57/// Bar {},
58/// }
59/// ```
60///
61/// Is equivalent to:
62///
63/// ```rust
64/// use cosmwasm_schema::cw_serde;
65///
66///
67/// #[cw_serde]
68/// enum ExecuteMsg {
69/// DustReceived {},
70/// FlushDust {},
71/// SetReturnContract { contract:String },
72
73/// }
74/// ```
75///
76/// Note: `#[pfc_dust_collect]` must be applied _before_ `#[cw_serde]`.
77#[proc_macro_attribute]
78pub fn pfc_dust_collect(metadata: TokenStream, input: TokenStream) -> TokenStream {
79 merge_variants(
80 metadata,
81 input,
82 quote! {
83 enum Right {
84 /// Receive dust from somewhere
85 DustReceived {},
86 /// Flush the dust
87 FlushDust{} ,
88 SetReturnContract{ contract: String },
89 }
90 }
91 .into(),
92 )
93}