sylvia_derive/
contract.rs1use communication::api::Api;
2use communication::enum_msg::EnumMessage;
3use communication::executor::Executor;
4use communication::instantiate_builder::InstantiateBuilder;
5use communication::querier::Querier;
6use communication::reply::Reply;
7use communication::struct_msg::StructMessage;
8use communication::wrapper_msg::GlueMessage;
9use mt::MtHelpers;
10use proc_macro2::TokenStream;
11use quote::quote;
12use syn::{GenericParam, ItemImpl};
13
14use crate::parser::attributes::features::SylviaFeatures;
15use crate::parser::attributes::msg::MsgType;
16use crate::parser::variant_descs::AsVariantDescs;
17use crate::parser::{
18 assert_new_method_defined, ContractErrorAttr, Custom, OverrideEntryPoint,
19 ParsedSylviaAttributes,
20};
21use crate::types::interfaces::Interfaces;
22use crate::types::msg_variant::MsgVariants;
23
24mod communication;
25mod mt;
26
27pub struct ContractInput<'a> {
44 item: &'a ItemImpl,
45 generics: Vec<&'a GenericParam>,
46 error: ContractErrorAttr,
47 custom: Custom,
48 override_entry_points: Vec<OverrideEntryPoint>,
49 interfaces: Interfaces,
50 sv_features: SylviaFeatures,
51}
52
53impl<'a> ContractInput<'a> {
54 pub fn new(item: &'a ItemImpl) -> Self {
55 assert_new_method_defined(item);
56
57 let generics = item.generics.params.iter().collect();
58 let parsed_attrs = ParsedSylviaAttributes::new(item.attrs.iter());
59 let error = parsed_attrs.error_attrs.unwrap_or_default();
60 let custom = parsed_attrs.custom_attr.unwrap_or_default();
61 let sv_features = parsed_attrs.sv_features;
62 let override_entry_points = parsed_attrs.override_entry_point_attrs;
63 let interfaces = Interfaces::new(item);
64
65 Self {
66 item,
67 generics,
68 error,
69 custom,
70 override_entry_points,
71 interfaces,
72 sv_features,
73 }
74 }
75
76 pub fn process(&self) -> TokenStream {
78 let Self {
79 item,
80 generics,
81 custom,
82 ..
83 } = self;
84 let multitest_helpers = self.emit_multitest_helpers();
85 let messages = self.emit_messages();
86 let contract_api = Api::new(item, generics, custom).emit();
87 let querier = self.emit_querier();
88 let executor = self.emit_executor();
89 let reply = self.emit_reply();
90 let instantiate_builder = self.emit_instantiate_builder_trait();
91
92 quote! {
93 pub mod sv {
94 use super::*;
95
96 #messages
97
98 #multitest_helpers
99
100 #querier
101
102 #executor
103
104 #reply
105
106 #contract_api
107
108 #instantiate_builder
109 }
110 }
111 }
112
113 fn emit_messages(&self) -> TokenStream {
114 let instantiate = self.emit_struct_msg(MsgType::Instantiate);
115 let migrate = self.emit_struct_msg(MsgType::Migrate);
116 let exec_impl = self.emit_enum_msg(MsgType::Exec);
117 let query_impl = self.emit_enum_msg(MsgType::Query);
118 let sudo_impl = self.emit_enum_msg(MsgType::Sudo);
119 let exec = self.emit_glue_msg(MsgType::Exec);
120 let query = self.emit_glue_msg(MsgType::Query);
121 let sudo = self.emit_glue_msg(MsgType::Sudo);
122
123 quote! {
124 #instantiate
125
126 #exec_impl
127
128 #query_impl
129
130 #sudo_impl
131
132 #migrate
133
134 #exec
135
136 #query
137
138 #sudo
139 }
140 }
141
142 fn emit_struct_msg(&self, msg_ty: MsgType) -> TokenStream {
143 StructMessage::new(self.item, msg_ty, &self.generics, &self.error, &self.custom)
144 .map_or(quote! {}, |msg| msg.emit())
145 }
146
147 fn emit_enum_msg(&self, msg_ty: MsgType) -> TokenStream {
148 EnumMessage::new(self.item, msg_ty, &self.generics, &self.error, &self.custom).emit()
149 }
150
151 fn emit_glue_msg(&self, msg_ty: MsgType) -> TokenStream {
152 GlueMessage::new(
153 self.item,
154 msg_ty,
155 &self.error,
156 &self.custom,
157 &self.interfaces,
158 )
159 .emit()
160 }
161
162 fn emit_multitest_helpers(&self) -> TokenStream {
163 if !cfg!(feature = "mt") {
164 return quote! {};
165 }
166
167 let Self {
168 item,
169 custom,
170 override_entry_points,
171 ..
172 } = self;
173
174 let generic_params = &self.generics;
175 MtHelpers::new(item, generic_params, custom, override_entry_points.clone()).emit()
176 }
177
178 fn emit_executor(&self) -> TokenStream {
179 let item = self.item;
180 let variants = MsgVariants::new(item.as_variants(), MsgType::Exec, &[], &None);
181
182 Executor::new(item.generics.clone(), *item.self_ty.clone(), variants).emit()
183 }
184 fn emit_querier(&self) -> TokenStream {
185 let item = self.item;
186 let variants = MsgVariants::new(item.as_variants(), MsgType::Query, &[], &None);
187
188 Querier::new(item.generics.clone(), *item.self_ty.clone(), variants).emit()
189 }
190
191 fn emit_reply(&self) -> TokenStream {
192 if !self.sv_features.replies {
193 return quote! {};
194 }
195
196 let variants = MsgVariants::new(self.item.as_variants(), MsgType::Reply, &[], &None);
197
198 Reply::new(self.item, &self.generics, &variants).emit()
199 }
200
201 fn emit_instantiate_builder_trait(&self) -> TokenStream {
202 let variants = MsgVariants::new(
203 self.item.as_variants(),
204 MsgType::Instantiate,
205 &self.generics,
206 &self.item.generics.where_clause,
207 );
208 let where_clause = variants.where_clause();
209
210 match variants.get_only_variant() {
211 Some(variant) => InstantiateBuilder::new(
212 *self.item.self_ty.clone(),
213 variants.used_generics(),
214 &where_clause,
215 variant,
216 )
217 .emit(),
218 None => quote! {},
219 }
220 }
221}