luru20_cw_ownable_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
9fn merge_variants(metadata: TokenStream, left: TokenStream, right: TokenStream) -> TokenStream {
10    use syn::Data::Enum;
11
12    // parse metadata
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    // parse the left enum
21    let mut left: DeriveInput = parse_macro_input!(left);
22    let Enum(DataEnum {
23        variants,
24        ..
25    }) = &mut left.data else {
26        return syn::Error::new(left.ident.span(), "only enums can accept variants")
27            .to_compile_error()
28            .into();
29    };
30
31    // parse the right enum
32    let right: DeriveInput = parse_macro_input!(right);
33    let Enum(DataEnum {
34        variants: to_add,
35        ..
36    }) = right.data else {
37        return syn::Error::new(left.ident.span(), "only enums can provide variants")
38            .to_compile_error()
39            .into();
40    };
41
42    // insert variants from the right to the left
43    variants.extend(to_add.into_iter());
44
45    quote! { #left }.into()
46}
47
48/// Append ownership-related execute message variant(s) to an enum.
49///
50/// For example, apply the `cw_ownable_execute` macro to the following enum:
51///
52/// ```rust
53/// use cosmwasm_schema::cw_serde;
54/// use luru20_cw_ownable::cw_ownable_exeucte;
55///
56/// #[cw_ownable_execute]
57/// #[cw_serde]
58/// enum ExecuteMsg {
59///     Foo {},
60///     Bar {},
61/// }
62/// ```
63///
64/// Is equivalent to:
65///
66/// ```rust
67/// use cosmwasm_schema::cw_serde;
68/// use luru20_cw_ownable::Action;
69///
70/// #[cw_serde]
71/// enum ExecuteMsg {
72///     UpdateOwnership(Action),
73///     Foo {},
74///     Bar {},
75/// }
76/// ```
77///
78/// Note: `#[cw_ownable_execute]` must be applied _before_ `#[cw_serde]`.
79#[proc_macro_attribute]
80pub fn cw_ownable_execute(metadata: TokenStream, input: TokenStream) -> TokenStream {
81    merge_variants(
82        metadata,
83        input,
84        quote! {
85            enum Right {
86                /// Update the contract's ownership. The `action` to be provided
87                /// can be either to propose transferring ownership to an account,
88                /// accept a pending ownership transfer, or renounce the ownership
89                /// permanently.
90                UpdateOwnership(::luru20_cw_ownable::Action),
91            }
92        }
93        .into(),
94    )
95}
96
97/// Append ownership-related query message variant(s) to an enum.
98///
99/// For example, apply the `cw_ownable_query` macro to the following enum:
100///
101/// ```rust
102/// use cosmwasm_schema::{cw_serde, QueryResponses};
103/// use luru20_cw_ownable::cw_ownable_query;
104///
105/// #[cw_ownable_query]
106/// #[cw_serde]
107/// #[derive(QueryResponses)]
108/// enum QueryMsg {
109///     #[returns(FooResponse)]
110///     Foo {},
111///     #[returns(BarResponse)]
112///     Bar {},
113/// }
114/// ```
115///
116/// Is equivalent to:
117///
118/// ```rust
119/// use cosmwasm_schema::cw_serde;
120/// use luru20_cw_ownable::Ownership;
121///
122/// #[cw_serde]
123/// #[derive(QueryResponses)]
124/// enum QueryMsg {
125///     #[returns(Ownership<String>)]
126///     Ownership {},
127///     #[returns(FooResponse)]
128///     Foo {},
129///     #[returns(BarResponse)]
130///     Bar {},
131/// }
132/// ```
133///
134/// Note: `#[cw_ownable_query]` must be applied _before_ `#[cw_serde]`.
135#[proc_macro_attribute]
136pub fn cw_ownable_query(metadata: TokenStream, input: TokenStream) -> TokenStream {
137    merge_variants(
138        metadata,
139        input,
140        quote! {
141            enum Right {
142                /// Query the contract's ownership information
143                #[returns(::luru20_cw_ownable::Ownership<String>)]
144                Ownership {},
145            }
146        }
147        .into(),
148    )
149}