abstract_macros/
lib.rs

1extern crate proc_macro2;
2use proc_macro::TokenStream;
3use quote::quote;
4use syn::{parse_macro_input, AttributeArgs, Fields, Item};
5
6const DELIMITER: &str = ",";
7
8/// Add the abstract event with action to a cosmwasm_std::Response.
9#[proc_macro]
10pub fn with_abstract_event(input: TokenStream) -> TokenStream {
11    let input = input.to_string();
12    let mut input = input.split(DELIMITER);
13    let base_response = input.next().unwrap().trim();
14    let contract_name = input.next().unwrap().trim();
15    let action = input.next().unwrap().trim();
16    // Collect the remaining
17    let attrs = input.collect::<Vec<&str>>().join(DELIMITER);
18
19    let attribute_addition = if attrs.is_empty() {
20        "".to_string()
21    } else if attrs.starts_with('[') && attrs.ends_with(']') {
22        format!(".add_attributes(vec!{attrs})")
23    } else {
24        format!(".add_attributes({attrs})")
25    };
26    let output = format!(
27        "{base_response}
28        .add_event(
29            cosmwasm_std::Event::new(\"abstract\")
30                .add_attribute(\"contract\", {contract_name})
31                .add_attribute(\"action\", {action})
32                {attribute_addition}
33        )"
34    );
35
36    output.parse().unwrap()
37}
38
39#[proc_macro_attribute]
40pub fn abstract_response(attrs: TokenStream, input: TokenStream) -> TokenStream {
41    let mut item = parse_macro_input!(input as syn::Item);
42    let attributes = parse_macro_input!(attrs as AttributeArgs);
43
44    let Item::Struct(resp_struct) = &mut item else {
45        panic!("Only works on structs");
46    };
47    let Fields::Unit = &mut resp_struct.fields else {
48        panic!("Struct must be unit-struct");
49    };
50    let visibility = resp_struct.vis.clone();
51    let resp_name = resp_struct.ident.clone();
52
53    let contract_name = attributes[0].clone();
54
55    let struct_def = quote!(
56        #visibility struct #resp_name;
57        impl #resp_name {
58            #visibility fn new<T: Into<String>, A: Into<cosmwasm_std::Attribute>>(
59                action: T,
60                attrs: impl IntoIterator<Item = A>,
61            ) -> cosmwasm_std::Response {
62                cosmwasm_std::Response::new().add_event(
63                    cosmwasm_std::Event::new("abstract")
64                        .add_attributes(vec![("contract", #contract_name)])
65                        .add_attributes(vec![("action", action)])
66                        .add_attributes(attrs),
67                )
68            }
69            #visibility fn action<T: Into<String>>(action: T) -> cosmwasm_std::Response {
70                #resp_name::new(action, Vec::<cosmwasm_std::Attribute>::new())
71            }
72        }
73    );
74
75    struct_def.into()
76}