ink_codegen/generator/
item_impls.rs1use core::iter;
16
17use crate::GenerateCode;
18use derive_more::From;
19use heck::ToLowerCamelCase as _;
20use ir::{
21 Callable as _,
22 HexLiteral,
23};
24use proc_macro2::TokenStream as TokenStream2;
25use quote::{
26 format_ident,
27 quote,
28 quote_spanned,
29 ToTokens,
30};
31use syn::spanned::Spanned as _;
32
33#[derive(From)]
35pub struct ItemImpls<'a> {
36 contract: &'a ir::Contract,
37}
38impl_as_ref_for_generator!(ItemImpls);
39
40impl GenerateCode for ItemImpls<'_> {
41 fn generate_code(&self) -> TokenStream2 {
42 let item_impls = self
43 .contract
44 .module()
45 .impls()
46 .map(|item_impl| self.generate_item_impl(item_impl));
47 let inout_guards = self.generate_input_output_guards();
48 let trait_message_property_guards = self.generate_trait_message_property_guards();
49 quote! {
50 const _: () = {
51 use ::ink::codegen::{Env as _, StaticEnv as _};
53
54 #( #item_impls )*
55 #inout_guards
56 #trait_message_property_guards
57 };
58 }
59 }
60}
61
62impl ItemImpls<'_> {
63 fn generate_trait_message_property_guards(&self) -> TokenStream2 {
72 let storage_span = self.contract.module().storage().span();
73 let storage_ident = self.contract.module().storage().ident();
74 let trait_message_guards = self
75 .contract
76 .module()
77 .impls()
78 .filter_map(|item_impl| item_impl.trait_path().map(|trait_path| {
79 iter::repeat(trait_path).zip(item_impl.iter_messages())
80 }))
81 .flatten()
82 .map(|(trait_path, message)| {
83 let message_span = message.span();
84 let message_local_id = message.local_id().hex_padded_suffixed();
85 let message_guard_payable = message.is_payable().then(|| {
86 quote_spanned!(message_span=>
87 const _: ::ink::codegen::TraitMessagePayable<{
88 <<::ink::reflect::TraitDefinitionRegistry<<#storage_ident as ::ink::env::ContractEnv>::Env>
89 as #trait_path>::__ink_TraitInfo
90 as ::ink::reflect::TraitMessageInfo<#message_local_id>>::PAYABLE
91 }> = ::ink::codegen::TraitMessagePayable::<true>;
92 )
93 });
94 let message_guard_selector = message.user_provided_selector().map(|selector| {
95 let given_selector = selector.into_be_u32().hex_padded_suffixed();
96 quote_spanned!(message_span=>
97 const _: ::ink::codegen::TraitMessageSelector<{
98 ::core::primitive::u32::from_be_bytes(
99 <<::ink::reflect::TraitDefinitionRegistry<<#storage_ident as ::ink::env::ContractEnv>::Env>
100 as #trait_path>::__ink_TraitInfo
101 as ::ink::reflect::TraitMessageInfo<#message_local_id>>::SELECTOR
102 )
103 }> = ::ink::codegen::TraitMessageSelector::<#given_selector>;
104 )
105 });
106 quote_spanned!(message_span=>
107 #message_guard_payable
108 #message_guard_selector
109 )
110 });
111 quote_spanned!(storage_span=>
112 #( #trait_message_guards )*
113 )
114 }
115
116 fn generate_input_output_guards(&self) -> TokenStream2 {
118 let storage_span = self.contract.module().storage().span();
119 let constructor_input_guards = self
120 .contract
121 .module()
122 .impls()
123 .flat_map(|item_impl| item_impl.iter_constructors())
124 .map(|constructor| {
125 let constructor_span = constructor.span();
126 let constructor_inputs = constructor.inputs().map(|input| {
127 let span = input.span();
128 let input_type = &*input.ty;
129 quote_spanned!(span=>
130 ::ink::codegen::utils::consume_type::<
131 ::ink::codegen::DispatchInput<#input_type>
132 >();
133 )
134 });
135 quote_spanned!(constructor_span=>
136 #( #constructor_inputs )*
137 )
138 });
139 let message_inout_guards = self
140 .contract
141 .module()
142 .impls()
143 .flat_map(|item_impl| item_impl.iter_messages())
144 .map(|message| {
145 let message_span = message.span();
146 let message_inputs = message.inputs().map(|input| {
147 let span = input.span();
148 let input_type = &*input.ty;
149 quote_spanned!(span=>
150 ::ink::codegen::utils::consume_type::<
151 ::ink::codegen::DispatchInput<#input_type>
152 >();
153 )
154 });
155 let message_output = message.output().map(|output_type| {
156 let span = output_type.span();
157 quote_spanned!(span=>
158 ::ink::codegen::utils::consume_type::<
159 ::ink::codegen::DispatchOutput<#output_type>
160 >();
161 )
162 });
163 quote_spanned!(message_span=>
164 #( #message_inputs )*
165 #message_output
166 )
167 });
168 quote_spanned!(storage_span=>
169 const _: () = {
170 #( #constructor_input_guards )*
171 #( #message_inout_guards )*
172 };
173 )
174 }
175
176 fn generate_trait_message(message: &ir::Message) -> TokenStream2 {
178 let span = message.span();
179 let attrs = message.attrs();
180 let vis = message.visibility();
181 let receiver = message.receiver();
182 let ident = message.ident();
183 let output_ident =
184 format_ident!("{}Output", ident.to_string().to_lower_camel_case());
185 let inputs = message.inputs();
186 let output = message
187 .output()
188 .cloned()
189 .unwrap_or_else(|| syn::parse_quote! { () });
190 let statements = message.statements();
191 let cfg_attrs = message.get_cfg_attrs(span);
192 quote_spanned!(span =>
193 #( #cfg_attrs )*
194 type #output_ident = #output;
195
196 #( #attrs )*
197 #vis fn #ident(#receiver #( , #inputs )* ) -> Self::#output_ident {
198 #( #statements )*
199 }
200 )
201 }
202
203 fn generate_trait_item_impl(item_impl: &ir::ItemImpl) -> TokenStream2 {
204 assert!(item_impl.trait_path().is_some());
205 let span = item_impl.span();
206 let attrs = item_impl.attrs();
207 let messages = item_impl
208 .iter_messages()
209 .map(|cws| Self::generate_trait_message(cws.callable()));
210 let trait_path = item_impl
211 .trait_path()
212 .expect("encountered missing trait path for trait impl block");
213 let self_type = item_impl.self_type();
214 quote_spanned!(span =>
215 #( #attrs )*
216 impl #trait_path for #self_type {
217 type __ink_TraitInfo = <::ink::reflect::TraitDefinitionRegistry<Environment>
218 as #trait_path>::__ink_TraitInfo;
219
220 #( #messages )*
221 }
222 )
223 }
224
225 fn generate_inherent_constructor(constructor: &ir::Constructor) -> TokenStream2 {
239 let span = constructor.span();
240 let attrs = constructor.attrs();
241 let vis = constructor.visibility();
242 let ident = constructor.ident();
243 let inputs = constructor.inputs();
244 let statements = constructor.statements();
245 let output = constructor.output();
246 quote_spanned!(span =>
247 #( #attrs )*
248 #[cfg(not(target_os = "dragonfly"))]
249 #vis fn #ident( #( #inputs ),* ) -> #output {
250 #( #statements )*
251 }
252 )
253 }
254
255 fn generate_inherent_message(message: &ir::Message) -> TokenStream2 {
258 let span = message.span();
259 let attrs = message.attrs();
260 let vis = message.visibility();
261 let receiver = message.receiver();
262 let ident = message.ident();
263 let inputs = message.inputs();
264 let output_arrow = message.output().map(|_| quote! { -> });
265 let output = message.output();
266 let statements = message.statements();
267 quote_spanned!(span =>
268 #( #attrs )*
269 #vis fn #ident(#receiver #( , #inputs )* ) #output_arrow #output {
270 #( #statements )*
271 }
272 )
273 }
274
275 fn generate_inherent_item_impl(item_impl: &ir::ItemImpl) -> TokenStream2 {
276 assert!(item_impl.trait_path().is_none());
277 let span = item_impl.span();
278 let attrs = item_impl.attrs();
279 let messages = item_impl
280 .iter_messages()
281 .map(|cws| Self::generate_inherent_message(cws.callable()));
282 let constructors = item_impl
283 .iter_constructors()
284 .map(|cws| Self::generate_inherent_constructor(cws.callable()));
285 let other_items = item_impl
286 .items()
287 .iter()
288 .filter_map(ir::ImplItem::filter_map_other_item)
289 .map(ToTokens::to_token_stream);
290 let self_type = item_impl.self_type();
291 quote_spanned!(span =>
292 #( #attrs )*
293 impl #self_type {
294 #( #constructors )*
295 #( #messages )*
296 #( #other_items )*
297 }
298 )
299 }
300
301 fn generate_item_impl_self_ty_guard(&self, item_impl: &ir::ItemImpl) -> TokenStream2 {
304 let self_ty = item_impl.self_type();
305 let span = self_ty.span();
306 let storage_ident = self.contract.module().storage().ident();
307 quote_spanned!(span =>
308 const _: ::ink::codegen::utils::IsSameType<#storage_ident> =
309 ::ink::codegen::utils::IsSameType::<#self_ty>::new();
310 )
311 }
312
313 fn generate_item_impl(&self, item_impl: &ir::ItemImpl) -> TokenStream2 {
315 let self_ty_guard = self.generate_item_impl_self_ty_guard(item_impl);
316 let impl_block = match item_impl.trait_path() {
317 Some(_) => Self::generate_trait_item_impl(item_impl),
318 None => Self::generate_inherent_item_impl(item_impl),
319 };
320 quote! {
321 #self_ty_guard
322 #impl_block
323 }
324 }
325}