sylvia_derive/interface/communication/
querier.rs1use convert_case::Case;
2use proc_macro2::TokenStream;
3use quote::{quote, ToTokens};
4use syn::Ident;
5
6use crate::crate_module;
7use crate::parser::attributes::msg::MsgType;
8use crate::parser::check_generics::GetPath;
9use crate::types::associated_types::{AssociatedTypes, ItemType};
10use crate::types::msg_field::MsgField;
11use crate::types::msg_variant::{MsgVariant, MsgVariants};
12use crate::utils::SvCasing;
13
14pub struct Querier<'a, Generic> {
19 variants: &'a MsgVariants<'a, Generic>,
20 associated_types: &'a AssociatedTypes<'a>,
21 interface_name: &'a Ident,
22}
23
24impl<'a, Generic> Querier<'a, Generic>
25where
26 Generic: GetPath + PartialEq + ToTokens,
27{
28 pub fn new(
29 variants: &'a MsgVariants<'a, Generic>,
30 associated_types: &'a AssociatedTypes,
31 interface_name: &'a Ident,
32 ) -> Self {
33 Self {
34 variants,
35 associated_types,
36 interface_name,
37 }
38 }
39
40 pub fn emit_querier_trait(&self) -> TokenStream {
41 let sylvia = crate_module();
42 let Self {
43 variants,
44 associated_types,
45 interface_name,
46 } = self;
47
48 let generics: Vec<_> = associated_types
49 .without_error()
50 .map(ItemType::as_name)
51 .collect();
52 let all_generics: Vec<_> = associated_types.as_names().collect();
53 let accessor = MsgType::Query.as_accessor_name();
54 let api_path = quote! {
55 < dyn #interface_name < Error = (), #(#generics = Self:: #generics,)* > as InterfaceMessagesApi > :: #accessor
56 };
57
58 let methods_trait_impl = variants
59 .variants()
60 .map(|variant| variant.emit_querier_impl(&api_path))
61 .collect::<Vec<_>>();
62
63 let querier_methods_declaration = variants
64 .variants()
65 .map(|variant| variant.emit_querier_method_declaration());
66
67 let types_declaration = associated_types.without_error().collect::<Vec<_>>();
68 let where_clause = associated_types.as_where_clause();
69
70 quote! {
71 pub trait Querier {
72 #(#types_declaration)*
73 #(#querier_methods_declaration)*
74 }
75
76 impl <'a, C: #sylvia ::cw_std::CustomQuery, #(#all_generics,)*> Querier for #sylvia ::types::BoundQuerier<'a, C, dyn #interface_name <#( #all_generics = #all_generics,)*> > #where_clause {
77 #(type #generics = #generics;)*
78 #(#methods_trait_impl)*
79 }
80
81 impl <'a, C: #sylvia ::cw_std::CustomQuery, Contract: #interface_name> Querier for #sylvia ::types::BoundQuerier<'a, C, Contract> {
82 #(type #generics = <Contract as #interface_name > :: #generics;)*
83 #(#methods_trait_impl)*
84 }
85 }
86 }
87}
88
89trait EmitQuerierMethod {
90 fn emit_querier_impl(&self, api_path: &TokenStream) -> TokenStream;
91 fn emit_querier_method_declaration(&self) -> TokenStream;
92}
93
94impl EmitQuerierMethod for MsgVariant<'_> {
95 fn emit_querier_impl(&self, api_path: &TokenStream) -> TokenStream {
96 let sylvia = crate_module();
97 let name = self.name();
98 let fields = self.fields();
99 let return_type = self.return_type();
100
101 let parameters = fields.iter().map(MsgField::emit_method_field_folded);
102 let fields_names = fields.iter().map(MsgField::name);
103 let variant_name = name.to_case(Case::Snake);
104
105 quote! {
106 fn #variant_name(&self, #(#parameters),*) -> Result< #return_type, #sylvia:: cw_std::StdError> {
107 let query = #api_path :: #variant_name (#(#fields_names),*);
108 self.querier().query_wasm_smart(self.contract(), &query)
109 }
110 }
111 }
112
113 fn emit_querier_method_declaration(&self) -> TokenStream {
114 let sylvia = crate_module();
115 let name = self.name();
116 let return_type = self.return_type();
117
118 let parameters = self
119 .fields()
120 .iter()
121 .map(|field| field.emit_method_field_folded());
122 let variant_name = name.to_case(Case::Snake);
123
124 quote! {
125 fn #variant_name(&self, #(#parameters),*) -> Result< #return_type, #sylvia:: cw_std::StdError>;
126 }
127 }
128}