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}