sylvia_derive/interface/communication/
executor.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 Executor<'a, Generic> {
15 variants: &'a MsgVariants<'a, Generic>,
16 associated_types: &'a AssociatedTypes<'a>,
17 interface_name: &'a Ident,
18}
19
20impl<'a, Generic> Executor<'a, Generic>
21where
22 Generic: GetPath + PartialEq + ToTokens,
23{
24 pub fn new(
25 variants: &'a MsgVariants<'a, Generic>,
26 associated_types: &'a AssociatedTypes,
27 interface_name: &'a Ident,
28 ) -> Self {
29 Self {
30 variants,
31 associated_types,
32 interface_name,
33 }
34 }
35
36 pub fn emit_executor_trait(&self) -> TokenStream {
37 let sylvia = crate_module();
38 let Self {
39 variants,
40 associated_types,
41 interface_name,
42 } = self;
43
44 let generics: Vec<_> = associated_types
45 .without_error()
46 .map(ItemType::as_name)
47 .collect();
48 let all_generics: Vec<_> = associated_types.as_names().collect();
49
50 let accessor = MsgType::Exec.as_accessor_name();
51 let executor_api_path = quote! {
52 < dyn #interface_name < Error = (), #(#generics = Self:: #generics,)* > as InterfaceMessagesApi >:: #accessor
53 };
54
55 let methods_trait_impl = variants
56 .variants()
57 .map(|variant| variant.emit_executor_impl(&executor_api_path))
58 .collect::<Vec<_>>();
59
60 let executor_methods_declaration = variants
61 .variants()
62 .map(|variant| variant.emit_executor_method_declaration());
63
64 let types_declaration = associated_types.without_error().collect::<Vec<_>>();
65 let where_clause = associated_types.as_where_clause();
66
67 quote! {
68 pub trait Executor {
69 #(#types_declaration)*
70 #(#executor_methods_declaration)*
71 }
72
73 impl <#(#all_generics,)*> Executor
74 for #sylvia ::types::ExecutorBuilder<(#sylvia ::types::EmptyExecutorBuilderState, dyn #interface_name <#( #all_generics = #all_generics,)* > ) > #where_clause {
75 #(type #generics = #generics;)*
76 #(#methods_trait_impl)*
77 }
78
79 impl <Contract: #interface_name> Executor
80 for #sylvia ::types::ExecutorBuilder<( #sylvia ::types::EmptyExecutorBuilderState, Contract )> {
81 #(type #generics = <Contract as #interface_name > :: #generics;)*
82 #(#methods_trait_impl)*
83 }
84 }
85 }
86}
87
88trait EmitExecutorMethod {
89 fn emit_executor_impl(&self, api_path: &TokenStream) -> TokenStream;
90 fn emit_executor_method_declaration(&self) -> TokenStream;
91}
92
93impl EmitExecutorMethod for MsgVariant<'_> {
94 fn emit_executor_impl(&self, api_path: &TokenStream) -> TokenStream {
95 let name = self.name();
96 let fields = self.fields();
97 let sylvia = crate_module();
98
99 let parameters = fields.iter().map(MsgField::emit_method_field_folded);
100 let fields_names = fields.iter().map(MsgField::name);
101 let variant_name = name.to_case(Case::Snake);
102
103 quote! {
104 fn #variant_name(self, #(#parameters),*) -> Result<#sylvia ::types::ExecutorBuilder< #sylvia ::types::ReadyExecutorBuilderState >, #sylvia ::cw_std::StdError> {
105 Ok(#sylvia ::types::ExecutorBuilder::<#sylvia ::types::ReadyExecutorBuilderState>::new(
106 self.contract().to_owned(),
107 self.funds().to_owned(),
108 #sylvia ::cw_std::to_json_binary( & #api_path :: #variant_name (#(#fields_names),*) )?,
109 ))
110 }
111 }
112 }
113
114 fn emit_executor_method_declaration(&self) -> TokenStream {
115 let name = self.name();
116 let sylvia = crate_module();
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< #sylvia ::types::ExecutorBuilder<#sylvia ::types::ReadyExecutorBuilderState>, #sylvia ::cw_std::StdError>;
126 }
127 }
128}