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}