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