1use core::iter;
16
17use derive_more::From;
18use ir::{
19 Callable,
20 CallableWithSelector,
21 Constructor,
22 HexLiteral as _,
23 Message,
24};
25use proc_macro2::{
26 Ident,
27 TokenStream as TokenStream2,
28};
29use quote::{
30 format_ident,
31 quote,
32 quote_spanned,
33};
34use syn::{
35 spanned::Spanned as _,
36 LitInt,
37};
38
39#[cfg(any(ink_abi = "sol", ink_abi = "all"))]
40use crate::generator::sol;
41use crate::{
42 generator,
43 GenerateCode,
44};
45
46pub struct MessageDispatchable<'a> {
49 message: CallableWithSelector<'a, Message>,
50 id: TokenStream2,
51}
52
53pub struct ConstructorDispatchable<'a> {
56 constructor: CallableWithSelector<'a, Constructor>,
57 id: LitInt,
58}
59
60#[derive(From)]
74pub struct Dispatch<'a> {
75 contract: &'a ir::Contract,
76}
77impl_as_ref_for_generator!(Dispatch);
78
79impl GenerateCode for Dispatch<'_> {
80 fn generate_code(&self) -> TokenStream2 {
81 let messages = self.compose_messages_with_ids();
82 let constructors = self.compose_constructors_with_ids();
83
84 let contract_dispatchable_constructor_infos =
85 self.generate_dispatchable_constructor_infos();
86 let contract_dispatchable_messages_infos =
87 self.generate_dispatchable_message_infos();
88 let constructor_decoder_type =
89 self.generate_constructor_decoder_type(&constructors);
90 let message_decoder_type = self.generate_message_decoder_type(&messages);
91 let entry_points = self.generate_entry_points(&constructors, &messages);
92
93 #[cfg(not(any(ink_abi = "sol", ink_abi = "all")))]
94 let solidity_call_info = quote!();
95
96 #[cfg(any(ink_abi = "sol", ink_abi = "all"))]
97 let solidity_call_info = self.generate_solidity_call_info();
98
99 quote! {
100 #contract_dispatchable_constructor_infos
101 #contract_dispatchable_messages_infos
102 #constructor_decoder_type
103 #message_decoder_type
104
105 #solidity_call_info
106
107 #[cfg(not(any(test, feature = "std", feature = "ink-as-dependency")))]
108 mod __do_not_access__ {
109 use super::*;
110 #entry_points
111 }
112 }
113 }
114}
115
116impl Dispatch<'_> {
117 fn query_wildcard_message(&self) -> Option<usize> {
119 self.contract
120 .module()
121 .impls()
122 .flat_map(|item_impl| item_impl.iter_messages())
123 .position(|item| item.has_wildcard_selector())
124 }
125
126 fn query_wildcard_constructor(&self) -> Option<usize> {
129 self.contract
130 .module()
131 .impls()
132 .flat_map(|item_impl| item_impl.iter_constructors())
133 .position(|item| item.has_wildcard_selector())
134 }
135
136 fn compose_messages_with_ids(&self) -> Vec<MessageDispatchable> {
140 #[cfg(not(ink_abi = "sol"))]
141 let storage_ident = self.contract.module().storage().ident();
142 self.contract
143 .module()
144 .impls()
145 .flat_map(|item_impl| {
146 iter::repeat(item_impl.trait_path()).zip(item_impl.iter_messages())
147 })
148 .flat_map(|(trait_path, message)| {
149 let mut message_dispatchables = Vec::new();
150
151 #[cfg(not(ink_abi = "sol"))]
152 {
153 let span = message.span();
154 let id = if let Some(trait_path) = trait_path {
155 let local_id = message.local_id().hex_padded_suffixed();
156 quote_spanned!(span=>
157 {
158 ::core::primitive::u32::from_be_bytes(
159 <<::ink::reflect::TraitDefinitionRegistry<<#storage_ident as ::ink::env::ContractEnv>::Env>
160 as #trait_path>::__ink_TraitInfo
161 as ::ink::reflect::TraitMessageInfo<#local_id>>::SELECTOR
162 )
163 }
164 )
165 } else {
166 let id = message
167 .composed_selector()
168 .into_be_u32()
169 .hex_padded_suffixed();
170 quote_spanned!(span=>
171 #id
172 )
173 };
174 message_dispatchables.push(MessageDispatchable { message, id });
175 }
176
177 #[cfg(any(ink_abi = "sol", ink_abi = "all"))]
178 {
179 let id = sol::utils::selector_id(&message);
180 message_dispatchables.push(MessageDispatchable { message, id });
181 let _ = trait_path; }
183
184 message_dispatchables
185 })
186 .collect::<Vec<_>>()
187 }
188
189 fn compose_constructors_with_ids(&self) -> Vec<ConstructorDispatchable> {
193 self.contract
194 .module()
195 .impls()
196 .flat_map(|item_impl| item_impl.iter_constructors())
197 .map(|constructor| {
198 let id = constructor
199 .composed_selector()
200 .into_be_u32()
201 .hex_padded_suffixed();
202 ConstructorDispatchable { constructor, id }
203 })
204 .collect::<Vec<_>>()
205 }
206
207 fn generate_dispatchable_constructor_infos(&self) -> TokenStream2 {
212 let span = self.contract.module().storage().span();
213 let storage_ident = self.contract.module().storage().ident();
214 let constructor_infos = self
215 .contract
216 .module()
217 .impls()
218 .flat_map(|item_impl| item_impl.iter_constructors())
219 .map(|constructor| {
220 let constructor_span = constructor.span();
221 let constructor_ident = constructor.ident();
222 let payable = constructor.is_payable();
223 let selector_id = constructor.composed_selector().into_be_u32().hex_padded_suffixed();
224 let selector_bytes = constructor.composed_selector().hex_lits();
225 let cfg_attrs = constructor.get_cfg_attrs(constructor_span);
226 let output_type = constructor.output().map(quote::ToTokens::to_token_stream)
227 .unwrap_or_else(|| quote! { () });
228 let input_bindings = generator::input_bindings(constructor.inputs());
229 let input_tuple_type = generator::input_types_tuple(constructor.inputs());
230 let input_tuple_bindings = generator::input_bindings_tuple(constructor.inputs());
231 let constructor_return_type = quote_spanned!(constructor_span=>
232 <::ink::reflect::ConstructorOutputValue<#output_type>
233 as ::ink::reflect::ConstructorOutput<#storage_ident>>
234 );
235 quote_spanned!(constructor_span =>
236 #( #cfg_attrs )*
237 impl ::ink::reflect::DispatchableConstructorInfo<#selector_id> for #storage_ident {
238 type Input = #input_tuple_type;
239 type Output = #output_type;
240 type Storage = #storage_ident;
241 type Error = #constructor_return_type::Error;
242 const IS_RESULT: ::core::primitive::bool = #constructor_return_type::IS_RESULT;
243
244 const CALLABLE: fn(Self::Input) -> Self::Output = |#input_tuple_bindings| {
245 #storage_ident::#constructor_ident(#( #input_bindings ),* )
246 };
247 const PAYABLE: ::core::primitive::bool = #payable;
248 const SELECTOR: [::core::primitive::u8; 4usize] = [ #( #selector_bytes ),* ];
249 const LABEL: &'static ::core::primitive::str = ::core::stringify!(#constructor_ident);
250 }
251 )
252 });
253 quote_spanned!(span=>
254 #( #constructor_infos )*
255 )
256 }
257
258 #[allow(clippy::vec_init_then_push)] fn generate_dispatchable_message_infos(&self) -> TokenStream2 {
264 let span = self.contract.module().storage().span();
265
266 let inherent_message_infos = self
267 .contract
268 .module()
269 .impls()
270 .filter(|item_impl| item_impl.trait_path().is_none())
271 .flat_map(|item_impl| item_impl.iter_messages())
272 .flat_map(|message| {
273 let mut message_infos = Vec::new();
274
275 #[cfg(not(ink_abi = "sol"))]
276 message_infos.push(self.dispatchable_inherent_message_infos(&message));
277
278 #[cfg(any(ink_abi = "sol", ink_abi = "all"))]
279 message_infos.push(self.solidity_message_info(&message, None));
280
281 message_infos
282 });
283 let trait_message_infos = self
284 .contract
285 .module()
286 .impls()
287 .filter_map(|item_impl| {
288 item_impl
289 .trait_path()
290 .map(|trait_path| {
291 let trait_ident = item_impl.trait_ident().expect(
292 "must have an ink! trait identifier if it is an ink! trait implementation"
293 );
294 iter::repeat((trait_ident, trait_path)).zip(item_impl.iter_messages())
295 })
296 })
297 .flatten()
298 .flat_map(|((trait_ident, trait_path), message)| {
299 let mut message_infos = Vec::new();
300
301 #[cfg(not(ink_abi = "sol"))]
302 message_infos.push(self.dispatchable_trait_message_infos(&message, trait_ident, trait_path));
303
304 #[cfg(any(ink_abi = "sol", ink_abi = "all"))]
306 message_infos.push(self.solidity_message_info(&message, Some((trait_ident, trait_path))));
307
308 message_infos
309 });
310 quote_spanned!(span=>
311 #( #inherent_message_infos )*
312 #( #trait_message_infos )*
313 )
314 }
315
316 #[cfg(not(ink_abi = "sol"))]
321 fn dispatchable_inherent_message_infos(
322 &self,
323 message: &CallableWithSelector<Message>,
324 ) -> TokenStream2 {
325 let storage_ident = self.contract.module().storage().ident();
326
327 let message_span = message.span();
328 let message_ident = message.ident();
329 let payable = message.is_payable();
330 let mutates = message.receiver().is_ref_mut();
331
332 let cfg_attrs = message.get_cfg_attrs(message_span);
333 let output_tuple_type = message
334 .output()
335 .map(quote::ToTokens::to_token_stream)
336 .unwrap_or_else(|| quote! { () });
337 let input_bindings = generator::input_bindings(message.inputs());
338 let input_tuple_type = generator::input_types_tuple(message.inputs());
339 let input_tuple_bindings = generator::input_bindings_tuple(message.inputs());
340
341 let selector_id = message
342 .composed_selector()
343 .into_be_u32()
344 .hex_padded_suffixed();
345 let selector_bytes = message.composed_selector().hex_lits();
346
347 #[cfg(feature = "std")]
348 let return_type = quote! { () };
349 #[cfg(not(feature = "std"))]
350 let return_type = quote! { ! };
351
352 quote_spanned!(message_span=>
353 #( #cfg_attrs )*
354 impl ::ink::reflect::DispatchableMessageInfo<#selector_id> for #storage_ident {
355 type Input = #input_tuple_type;
356 type Output = #output_tuple_type;
357 type Storage = #storage_ident;
358
359 const CALLABLE: fn(&mut Self::Storage, Self::Input) -> Self::Output =
360 |storage, #input_tuple_bindings| {
361 #storage_ident::#message_ident( storage #( , #input_bindings )* )
362 };
363 const DECODE: fn(&mut &[::core::primitive::u8]) -> ::core::result::Result<Self::Input, ::ink::env::DispatchError> =
364 |input| {
365 <Self::Input as ::ink::scale::Decode>::decode(input)
366 .map_err(|_| ::ink::env::DispatchError::InvalidParameters)
367 };
368 const RETURN: fn(::ink::env::ReturnFlags, Self::Output) -> #return_type =
369 |flags, output| {
370 ::ink::env::return_value::<::ink::MessageResult::<Self::Output>>(
371 flags,
372 &::ink::MessageResult::Ok(output),
375 )
376 };
377 const SELECTOR: [::core::primitive::u8; 4usize] = [ #( #selector_bytes ),* ];
378 const PAYABLE: ::core::primitive::bool = #payable;
379 const MUTATES: ::core::primitive::bool = #mutates;
380 const LABEL: &'static ::core::primitive::str = ::core::stringify!(#message_ident);
381 const ENCODING: ::ink::reflect::Encoding = ::ink::reflect::Encoding::Scale;
382 }
383 )
384 }
385
386 #[cfg(not(ink_abi = "sol"))]
391 fn dispatchable_trait_message_infos(
392 &self,
393 message: &CallableWithSelector<Message>,
394 trait_ident: &Ident,
395 trait_path: &syn::Path,
396 ) -> TokenStream2 {
397 let storage_ident = self.contract.module().storage().ident();
398
399 let message_span = message.span();
400 let message_ident = message.ident();
401 let mutates = message.receiver().is_ref_mut();
402 let local_id = message.local_id().hex_padded_suffixed();
403 let payable = quote! {{
404 <<::ink::reflect::TraitDefinitionRegistry<<#storage_ident as ::ink::env::ContractEnv>::Env>
405 as #trait_path>::__ink_TraitInfo
406 as ::ink::reflect::TraitMessageInfo<#local_id>>::PAYABLE
407 }};
408 let selector = quote! {{
409 <<::ink::reflect::TraitDefinitionRegistry<<#storage_ident as ::ink::env::ContractEnv>::Env>
410 as #trait_path>::__ink_TraitInfo
411 as ::ink::reflect::TraitMessageInfo<#local_id>>::SELECTOR
412 }};
413 let selector_id = quote! {{
414 ::core::primitive::u32::from_be_bytes(#selector)
415 }};
416 let output_tuple_type = message
417 .output()
418 .map(quote::ToTokens::to_token_stream)
419 .unwrap_or_else(|| quote! { () });
420 let input_bindings = generator::input_bindings(message.inputs());
421 let input_tuple_type = generator::input_types_tuple(message.inputs());
422 let input_tuple_bindings = generator::input_bindings_tuple(message.inputs());
423 let label = format!("{trait_ident}::{message_ident}");
424 let cfg_attrs = message.get_cfg_attrs(message_span);
425
426 #[cfg(feature = "std")]
427 let return_type = quote! { () };
428 #[cfg(not(feature = "std"))]
429 let return_type = quote! { ! };
430
431 quote_spanned!(message_span=>
432 #( #cfg_attrs )*
433 impl ::ink::reflect::DispatchableMessageInfo<#selector_id> for #storage_ident {
434 type Input = #input_tuple_type;
435 type Output = #output_tuple_type;
436 type Storage = #storage_ident;
437
438 const CALLABLE: fn(&mut Self::Storage, Self::Input) -> Self::Output =
439 |storage, #input_tuple_bindings| {
440 <#storage_ident as #trait_path>::#message_ident( storage #( , #input_bindings )* )
441 };
442 const DECODE: fn(&mut &[::core::primitive::u8]) -> ::core::result::Result<Self::Input, ::ink::env::DispatchError> =
443 |input| {
444 <Self::Input as ::ink::scale::Decode>::decode(input)
445 .map_err(|_| ::ink::env::DispatchError::InvalidParameters)
446 };
447 const RETURN: fn(::ink::env::ReturnFlags, Self::Output) -> #return_type =
448 |flags, output| {
449 ::ink::env::return_value::<::ink::MessageResult::<Self::Output>>(
450 flags,
451 &::ink::MessageResult::Ok(output),
454 )
455 };
456 const SELECTOR: [::core::primitive::u8; 4usize] = #selector;
457 const PAYABLE: ::core::primitive::bool = #payable;
458 const MUTATES: ::core::primitive::bool = #mutates;
459 const LABEL: &'static ::core::primitive::str = #label;
460 const ENCODING: ::ink::reflect::Encoding = ::ink::reflect::Encoding::Scale;
461 }
462 )
463 }
464
465 #[cfg(any(ink_abi = "sol", ink_abi = "all"))]
468 fn solidity_message_info(
469 &self,
470 message: &CallableWithSelector<Message>,
471 trait_info: Option<(&Ident, &syn::Path)>,
472 ) -> TokenStream2 {
473 let storage_ident = self.contract.module().storage().ident();
474 let message_span = message.span();
475 let message_ident = message.ident();
476 let payable = message.is_payable();
477 let mutates = message.receiver().is_ref_mut();
478
479 let cfg_attrs = message.get_cfg_attrs(message_span);
480 let output_tuple_type = message
481 .output()
482 .map(quote::ToTokens::to_token_stream)
483 .unwrap_or_else(|| quote! { () });
484 let input_bindings = generator::input_bindings(message.inputs());
485 let input_tuple_type = generator::input_types_tuple(message.inputs());
486 let input_tuple_bindings = generator::input_bindings_tuple(message.inputs());
487
488 let selector_id = sol::utils::selector_id(message);
489 let selector_bytes = sol::utils::selector(message);
490
491 let (call_prefix, label) = match trait_info {
492 None => {
493 (
494 quote! {
495 #storage_ident
496 },
497 message_ident.to_string(),
498 )
499 }
500 Some((trait_ident, trait_path)) => {
501 (
502 quote! {
503 <#storage_ident as #trait_path>
504 },
505 format!("{trait_ident}::{message_ident}"),
506 )
507 }
508 };
509
510 #[cfg(feature = "std")]
511 let return_type = quote! { () };
512 #[cfg(not(feature = "std"))]
513 let return_type = quote! { ! };
514
515 quote_spanned!(message_span=>
516 #( #cfg_attrs )*
517 impl ::ink::reflect::DispatchableMessageInfo<#selector_id> for #storage_ident {
518 type Input = #input_tuple_type;
519 type Output = #output_tuple_type;
520 type Storage = #storage_ident;
521
522 const CALLABLE: fn(&mut Self::Storage, Self::Input) -> Self::Output =
523 |storage, #input_tuple_bindings| {
524 #call_prefix::#message_ident( storage #( , #input_bindings )* )
525 };
526 const DECODE: fn(&mut &[::core::primitive::u8]) -> ::core::result::Result<Self::Input, ::ink::env::DispatchError> =
527 |input| {
528 <Self::Input as ::ink::SolDecode>::decode(input)
529 .map_err(|_| ::ink::env::DispatchError::InvalidParameters)
530 };
531 const RETURN: fn(::ink::env::ReturnFlags, Self::Output) -> #return_type =
532 |flags, output| {
533 ::ink::env::return_value_solidity::<Self::Output>(
534 flags,
535 &output,
536 )
537 };
538 const SELECTOR: [::core::primitive::u8; 4usize] = #selector_bytes;
539 const PAYABLE: ::core::primitive::bool = #payable;
540 const MUTATES: ::core::primitive::bool = #mutates;
541 const LABEL: &'static ::core::primitive::str = #label;
542 const ENCODING: ::ink::reflect::Encoding = ::ink::reflect::Encoding::Solidity;
543 }
544 )
545 }
546
547 fn generate_entry_points(
552 &self,
553 constructors: &[ConstructorDispatchable],
554 messages: &[MessageDispatchable],
555 ) -> TokenStream2 {
556 let span = self.contract.module().storage().span();
557 let storage_ident = self.contract.module().storage().ident();
558 let any_constructor_accept_payment =
559 self.any_constructor_accepts_payment(constructors);
560 let any_message_accepts_payment = self.any_message_accepts_payment(messages);
561
562 let fn_call: syn::ItemFn = syn::parse_quote! {
563 #[cfg(target_arch = "riscv64")]
564 #[::ink::polkavm_export(abi = ::ink::polkavm_derive::default_abi)]
565 pub extern "C" fn call() {
566 internal_call()
567 }
568 };
569 let fn_deploy: syn::ItemFn = syn::parse_quote! {
570 #[cfg(target_arch = "riscv64")]
571 #[::ink::polkavm_export(abi = ::ink::polkavm_derive::default_abi)]
572 pub extern "C" fn deploy() {
573 internal_deploy()
574 }
575 };
576 quote_spanned!(span=>
577 #[allow(dead_code)] #[allow(clippy::nonminimal_bool)]
579 #[cfg(target_arch = "riscv64")]
580 fn internal_deploy() {
581 if !#any_constructor_accept_payment {
582 ::ink::codegen::deny_payment()
583 .unwrap_or_else(|error| ::core::panic!("{}", error))
584 }
585
586 let dispatchable = match ::ink::env::decode_input::<
587 <#storage_ident as ::ink::reflect::ContractConstructorDecoder>::Type,
588 >() {
589 ::core::result::Result::Ok(decoded_dispatchable) => {
590 decoded_dispatchable
591 }
592 ::core::result::Result::Err(_decoding_error) => {
593 let error = ::ink::ConstructorResult::Err(::ink::LangError::CouldNotReadInput);
594
595 ::ink::env::return_value::<::ink::ConstructorResult<()>>(
602 ::ink::env::ReturnFlags::REVERT,
603 &error,
604 );
605 }
606 };
607
608 <<#storage_ident as ::ink::reflect::ContractConstructorDecoder>::Type
609 as ::ink::reflect::ExecuteDispatchable>::execute_dispatchable(dispatchable)
610 .unwrap_or_else(|error| {
611 ::core::panic!("dispatching ink! constructor failed: {}", error)
612 })
613 }
614
615 #[allow(dead_code)] #[allow(clippy::nonminimal_bool)]
617 #[cfg(target_arch = "riscv64")]
618 fn internal_call() {
619 if !#any_message_accepts_payment {
620 ::ink::codegen::deny_payment()
621 .unwrap_or_else(|error| ::core::panic!("{}", error))
622 }
623
624 let dispatchable = match ::ink::env::decode_input::<
625 <#storage_ident as ::ink::reflect::ContractMessageDecoder>::Type,
626 >() {
627 ::core::result::Result::Ok(decoded_dispatchable) => {
628 decoded_dispatchable
629 }
630 ::core::result::Result::Err(_decoding_error) => {
631 let error = ::ink::MessageResult::Err(::ink::LangError::CouldNotReadInput);
632
633 ::ink::env::return_value::<::ink::MessageResult<()>>(
640 ::ink::env::ReturnFlags::REVERT,
641 &error,
642 );
643 }
644 };
645
646 <<#storage_ident as ::ink::reflect::ContractMessageDecoder>::Type
647 as ::ink::reflect::ExecuteDispatchable>::execute_dispatchable(dispatchable)
648 .unwrap_or_else(|error| {
649 ::core::panic!("dispatching ink! message failed: {}", error)
650 })
651 }
652
653 #fn_call
654
655 #fn_deploy
656 )
657 }
658
659 fn generate_constructor_decoder_type(
665 &self,
666 constructors: &[ConstructorDispatchable],
667 ) -> TokenStream2 {
668 fn expand_constructor_input(
671 span: proc_macro2::Span,
672 storage_ident: &syn::Ident,
673 constructor_id: LitInt,
674 ) -> TokenStream2 {
675 quote_spanned!(span=>
676 <#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #constructor_id >>::Input
677 )
678 }
679
680 fn constructor_variant_ident(n: usize) -> syn::Ident {
682 quote::format_ident!("Constructor{}", n)
683 }
684
685 let span = self.contract.module().storage().span();
686 let storage_ident = self.contract.module().storage().ident();
687 let constructors_variants =
688 constructors.iter().enumerate().map(|(index, item)| {
689 let constructor_span = item.constructor.span();
690 let constructor_ident = constructor_variant_ident(index);
691 let cfg_attrs = item.constructor.get_cfg_attrs(constructor_span);
692 let constructor_input = expand_constructor_input(
693 constructor_span,
694 storage_ident,
695 item.id.clone(),
696 );
697 quote_spanned!(constructor_span=>
698 #( #cfg_attrs )*
699 #constructor_ident(#constructor_input)
700 )
701 });
702
703 let constructor_selector=
704 constructors.iter().enumerate().map(|(index, item)| {
705 let constructor_span = item.constructor.span();
706 let const_ident = format_ident!("CONSTRUCTOR_{}", index);
707 let id = item.id.clone();
708 let cfg_attrs = item.constructor.get_cfg_attrs(constructor_span);
709 quote_spanned!(span=>
710 #( #cfg_attrs )*
711 const #const_ident: [::core::primitive::u8; 4usize] = <#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >>::SELECTOR;
712 )
713 });
714
715 let constructor_match = constructors.iter().enumerate().map(|(index, item)| {
716 let constructor_span = item.constructor.span();
717 let constructor_ident = constructor_variant_ident(index);
718 let const_ident = format_ident!("CONSTRUCTOR_{}", index);
719 let constructor_input = expand_constructor_input(
720 constructor_span,
721 storage_ident,
722 item.id.clone(),
723 );
724 let cfg_attrs = item.constructor.get_cfg_attrs(constructor_span);
725 quote_spanned!(constructor_span=>
726 #( #cfg_attrs )*
727 #const_ident => {
728 ::core::result::Result::Ok(Self::#constructor_ident(
729 <#constructor_input as ::ink::scale::Decode>::decode(input)
730 .map_err(|_| ::ink::env::DispatchError::InvalidParameters)?
731 ))
732 }
733 )
734 });
735 let possibly_wildcard_selector_constructor = match self
736 .query_wildcard_constructor()
737 {
738 Some(wildcard_index) => {
739 let item = &constructors[wildcard_index];
740 let constructor_span = item.constructor.span();
741 let constructor_ident = constructor_variant_ident(wildcard_index);
742 let constructor_input = expand_constructor_input(
743 constructor_span,
744 storage_ident,
745 item.id.clone(),
746 );
747 quote! {
748 ::core::result::Result::Ok(Self::#constructor_ident(
749 <#constructor_input as ::ink::scale::Decode>::decode(input)
750 .map_err(|_| ::ink::env::DispatchError::InvalidParameters)?
751 ))
752 }
753 }
754 None => {
755 quote! {
756 ::core::result::Result::Err(::ink::env::DispatchError::UnknownSelector)
757 }
758 }
759 };
760
761 let constructor_execute = constructors.iter().enumerate().map(|(index, item)| {
762 let constructor_span = item.constructor.span();
763 let constructor_ident = constructor_variant_ident(index);
764 let id = item.id.clone();
765 let cfg_attrs = item.constructor.get_cfg_attrs(constructor_span);
766 let constructor_callable = quote_spanned!(constructor_span=>
767 <#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >>::CALLABLE
768 );
769 let constructor_output = quote_spanned!(constructor_span=>
770 <#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >>::Output
771 );
772 let deny_payment = quote_spanned!(constructor_span=>
773 !<#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >>::PAYABLE
774 );
775 let constructor_value = quote_spanned!(constructor_span=>
776 <::ink::reflect::ConstructorOutputValue<#constructor_output>
777 as ::ink::reflect::ConstructorOutput::<#storage_ident>>
778 );
779
780 let constructor_accept_payment_assignment =
781 self.any_constructor_accepts_payment(constructors);
782
783 quote_spanned!(constructor_span=>
784 #( #cfg_attrs )*
785 Self::#constructor_ident(input) => {
786 if #constructor_accept_payment_assignment && #deny_payment {
787 ::ink::codegen::deny_payment()?;
788 }
789
790 let result: #constructor_output = #constructor_callable(input);
791 let output_value = ::ink::reflect::ConstructorOutputValue::new(result);
792 let output_result = #constructor_value::as_result(&output_value);
793
794 if let ::core::result::Result::Ok(contract) = output_result.as_ref() {
795 ::ink::env::set_contract_storage::<::ink::primitives::Key, #storage_ident>(
796 &<#storage_ident as ::ink::storage::traits::StorageKey>::KEY,
797 contract,
798 );
799 }
800
801 let mut flag = ::ink::env::ReturnFlags::empty();
805 if output_result.is_err() {
806 flag = ::ink::env::ReturnFlags::REVERT;
807 }
808
809 ::ink::env::return_value::<
810 ::ink::ConstructorResult<
811 ::core::result::Result<(), &#constructor_value::Error>
812 >,
813 >(
814 flag,
815 &::ink::ConstructorResult::Ok(output_result.map(|_| ())),
818 );
819
820 #[cfg(feature = "std")]
821 return ::core::result::Result::Ok(());
822
823 #[cfg(not(feature = "std"))]
824 #[cfg_attr(not(feature = "std"), allow(unreachable_code))]
825 {
826 ::core::unreachable!("either `return_value` or the `return` before will already have returned");
827 }
828 }
829 )
830 });
831 quote_spanned!(span=>
832 const _: () = {
833 #[allow(non_camel_case_types)]
834 pub enum __ink_ConstructorDecoder {
835 #( #constructors_variants ),*
836 }
837
838 impl ::ink::env::DecodeDispatch for __ink_ConstructorDecoder {
839 fn decode_dispatch(input: &mut &[::core::primitive::u8])
840 -> ::core::result::Result<Self, ::ink::env::DispatchError> {
841 #(
842 #constructor_selector
843 )*
844 match <[::core::primitive::u8; 4usize] as ::ink::scale::Decode>::decode(input)
845 .map_err(|_| ::ink::env::DispatchError::InvalidSelector)?
846 {
847 #( #constructor_match , )*
848 _invalid => #possibly_wildcard_selector_constructor
849 }
850 }
851 }
852
853 impl ::ink::reflect::ExecuteDispatchable for __ink_ConstructorDecoder {
854 #[allow(clippy::nonminimal_bool, dead_code)]
855 fn execute_dispatchable(self) -> ::core::result::Result<(), ::ink::env::DispatchError> {
856 match self {
857 #( #constructor_execute ),*
858 }
859 }
860 }
861
862 impl ::ink::reflect::ContractConstructorDecoder for #storage_ident {
863 type Type = __ink_ConstructorDecoder;
864 }
865 };
866 )
867 }
868
869 fn generate_message_decoder_type(
875 &self,
876 messages: &[MessageDispatchable],
877 ) -> TokenStream2 {
878 fn expand_message_input(
881 span: proc_macro2::Span,
882 storage_ident: &syn::Ident,
883 message_id: TokenStream2,
884 ) -> TokenStream2 {
885 quote_spanned!(span=>
886 <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #message_id >>::Input
887 )
888 }
889
890 fn message_variant_ident(n: usize) -> syn::Ident {
892 quote::format_ident!("Message{}", n)
893 }
894
895 let span = self.contract.module().storage().span();
896 let storage_ident = self.contract.module().storage().ident();
897 let message_variants = messages.iter().enumerate().map(|(index, item)| {
898 let message_span = item.message.span();
899 let message_ident = message_variant_ident(index);
900 let cfg_attrs = item.message.get_cfg_attrs(message_span);
901 let message_input =
902 expand_message_input(message_span, storage_ident, item.id.clone());
903 quote_spanned!(message_span=>
904 #( #cfg_attrs )*
905 #message_ident(#message_input)
906 )
907 });
908
909 let message_selector = messages
910 .iter()
911 .enumerate()
912 .map(|(index, item)| {
913 let message_span = item.message.span();
914 let const_ident = format_ident!("MESSAGE_{}", index);
915 let cfg_attrs = item.message.get_cfg_attrs(message_span);
916 let id = item.id.clone();
917 quote_spanned!(span=>
918 #( #cfg_attrs )*
919 const #const_ident: [::core::primitive::u8; 4usize] = <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::SELECTOR;
920 )
921 });
922
923 let message_match = messages
924 .iter()
925 .enumerate()
926 .map(|(index, item)| {
927 let message_ident = message_variant_ident(index);
928 let const_ident = format_ident!("MESSAGE_{}", index);
929 let message_span = item.message.span();
930 let cfg_attrs = item.message.get_cfg_attrs(message_span);
931 let id = item.id.clone();
932 quote_spanned!(message_span=>
933 #( #cfg_attrs )*
934 #const_ident => {
935 ::core::result::Result::Ok(Self::#message_ident(
936 <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::DECODE(input)?
937 ))
938 }
939 )
940 });
941 let possibly_wildcard_selector_message = match self.query_wildcard_message() {
942 Some(wildcard_index) => {
943 let item = messages
944 .get(wildcard_index)
945 .expect("unable to get wildcard index");
946 let message_span = item.message.span();
947 let message_ident = message_variant_ident(wildcard_index);
948 let message_input =
949 expand_message_input(message_span, storage_ident, item.id.clone());
950 quote! {
951 ::core::result::Result::Ok(Self::#message_ident(
952 <#message_input as ::ink::scale::Decode>::decode(input)
953 .map_err(|_| ::ink::env::DispatchError::InvalidParameters)?
954 ))
955 }
956 }
957 None => {
958 quote! {
959 ::core::result::Result::Err(::ink::env::DispatchError::UnknownSelector)
960 }
961 }
962 };
963
964 let message_execute = messages
965 .iter()
966 .enumerate()
967 .map(|(index, item)| {
968 let message_span = item.message.span();
969 let message_ident = message_variant_ident(index);
970 let id = item.id.clone();
971 let cfg_attrs = item.message.get_cfg_attrs(message_span);
972 let message_callable = quote_spanned!(message_span=>
973 <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::CALLABLE
974 );
975 let message_return = quote_spanned!(message_span=>
976 <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::RETURN
977 );
978 let message_output = quote_spanned!(message_span=>
979 <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::Output
980 );
981 let deny_payment = quote_spanned!(message_span=>
982 !<#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::PAYABLE
983 );
984 let mutates_storage = quote_spanned!(message_span=>
985 <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::MUTATES
986 );
987
988 let any_message_accepts_payment =
989 self.any_message_accepts_payment(messages);
990
991 quote_spanned!(message_span=>
992 #( #cfg_attrs )*
993 Self::#message_ident(input) => {
994 if #any_message_accepts_payment && #deny_payment {
995 ::ink::codegen::deny_payment()?;
996 }
997
998 let result: #message_output = #message_callable(&mut contract, input);
999 let is_reverted = ::ink::is_result_type!(#message_output)
1000 && ::ink::is_result_err!(result);
1001
1002 let mut flag = ::ink::env::ReturnFlags::REVERT;
1006
1007 if !is_reverted {
1009 flag = ::ink::env::ReturnFlags::empty();
1010 push_contract(contract, #mutates_storage);
1011 }
1012
1013 #message_return(flag, result);
1014
1015 #[cfg(feature = "std")]
1016 return ::core::result::Result::Ok(());
1017
1018 #[cfg(not(feature = "std"))]
1019 #[cfg_attr(not(feature = "std"), allow(unreachable_code))]
1020 {
1021 ::core::unreachable!("either `return_value` or the `return` before will already have returned");
1022 }
1023 }
1024 )
1025 });
1026
1027 quote_spanned!(span=>
1028 const _: () = {
1029 #[allow(non_camel_case_types)]
1030 pub enum __ink_MessageDecoder {
1031 #( #message_variants ),*
1032 }
1033
1034 impl ::ink::env::DecodeDispatch for __ink_MessageDecoder {
1035 fn decode_dispatch(input: &mut &[::core::primitive::u8])
1036 -> ::core::result::Result<Self, ::ink::env::DispatchError> {
1037 #(
1038 #message_selector
1039 )*
1040 match <[::core::primitive::u8; 4usize] as ::ink::scale::Decode>::decode(input)
1041 .map_err(|_| ::ink::env::DispatchError::InvalidSelector)?
1042 {
1043 #( #message_match , )*
1044 _invalid => #possibly_wildcard_selector_message
1045 }
1046 }
1047 }
1048
1049 fn push_contract(contract: ::core::mem::ManuallyDrop<#storage_ident>, mutates: bool) {
1050 if mutates {
1051 ::ink::env::set_contract_storage::<::ink::primitives::Key, #storage_ident>(
1052 &<#storage_ident as ::ink::storage::traits::StorageKey>::KEY,
1053 &contract,
1054 );
1055 }
1056 }
1057
1058 impl ::ink::reflect::ExecuteDispatchable for __ink_MessageDecoder {
1059 #[allow(clippy::nonminimal_bool, clippy::let_unit_value, dead_code)]
1060 fn execute_dispatchable(
1061 self
1062 ) -> ::core::result::Result<(), ::ink::env::DispatchError> {
1063 let key = <#storage_ident as ::ink::storage::traits::StorageKey>::KEY;
1064 let mut contract: ::core::mem::ManuallyDrop<#storage_ident> =
1065 ::core::mem::ManuallyDrop::new(
1066 match ::ink::env::get_contract_storage(&key) {
1067 ::core::result::Result::Ok(::core::option::Option::Some(value)) => value,
1068 ::core::result::Result::Ok(::core::option::Option::None) => {
1069 ::core::panic!("storage entry was empty")
1070 },
1071 ::core::result::Result::Err(_) => {
1072 ::core::panic!("could not properly decode storage entry")
1073 },
1074 }
1075 );
1076
1077 match self {
1078 #( #message_execute ),*
1079 }
1080 }
1081 }
1082
1083 impl ::ink::reflect::ContractMessageDecoder for #storage_ident {
1084 type Type = __ink_MessageDecoder;
1085 }
1086 };
1087 )
1088 }
1089
1090 fn any_message_accepts_payment(
1100 &self,
1101 messages: &[MessageDispatchable],
1102 ) -> TokenStream2 {
1103 let span = self.contract.module().storage().span();
1104 let storage_ident = self.contract.module().storage().ident();
1105 let message_is_payable = messages
1106 .iter()
1107 .enumerate()
1108 .map(|(index, item)| {
1109 let message_span = item.message.span();
1110 let cfg_attrs = item.message.get_cfg_attrs(message_span);
1111 let id = item.id.clone();
1112 let ident = quote::format_ident!("message_{}", index);
1113 quote_spanned!(message_span=>
1114 {
1115 let #ident = false;
1116 #( #cfg_attrs )*
1117 let #ident = <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::PAYABLE;
1118 #ident
1119 }
1120 )
1121 });
1122 quote_spanned!(span=>
1123 {
1124 false #( || #message_is_payable )*
1125 }
1126 )
1127 }
1128
1129 fn any_constructor_accepts_payment(
1139 &self,
1140 constructors: &[ConstructorDispatchable],
1141 ) -> TokenStream2 {
1142 let span = self.contract.module().storage().span();
1143 let storage_ident = self.contract.module().storage().ident();
1144 let constructor_is_payable = constructors.iter().enumerate().map(|(index, item)| {
1145 let constructor_span = item.constructor.span();
1146 let cfg_attrs = item.constructor.get_cfg_attrs(constructor_span);
1147 let id = item.id.clone();
1148 let ident = quote::format_ident!("constructor_{}", index);
1149 quote_spanned!(constructor_span=>
1150 {
1151 let #ident = false;
1152 #( #cfg_attrs )*
1153 let #ident = <#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >>::PAYABLE;
1154 #ident
1155 }
1156 )
1157 });
1158 quote_spanned!(span=>
1159 {
1160 false #( || #constructor_is_payable )*
1161 }
1162 )
1163 }
1164
1165 #[cfg(any(ink_abi = "sol", ink_abi = "all"))]
1167 fn generate_solidity_call_info(&self) -> TokenStream2 {
1168 let span = self.contract.module().span();
1169 let call_tys = self
1170 .contract
1171 .module()
1172 .impls()
1173 .flat_map(|item_impl| item_impl.iter_messages())
1174 .map(|message| {
1175 let span = message.span();
1176 let ident = message.ident();
1177 let ident_str = ident.to_string();
1178 let call_type_ident = sol::utils::call_info_type_ident(&message);
1179 let signature = sol::utils::call_signature(ident_str, message.inputs());
1180
1181 quote_spanned!(span=>
1182 pub struct #call_type_ident;
1183
1184 const _: () = {
1185 impl #call_type_ident {
1186 pub const SIGNATURE: &'static ::core::primitive::str = #signature;
1187 pub const SELECTOR: [::core::primitive::u8; 4usize] = ::ink::codegen::sol_selector_bytes(Self::SIGNATURE);
1188 pub const SELECTOR_ID: ::core::primitive::u32 = ::core::primitive::u32::from_be_bytes(Self::SELECTOR);
1189 }
1190 };
1191 )
1192 });
1193 quote_spanned!(span=>
1194 #[allow(non_camel_case_types)]
1195 mod __ink_sol_interop__ {
1196 #[allow(unused)]
1197 use super::*;
1198
1199 #(#call_tys)*
1200 }
1201 )
1202 }
1203}