sylvia_derive/contract/communication/
executor.rs1use convert_case::Case;
2use proc_macro2::TokenStream;
3use quote::quote;
4use syn::{GenericParam, Generics, Type};
5
6use crate::crate_module;
7use crate::parser::attributes::msg::MsgType;
8use crate::types::associated_types::EmitAssociated;
9use crate::types::msg_field::MsgField;
10use crate::types::msg_variant::{MsgVariant, MsgVariants};
11use crate::utils::SvCasing;
12
13pub struct Executor<'a> {
18 generics: Generics,
19 self_ty: Type,
20 variants: MsgVariants<'a, GenericParam>,
21}
22
23impl<'a> Executor<'a> {
24 pub fn new(generics: Generics, self_ty: Type, variants: MsgVariants<'a, GenericParam>) -> Self {
25 Self {
26 generics,
27 self_ty,
28 variants,
29 }
30 }
31
32 pub fn emit(&self) -> TokenStream {
33 let sylvia = crate_module();
34 let Self {
35 generics,
36 self_ty,
37 variants,
38 ..
39 } = self;
40
41 let where_clause = &generics.where_clause;
42 let generics: Vec<_> = generics.params.iter().collect();
43 let contract = &self_ty;
44
45 let accessor = MsgType::Exec.as_accessor_name();
46 let executor_api_path = quote! { < #contract as #sylvia ::types::ContractApi>:: #accessor };
47
48 let executor_methods_impl = variants
49 .variants()
50 .map(|variant| variant.emit_executor_impl(&executor_api_path));
51
52 let executor_methods_declaration = variants
53 .variants()
54 .map(|variant| variant.emit_executor_method_declaration());
55
56 let types_declaration = where_clause
57 .as_ref()
58 .map(EmitAssociated::emit_declaration)
59 .unwrap_or(vec![]);
60
61 let types_implementation = where_clause
62 .as_ref()
63 .map(EmitAssociated::emit_implementation)
64 .unwrap_or(vec![]);
65
66 quote! {
67 pub trait Executor<#(#generics,)*> #where_clause {
68 #(#types_declaration)*
69 #(#executor_methods_declaration)*
70 }
71
72 impl <#(#generics,)*> Executor<#(#generics,)*>
73 for #sylvia ::types::ExecutorBuilder<( #sylvia ::types::EmptyExecutorBuilderState, #contract )> #where_clause {
74 #(#types_implementation)*
75 #(#executor_methods_impl)*
76 }
77 }
78 }
79}
80
81trait EmitExecutorMethod {
82 fn emit_executor_impl(&self, api_path: &TokenStream) -> TokenStream;
83 fn emit_executor_method_declaration(&self) -> TokenStream;
84}
85
86impl EmitExecutorMethod for MsgVariant<'_> {
87 fn emit_executor_impl(&self, api_path: &TokenStream) -> TokenStream {
88 let name = self.name();
89 let fields = self.fields();
90 let sylvia = crate_module();
91
92 let parameters = fields.iter().map(MsgField::emit_method_field_folded);
93 let fields_names = fields.iter().map(MsgField::name);
94 let variant_name = name.to_case(Case::Snake);
95
96 quote! {
97 fn #variant_name(self, #(#parameters),*) -> Result<#sylvia ::types::ExecutorBuilder< #sylvia ::types::ReadyExecutorBuilderState >, #sylvia ::cw_std::StdError> {
98 Ok(#sylvia ::types::ExecutorBuilder::<#sylvia ::types::ReadyExecutorBuilderState>::new(
99 self.contract().to_owned(),
100 self.funds().to_owned(),
101 #sylvia ::cw_std::to_json_binary( & #api_path :: #variant_name (#(#fields_names),*) )?,
102 ))
103 }
104 }
105 }
106
107 fn emit_executor_method_declaration(&self) -> TokenStream {
108 let name = self.name();
109 let sylvia = crate_module();
110
111 let parameters = self
112 .fields()
113 .iter()
114 .map(|field| field.emit_method_field_folded());
115 let variant_name = name.to_case(Case::Snake);
116
117 quote! {
118 fn #variant_name(self, #(#parameters),*) -> Result< #sylvia ::types::ExecutorBuilder<#sylvia ::types::ReadyExecutorBuilderState>, #sylvia ::cw_std::StdError>;
119 }
120 }
121}