1use core::iter;
16
17use derive_more::From;
18use ink_primitives::abi::Abi;
19use ir::{
20 Callable,
21 CallableWithSelector,
22 Constructor,
23 HexLiteral as _,
24 Message,
25};
26use itertools::Itertools;
27use proc_macro2::{
28 Ident,
29 TokenStream as TokenStream2,
30};
31use quote::{
32 format_ident,
33 quote,
34 quote_spanned,
35};
36use syn::spanned::Spanned as _;
37
38use crate::{
39 generator,
40 generator::sol,
41 GenerateCode,
42};
43
44pub struct MessageDispatchable<'a> {
47 message: CallableWithSelector<'a, Message>,
48 id: TokenStream2,
49}
50
51pub struct ConstructorDispatchable<'a> {
54 constructor: CallableWithSelector<'a, Constructor>,
55 id: TokenStream2,
56 abi: Abi,
57}
58
59#[derive(From)]
73pub struct Dispatch<'a> {
74 contract: &'a ir::Contract,
75}
76impl_as_ref_for_generator!(Dispatch);
77
78impl GenerateCode for Dispatch<'_> {
79 fn generate_code(&self) -> TokenStream2 {
80 let messages = self.compose_messages_with_ids();
81 let constructors = self.compose_constructors_with_ids();
82
83 let contract_dispatchable_constructor_infos =
84 self.generate_dispatchable_constructor_infos();
85 let contract_dispatchable_messages_infos =
86 self.generate_dispatchable_message_infos();
87 let constructor_decoder_type =
88 self.generate_constructor_decoder_type(&constructors);
89 let message_decoder_type = self.generate_message_decoder_type(&messages);
90 let entry_points = self.generate_entry_points(&constructors, &messages);
91
92 quote! {
93 #contract_dispatchable_constructor_infos
94 #contract_dispatchable_messages_infos
95 #constructor_decoder_type
96 #message_decoder_type
97
98 #[cfg(not(any(test, feature = "std", feature = "ink-as-dependency")))]
99 mod __do_not_access__ {
100 use super::*;
101 #entry_points
102 }
103 }
104 }
105}
106
107const SOL_CTOR_ID: u32 = 0;
112
113impl Dispatch<'_> {
114 fn query_wildcard_message(&self) -> Option<usize> {
116 self.contract
117 .module()
118 .impls()
119 .flat_map(|item_impl| item_impl.iter_messages())
120 .position(|item| item.has_wildcard_selector())
121 }
122
123 #[cfg_attr(ink_abi = "sol", allow(dead_code))]
126 fn query_wildcard_constructor(&self) -> Option<usize> {
127 self.contract
128 .module()
129 .impls()
130 .flat_map(|item_impl| item_impl.iter_constructors())
131 .position(|item| item.has_wildcard_selector())
132 }
133
134 fn constructor_sol(&self) -> Option<CallableWithSelector<Constructor>> {
136 self.contract
137 .module()
138 .impls()
139 .flat_map(|item_impl| item_impl.iter_constructors())
140 .find_or_first(|constructor| constructor.is_default())
141 }
142
143 fn compose_messages_with_ids(&self) -> Vec<MessageDispatchable> {
147 let storage_ident = self.contract.module().storage().ident();
148 self.contract
149 .module()
150 .impls()
151 .flat_map(|item_impl| {
152 iter::repeat(item_impl.trait_path()).zip(item_impl.iter_messages())
153 })
154 .flat_map(|(trait_path, message)| {
155 let mut message_dispatchables = Vec::new();
156 for_each_abi!(@type |abi| {
157 match abi {
158 Abi::Ink => {
159 let span = message.span();
160 let id = if let Some(trait_path) = trait_path {
161 let local_id = message.local_id().hex_padded_suffixed();
162 quote_spanned!(span=>
163 {
164 ::core::primitive::u32::from_be_bytes(
165 <<::ink::reflect::TraitDefinitionRegistry<<#storage_ident as ::ink::env::ContractEnv>::Env>
166 as #trait_path>::__ink_TraitInfo
167 as ::ink::reflect::TraitMessageInfo<#local_id>>::SELECTOR
168 )
169 }
170 )
171 } else {
172 let id = message
173 .composed_selector()
174 .into_be_u32()
175 .hex_padded_suffixed();
176 quote_spanned!(span=>
177 #id
178 )
179 };
180 message_dispatchables.push(MessageDispatchable { message, id });
181 }
182 Abi::Sol => {
183 let id = sol::utils::selector_id(&message);
184 message_dispatchables.push(MessageDispatchable { message, id });
185 }
186 }
187 });
188
189 message_dispatchables
190 })
191 .collect::<Vec<_>>()
192 }
193
194 fn compose_constructors_with_ids(&self) -> Vec<ConstructorDispatchable> {
198 let mut constructor_dispatchables = Vec::new();
199 for_each_abi!(@type |abi| {
200 match abi {
201 Abi::Ink => {
202 constructor_dispatchables.extend(
203 self.contract
204 .module()
205 .impls()
206 .flat_map(|item_impl| item_impl.iter_constructors())
207 .map(|constructor| {
208 let id = constructor
209 .composed_selector()
210 .into_be_u32()
211 .hex_padded_suffixed();
212 ConstructorDispatchable {
213 constructor,
214 id: quote!( #id ),
215 abi: Abi::Ink
216 }
217 })
218 );
219 }
220 Abi::Sol => {
221 let constructor = self.constructor_sol()
223 .expect("Expected at least one constructor");
224 constructor_dispatchables.push(
225 ConstructorDispatchable {
226 constructor,
227 id: quote!( #SOL_CTOR_ID ),
228 abi: Abi::Sol
229 }
230 );
231 }
232 }
233 });
234 constructor_dispatchables
235 }
236
237 fn generate_dispatchable_constructor_infos(&self) -> TokenStream2 {
242 generate_abi_impls!(@type |abi| {
243 match abi {
244 Abi::Ink => {
245 let span = self.contract.module().storage().span();
246 let constructor_infos = self
247 .contract
248 .module()
249 .impls()
250 .flat_map(|item_impl| item_impl.iter_constructors())
251 .map(|constructor| self.generate_dispatchable_constructor_info(constructor, abi));
252 quote_spanned!(span=>
253 #( #constructor_infos )*
254 )
255 }
256 Abi::Sol => {
257 let constructor = self.constructor_sol()
259 .expect("Expected at least one constructor");
260 self.generate_dispatchable_constructor_info(constructor, abi)
261 }
262 }
263 })
264 }
265
266 fn generate_dispatchable_constructor_info(
278 &self,
279 constructor: CallableWithSelector<Constructor>,
280 abi: Abi,
281 ) -> TokenStream2 {
282 let storage_ident = self.contract.module().storage().ident();
283 let span = constructor.span();
284 let constructor_ident = constructor.ident();
285 let payable = constructor.is_payable();
286 let cfg_attrs = constructor.get_cfg_attrs(span);
287 let output_type = constructor
288 .output()
289 .map(quote::ToTokens::to_token_stream)
290 .unwrap_or_else(|| quote! { () });
291 let input_bindings = generator::input_bindings(constructor.inputs());
292 let input_tuple_type = generator::input_types_tuple(constructor.inputs());
293 let input_tuple_bindings = generator::input_bindings_tuple(constructor.inputs());
294 let constructor_return_type = quote_spanned!(span=>
295 <::ink::reflect::ConstructorOutputValue<#output_type>
296 as ::ink::reflect::ConstructorOutput<#storage_ident>>
297 );
298
299 #[cfg(feature = "std")]
300 let return_type = quote! { () };
301 #[cfg(not(feature = "std"))]
302 let return_type = quote! { ! };
303
304 let (constructor_id, selector_bytes, abi_ty, decode_trait, return_expr) =
305 match abi {
306 Abi::Ink => {
307 let id = constructor
308 .composed_selector()
309 .into_be_u32()
310 .hex_padded_suffixed();
311 let selector_bytes = constructor.composed_selector().hex_lits();
312 (
313 quote!( #id ),
314 quote! {
315 ::core::option::Option::Some([ #( #selector_bytes ),* ])
316 },
317 quote!(::ink::abi::Abi::Ink),
318 quote!(::ink::scale::Decode),
319 quote_spanned!(span =>
320 ::ink::env::return_value::<
321 ::ink::ConstructorResult<
322 ::core::result::Result<(), &Self::Error>
323 >,
324 >(
325 flags,
326 &::ink::ConstructorResult::Ok(output),
329 )
330 ),
331 )
332 }
333 Abi::Sol => {
334 let decode_trait = if input_bindings.len() == 1 {
339 quote!(::ink::SolDecode)
340 } else {
341 quote!(::ink::sol::SolParamsDecode)
342 };
343 (
344 quote!( #SOL_CTOR_ID ),
345 quote!(::core::option::Option::None),
346 quote!(::ink::abi::Abi::Sol),
347 decode_trait,
348 quote_spanned!(span =>
349 ::ink::env::return_value_solidity::<::core::result::Result<(), &Self::Error>>(
350 flags,
351 &output,
352 )
353 ),
354 )
355 }
356 };
357 quote_spanned!(span =>
358 #( #cfg_attrs )*
359 impl ::ink::reflect::DispatchableConstructorInfo<#constructor_id> for #storage_ident {
360 type Input = #input_tuple_type;
361 type Output = #output_type;
362 type Storage = #storage_ident;
363 type Error = #constructor_return_type::Error;
364 const IS_RESULT: ::core::primitive::bool = #constructor_return_type::IS_RESULT;
365
366 const CALLABLE: fn(Self::Input) -> Self::Output = |#input_tuple_bindings| {
367 #storage_ident::#constructor_ident(#( #input_bindings ),* )
368 };
369 const DECODE: fn(&mut &[::core::primitive::u8]) -> ::core::result::Result<Self::Input, ::ink::env::DispatchError> =
370 |input| {
371 <Self::Input as #decode_trait>::decode(input)
372 .map_err(|_| ::ink::env::DispatchError::InvalidParameters)
373 };
374 const RETURN: fn(::ink::env::ReturnFlags, ::core::result::Result<(), &Self::Error>) -> #return_type =
375 |flags, output| {
376 #return_expr
377 };
378 const PAYABLE: ::core::primitive::bool = #payable;
379 const SELECTOR: ::core::option::Option<[::core::primitive::u8; 4usize]> = #selector_bytes;
380 const LABEL: &'static ::core::primitive::str = ::core::stringify!(#constructor_ident);
381 const ABI: ::ink::abi::Abi = #abi_ty;
382 }
383 )
384 }
385
386 fn generate_dispatchable_message_infos(&self) -> TokenStream2 {
391 let span = self.contract.module().storage().span();
392
393 let inherent_message_infos = self
394 .contract
395 .module()
396 .impls()
397 .filter(|item_impl| item_impl.trait_path().is_none())
398 .flat_map(|item_impl| item_impl.iter_messages())
399 .map(|message| self.dispatchable_inherent_message_infos(&message));
400 let trait_message_infos = self
401 .contract
402 .module()
403 .impls()
404 .filter_map(|item_impl| {
405 item_impl
406 .trait_path()
407 .map(|trait_path| {
408 let trait_ident = item_impl.trait_ident().expect(
409 "must have an ink! trait identifier if it is an ink! trait implementation"
410 );
411 iter::repeat((trait_ident, trait_path)).zip(item_impl.iter_messages())
412 })
413 })
414 .flatten()
415 .map(|((trait_ident, trait_path), message)| {
416 self.dispatchable_trait_message_infos(&message, trait_ident, trait_path)
417 });
418 quote_spanned!(span=>
419 #( #inherent_message_infos )*
420 #( #trait_message_infos )*
421 )
422 }
423
424 fn dispatchable_inherent_message_infos(
429 &self,
430 message: &CallableWithSelector<Message>,
431 ) -> TokenStream2 {
432 let storage_ident = self.contract.module().storage().ident();
433
434 let message_span = message.span();
435 let message_ident = message.ident();
436 let payable = message.is_payable();
437 let mutates = message.receiver().is_ref_mut();
438
439 let cfg_attrs = message.get_cfg_attrs(message_span);
440 let output_tuple_type = message
441 .output()
442 .map(quote::ToTokens::to_token_stream)
443 .unwrap_or_else(|| quote! { () });
444 let input_bindings = generator::input_bindings(message.inputs());
445 let input_tuple_type = generator::input_types_tuple(message.inputs());
446 let input_tuple_bindings = generator::input_bindings_tuple(message.inputs());
447
448 #[cfg(feature = "std")]
449 let return_type = quote! { () };
450 #[cfg(not(feature = "std"))]
451 let return_type = quote! { ! };
452
453 generate_abi_impls!(@type |abi| {
454 let (selector_id, selector_bytes, abi_ty, decode_trait, return_expr) = match abi {
455 Abi::Ink => {
456 let selector_id = message
457 .composed_selector()
458 .into_be_u32()
459 .hex_padded_suffixed();
460 let selector_bytes = message.composed_selector().hex_lits();
461 (
462 quote!(#selector_id),
463 quote!([ #( #selector_bytes ),* ]),
464 quote!(::ink::abi::Abi::Ink),
465 quote!(::ink::scale::Decode),
466 quote! {
467 ::ink::env::return_value::<::ink::MessageResult::<Self::Output>>(
468 flags,
469 &::ink::MessageResult::Ok(output),
472 )
473 },
474 )
475 }
476 Abi::Sol => {
477 let decode_trait = if input_bindings.len() == 1 {
478 quote!(::ink::SolDecode)
479 } else {
480 quote!(::ink::sol::SolParamsDecode)
481 };
482 (
483 sol::utils::selector_id(message),
484 sol::utils::selector(message),
485 quote!(::ink::abi::Abi::Sol),
486 decode_trait,
487 quote! {
488 ::ink::env::return_value_solidity::<Self::Output>(
489 flags,
490 &output,
491 )
492 },
493 )
494 }
495 };
496 quote_spanned!(message_span=>
497 #( #cfg_attrs )*
498 impl ::ink::reflect::DispatchableMessageInfo<#selector_id> for #storage_ident {
499 type Input = #input_tuple_type;
500 type Output = #output_tuple_type;
501 type Storage = #storage_ident;
502
503 const CALLABLE: fn(&mut Self::Storage, Self::Input) -> Self::Output =
504 |storage, #input_tuple_bindings| {
505 #storage_ident::#message_ident( storage #( , #input_bindings )* )
506 };
507 const DECODE: fn(&mut &[::core::primitive::u8]) -> ::core::result::Result<Self::Input, ::ink::env::DispatchError> =
508 |input| {
509 <Self::Input as #decode_trait>::decode(input)
510 .map_err(|_| ::ink::env::DispatchError::InvalidParameters)
511 };
512 const RETURN: fn(::ink::env::ReturnFlags, Self::Output) -> #return_type =
513 |flags, output| {
514 #return_expr
515 };
516 const SELECTOR: [::core::primitive::u8; 4usize] = #selector_bytes;
517 const PAYABLE: ::core::primitive::bool = #payable;
518 const MUTATES: ::core::primitive::bool = #mutates;
519 const LABEL: &'static ::core::primitive::str = ::core::stringify!(#message_ident);
520 const ABI: ::ink::abi::Abi = #abi_ty;
521 }
522 )
523 })
524 }
525
526 fn dispatchable_trait_message_infos(
531 &self,
532 message: &CallableWithSelector<Message>,
533 trait_ident: &Ident,
534 trait_path: &syn::Path,
535 ) -> TokenStream2 {
536 let storage_ident = self.contract.module().storage().ident();
537
538 let message_span = message.span();
539 let message_ident = message.ident();
540 let mutates = message.receiver().is_ref_mut();
541 let output_tuple_type = message
542 .output()
543 .map(quote::ToTokens::to_token_stream)
544 .unwrap_or_else(|| quote! { () });
545 let input_bindings = generator::input_bindings(message.inputs());
546 let input_tuple_type = generator::input_types_tuple(message.inputs());
547 let input_tuple_bindings = generator::input_bindings_tuple(message.inputs());
548 let label = format!("{trait_ident}::{message_ident}");
549 let cfg_attrs = message.get_cfg_attrs(message_span);
550
551 #[cfg(feature = "std")]
552 let return_type = quote! { () };
553 #[cfg(not(feature = "std"))]
554 let return_type = quote! { ! };
555
556 generate_abi_impls!(@type |abi| {
557 let (local_id, abi_ty, decode_trait, return_expr) = match abi {
558 Abi::Ink => {
559 let local_id = message.local_id().hex_padded_suffixed();
560 (
561 quote!(#local_id),
562 quote!(::ink::abi::Abi::Ink),
563 quote!(::ink::scale::Decode),
564 quote! {
565 ::ink::env::return_value::<::ink::MessageResult::<Self::Output>>(
566 flags,
567 &::ink::MessageResult::Ok(output),
570 )
571 },
572 )
573 }
574 Abi::Sol => {
575 let decode_trait = if input_bindings.len() == 1 {
576 quote!(::ink::SolDecode)
577 } else {
578 quote!(::ink::sol::SolParamsDecode)
579 };
580 (
581 sol::utils::selector_id(message),
582 quote!(::ink::abi::Abi::Sol),
583 decode_trait,
584 quote! {
585 ::ink::env::return_value_solidity::<Self::Output>(
586 flags,
587 &output,
588 )
589 },
590 )
591 }
592 };
593 let payable = quote! {{
594 <<::ink::reflect::TraitDefinitionRegistry<<#storage_ident as ::ink::env::ContractEnv>::Env>
595 as #trait_path>::__ink_TraitInfo
596 as ::ink::reflect::TraitMessageInfo<#local_id>>::PAYABLE
597 }};
598 let selector = quote! {{
599 <<::ink::reflect::TraitDefinitionRegistry<<#storage_ident as ::ink::env::ContractEnv>::Env>
600 as #trait_path>::__ink_TraitInfo
601 as ::ink::reflect::TraitMessageInfo<#local_id>>::SELECTOR
602 }};
603 let selector_id = quote! {{
604 ::core::primitive::u32::from_be_bytes(#selector)
605 }};
606 quote_spanned!(message_span=>
607 #( #cfg_attrs )*
608 impl ::ink::reflect::DispatchableMessageInfo<#selector_id> for #storage_ident {
609 type Input = #input_tuple_type;
610 type Output = #output_tuple_type;
611 type Storage = #storage_ident;
612
613 const CALLABLE: fn(&mut Self::Storage, Self::Input) -> Self::Output =
614 |storage, #input_tuple_bindings| {
615 <#storage_ident as #trait_path>::#message_ident( storage #( , #input_bindings )* )
616 };
617 const DECODE: fn(&mut &[::core::primitive::u8]) -> ::core::result::Result<Self::Input, ::ink::env::DispatchError> =
618 |input| {
619 <Self::Input as #decode_trait>::decode(input)
620 .map_err(|_| ::ink::env::DispatchError::InvalidParameters)
621 };
622 const RETURN: fn(::ink::env::ReturnFlags, Self::Output) -> #return_type =
623 |flags, output| {
624 #return_expr
625 };
626 const SELECTOR: [::core::primitive::u8; 4usize] = #selector;
627 const PAYABLE: ::core::primitive::bool = #payable;
628 const MUTATES: ::core::primitive::bool = #mutates;
629 const LABEL: &'static ::core::primitive::str = #label;
630 const ABI: ::ink::abi::Abi = #abi_ty;
631 }
632 )
633 })
634 }
635
636 fn generate_entry_points(
641 &self,
642 constructors: &[ConstructorDispatchable],
643 messages: &[MessageDispatchable],
644 ) -> TokenStream2 {
645 let span = self.contract.module().storage().span();
646 let storage_ident = self.contract.module().storage().ident();
647 let any_constructor_accept_payment =
648 self.any_constructor_accepts_payment(constructors);
649 let any_message_accepts_payment = self.any_message_accepts_payment(messages);
650
651 let fn_call: syn::ItemFn = syn::parse_quote! {
652 #[cfg(target_arch = "riscv64")]
653 #[::ink::polkavm_export(abi = ::ink::polkavm_derive::default_abi)]
654 pub extern "C" fn call() {
655 internal_call()
656 }
657 };
658 let fn_deploy: syn::ItemFn = syn::parse_quote! {
659 #[cfg(target_arch = "riscv64")]
660 #[::ink::polkavm_export(abi = ::ink::polkavm_derive::default_abi)]
661 pub extern "C" fn deploy() {
662 internal_deploy()
663 }
664 };
665 quote_spanned!(span=>
666 #[allow(dead_code)] #[allow(clippy::nonminimal_bool)]
668 #[cfg(target_arch = "riscv64")]
669 fn internal_deploy() {
670 if !#any_constructor_accept_payment {
671 ::ink::codegen::deny_payment()
672 .unwrap_or_else(|error| ::core::panic!("{}", error))
673 }
674
675 let dispatchable = match ::ink::env::decode_input::<
676 <#storage_ident as ::ink::reflect::ContractConstructorDecoder>::Type,
677 >() {
678 ::core::result::Result::Ok(decoded_dispatchable) => {
679 decoded_dispatchable
680 }
681 ::core::result::Result::Err(_decoding_error) => {
682 let error = ::ink::ConstructorResult::Err(::ink::LangError::CouldNotReadInput);
683
684 ::ink::env::return_value::<::ink::ConstructorResult<()>>(
691 ::ink::env::ReturnFlags::REVERT,
692 &error,
693 );
694 }
695 };
696
697 <<#storage_ident as ::ink::reflect::ContractConstructorDecoder>::Type
698 as ::ink::reflect::ExecuteDispatchable>::execute_dispatchable(dispatchable)
699 .unwrap_or_else(|error| {
700 ::core::panic!("dispatching ink! constructor failed: {}", error)
701 })
702 }
703
704 #[allow(dead_code)] #[allow(clippy::nonminimal_bool)]
706 #[cfg(target_arch = "riscv64")]
707 fn internal_call() {
708 if !#any_message_accepts_payment {
709 ::ink::codegen::deny_payment()
710 .unwrap_or_else(|error| ::core::panic!("{}", error))
711 }
712
713 let dispatchable = match ::ink::env::decode_input::<
714 <#storage_ident as ::ink::reflect::ContractMessageDecoder>::Type,
715 >() {
716 ::core::result::Result::Ok(decoded_dispatchable) => {
717 decoded_dispatchable
718 }
719 ::core::result::Result::Err(_decoding_error) => {
720 let error = ::ink::MessageResult::Err(::ink::LangError::CouldNotReadInput);
721
722 ::ink::env::return_value::<::ink::MessageResult<()>>(
729 ::ink::env::ReturnFlags::REVERT,
730 &error,
731 );
732 }
733 };
734
735 <<#storage_ident as ::ink::reflect::ContractMessageDecoder>::Type
736 as ::ink::reflect::ExecuteDispatchable>::execute_dispatchable(dispatchable)
737 .unwrap_or_else(|error| {
738 ::core::panic!("dispatching ink! message failed: {}", error)
739 })
740 }
741
742 #fn_call
743
744 #fn_deploy
745 )
746 }
747
748 fn generate_constructor_decoder_type(
754 &self,
755 constructors: &[ConstructorDispatchable],
756 ) -> TokenStream2 {
757 fn expand_constructor_input(
760 span: proc_macro2::Span,
761 storage_ident: &syn::Ident,
762 constructor_id: TokenStream2,
763 ) -> TokenStream2 {
764 quote_spanned!(span=>
765 <#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #constructor_id >>::Input
766 )
767 }
768
769 fn constructor_variant_ident(n: usize) -> syn::Ident {
771 format_ident!("Constructor{}", n)
772 }
773
774 let span = self.contract.module().storage().span();
775 let storage_ident = self.contract.module().storage().ident();
776 let constructors_variants =
777 constructors.iter().enumerate().map(|(index, item)| {
778 let constructor_span = item.constructor.span();
779 let constructor_ident = constructor_variant_ident(index);
780 let cfg_attrs = item.constructor.get_cfg_attrs(constructor_span);
781 let constructor_input = expand_constructor_input(
782 constructor_span,
783 storage_ident,
784 item.id.clone(),
785 );
786 quote_spanned!(constructor_span=>
787 #( #cfg_attrs )*
788 #constructor_ident(#constructor_input)
789 )
790 });
791
792 let solidity_constructor_dispatch_decode = || {
794 let solidity_constructor_info = constructors
795 .iter()
796 .enumerate()
797 .find(|(_, item)| matches!(item.abi, Abi::Sol));
798 match solidity_constructor_info {
799 Some((index, item)) => {
800 let constructor_span = item.constructor.span();
801 let constructor_ident = constructor_variant_ident(index);
802 quote_spanned!(constructor_span=>
803 <#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #SOL_CTOR_ID >>::DECODE(input)
804 .map(Self::#constructor_ident)
805 )
806 }
807 None => {
808 quote! {
809 ::core::result::Result::Err(::ink::env::DispatchError::UnknownSelector)
810 }
811 }
812 }
813 };
814
815 #[cfg(not(ink_abi = "sol"))]
816 let decode_dispatch = {
817 let constructor_selector =
818 constructors.iter().enumerate().filter_map(|(index, item)| {
819 if matches!(item.abi, Abi::Sol) {
820 return None;
822 }
823 let constructor_span = item.constructor.span();
824 let const_ident = format_ident!("CONSTRUCTOR_{}", index);
825 let id = item.id.clone();
826 let cfg_attrs = item.constructor.get_cfg_attrs(constructor_span);
827 Some(quote_spanned!(span=>
828 #( #cfg_attrs )*
829 const #const_ident: [::core::primitive::u8; 4usize] = <
830 #storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >
831 >::SELECTOR.expect("Expected a selector");
832 ))
833 });
834
835 let constructor_match = constructors.iter()
836 .enumerate()
837 .filter_map(|(index, item)| {
838 if matches!(item.abi, Abi::Sol) {
839 return None;
841 }
842 let constructor_span = item.constructor.span();
843 let constructor_ident = constructor_variant_ident(index);
844 let const_ident = format_ident!("CONSTRUCTOR_{}", index);
845 let id = item.id.clone();
846 let cfg_attrs = item.constructor.get_cfg_attrs(constructor_span);
847 Some(quote_spanned!(constructor_span=>
848 #( #cfg_attrs )*
849 #const_ident => {
850 ::core::result::Result::Ok(Self::#constructor_ident(
851 <#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >>::DECODE(input)?
852 ))
853 }
854 ))
855 });
856
857 let wildcard_selector_constructor =
858 self.query_wildcard_constructor().map(|wildcard_index| {
859 let item = &constructors[wildcard_index];
860 let constructor_span = item.constructor.span();
861 let constructor_ident = constructor_variant_ident(wildcard_index);
862 let constructor_input = expand_constructor_input(
863 constructor_span,
864 storage_ident,
865 item.id.clone(),
866 );
867 quote_spanned!(constructor_span=>
868 <#constructor_input as ::ink::scale::Decode>::decode(input)
869 .map(Self::#constructor_ident)
870 .map_err(|_| ::ink::env::DispatchError::InvalidParameters)
871 )
872 });
873
874 let (possible_full_input_ref, fallback_match) = if cfg!(ink_abi = "all") {
875 let solidity_constructor = solidity_constructor_dispatch_decode();
876 let try_wildcard_selector_constructor = wildcard_selector_constructor
877 .map(|wildcard_selector_constructor| {
878 quote_spanned!(span=>
879 let wildcard_result = #wildcard_selector_constructor;
880 if wildcard_result.is_ok() {
881 return wildcard_result;
882 }
883 )
884 });
885 (
886 quote_spanned!(span=>
889 let mut full_input = *input;
890 ),
891 quote_spanned!(span=>
892 {
893 #try_wildcard_selector_constructor
895
896 let input = &mut full_input;
898 #solidity_constructor
899 }
900 ),
901 )
902 } else {
903 let fallback_match = wildcard_selector_constructor.unwrap_or_else(|| {
904 quote_spanned!(span =>
905 ::core::result::Result::Err(::ink::env::DispatchError::UnknownSelector)
906 )
907 });
908 (quote!(), fallback_match)
909 };
910
911 quote_spanned!(span =>
912 #possible_full_input_ref
913 #(
914 #constructor_selector
915 )*
916 match <[::core::primitive::u8; 4usize] as ::ink::scale::Decode>::decode(input)
917 .map_err(|_| ::ink::env::DispatchError::InvalidSelector)?
918 {
919 #( #constructor_match , )*
920 _invalid => #fallback_match
921 }
922 )
923 };
924 #[cfg(ink_abi = "sol")]
925 let decode_dispatch = {
926 let solidity_constructor = solidity_constructor_dispatch_decode();
927 quote_spanned!(span =>
928 #solidity_constructor
929 )
930 };
931
932 let constructor_execute = constructors.iter().enumerate().map(|(index, item)| {
933 let constructor_span = item.constructor.span();
934 let constructor_ident = constructor_variant_ident(index);
935 let id = item.id.clone();
936 let cfg_attrs = item.constructor.get_cfg_attrs(constructor_span);
937 let constructor_callable = quote_spanned!(constructor_span=>
938 <#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >>::CALLABLE
939 );
940 let constructor_return = quote_spanned!(constructor_span=>
941 <#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >>::RETURN
942 );
943 let constructor_output = quote_spanned!(constructor_span=>
944 <#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >>::Output
945 );
946 let deny_payment = quote_spanned!(constructor_span=>
947 !<#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >>::PAYABLE
948 );
949 let constructor_value = quote_spanned!(constructor_span=>
950 <::ink::reflect::ConstructorOutputValue<#constructor_output>
951 as ::ink::reflect::ConstructorOutput::<#storage_ident>>
952 );
953
954 let constructor_accept_payment_assignment =
955 self.any_constructor_accepts_payment(constructors);
956
957 quote_spanned!(constructor_span=>
958 #( #cfg_attrs )*
959 Self::#constructor_ident(input) => {
960 if #constructor_accept_payment_assignment && #deny_payment {
961 ::ink::codegen::deny_payment()?;
962 }
963
964 let result: #constructor_output = #constructor_callable(input);
965 let output_value = ::ink::reflect::ConstructorOutputValue::new(result);
966 let output_result = #constructor_value::as_result(&output_value);
967
968 if let ::core::result::Result::Ok(contract) = output_result.as_ref() {
969 ::ink::env::set_contract_storage::<::ink::primitives::Key, #storage_ident>(
970 &<#storage_ident as ::ink::storage::traits::StorageKey>::KEY,
971 contract,
972 );
973 }
974
975 let mut flag = ::ink::env::ReturnFlags::empty();
979 if output_result.is_err() {
980 flag = ::ink::env::ReturnFlags::REVERT;
981 }
982
983 #constructor_return(flag, output_result.map(|_| ()));
988
989 #[cfg(feature = "std")]
990 return ::core::result::Result::Ok(());
991
992 #[cfg(not(feature = "std"))]
993 #[cfg_attr(not(feature = "std"), allow(unreachable_code))]
994 {
995 ::core::unreachable!("either `return_value` or the `return` before will already have returned");
996 }
997 }
998 )
999 });
1000 quote_spanned!(span=>
1001 const _: () = {
1002 #[allow(non_camel_case_types)]
1003 pub enum __ink_ConstructorDecoder {
1004 #( #constructors_variants ),*
1005 }
1006
1007 impl ::ink::env::DecodeDispatch for __ink_ConstructorDecoder {
1008 fn decode_dispatch(input: &mut &[::core::primitive::u8])
1009 -> ::core::result::Result<Self, ::ink::env::DispatchError> {
1010 #decode_dispatch
1011 }
1012 }
1013
1014 impl ::ink::reflect::ExecuteDispatchable for __ink_ConstructorDecoder {
1015 #[allow(clippy::nonminimal_bool, dead_code)]
1016 fn execute_dispatchable(self) -> ::core::result::Result<(), ::ink::env::DispatchError> {
1017 match self {
1018 #( #constructor_execute ),*
1019 }
1020 }
1021 }
1022
1023 impl ::ink::reflect::ContractConstructorDecoder for #storage_ident {
1024 type Type = __ink_ConstructorDecoder;
1025 }
1026 };
1027 )
1028 }
1029
1030 fn generate_message_decoder_type(
1036 &self,
1037 messages: &[MessageDispatchable],
1038 ) -> TokenStream2 {
1039 fn expand_message_input(
1042 span: proc_macro2::Span,
1043 storage_ident: &Ident,
1044 message_id: TokenStream2,
1045 ) -> TokenStream2 {
1046 quote_spanned!(span=>
1047 <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #message_id >>::Input
1048 )
1049 }
1050
1051 fn message_variant_ident(n: usize) -> syn::Ident {
1053 format_ident!("Message{}", n)
1054 }
1055
1056 let span = self.contract.module().storage().span();
1057 let storage_ident = self.contract.module().storage().ident();
1058 let message_variants = messages.iter().enumerate().map(|(index, item)| {
1059 let message_span = item.message.span();
1060 let message_ident = message_variant_ident(index);
1061 let cfg_attrs = item.message.get_cfg_attrs(message_span);
1062 let message_input =
1063 expand_message_input(message_span, storage_ident, item.id.clone());
1064 quote_spanned!(message_span=>
1065 #( #cfg_attrs )*
1066 #message_ident(#message_input)
1067 )
1068 });
1069
1070 let message_selector = messages
1071 .iter()
1072 .enumerate()
1073 .map(|(index, item)| {
1074 let message_span = item.message.span();
1075 let const_ident = format_ident!("MESSAGE_{}", index);
1076 let cfg_attrs = item.message.get_cfg_attrs(message_span);
1077 let id = item.id.clone();
1078 quote_spanned!(span=>
1079 #( #cfg_attrs )*
1080 const #const_ident: [::core::primitive::u8; 4usize] = <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::SELECTOR;
1081 )
1082 });
1083
1084 let message_match = messages
1085 .iter()
1086 .enumerate()
1087 .map(|(index, item)| {
1088 let message_ident = message_variant_ident(index);
1089 let const_ident = format_ident!("MESSAGE_{}", index);
1090 let message_span = item.message.span();
1091 let cfg_attrs = item.message.get_cfg_attrs(message_span);
1092 let id = item.id.clone();
1093 quote_spanned!(message_span=>
1094 #( #cfg_attrs )*
1095 #const_ident => {
1096 ::core::result::Result::Ok(Self::#message_ident(
1097 <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::DECODE(input)?
1098 ))
1099 }
1100 )
1101 });
1102 let possibly_wildcard_selector_message = match self.query_wildcard_message() {
1103 Some(wildcard_index) => {
1104 let item = messages
1105 .get(wildcard_index)
1106 .expect("unable to get wildcard index");
1107 let message_span = item.message.span();
1108 let message_ident = message_variant_ident(wildcard_index);
1109 let message_input =
1110 expand_message_input(message_span, storage_ident, item.id.clone());
1111 quote! {
1112 ::core::result::Result::Ok(Self::#message_ident(
1113 <#message_input as ::ink::scale::Decode>::decode(input)
1114 .map_err(|_| ::ink::env::DispatchError::InvalidParameters)?
1115 ))
1116 }
1117 }
1118 None => {
1119 quote! {
1120 ::core::result::Result::Err(::ink::env::DispatchError::UnknownSelector)
1121 }
1122 }
1123 };
1124
1125 let message_execute = messages
1126 .iter()
1127 .enumerate()
1128 .map(|(index, item)| {
1129 let message_span = item.message.span();
1130 let message_ident = message_variant_ident(index);
1131 let id = item.id.clone();
1132 let cfg_attrs = item.message.get_cfg_attrs(message_span);
1133 let message_callable = quote_spanned!(message_span=>
1134 <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::CALLABLE
1135 );
1136 let message_return = quote_spanned!(message_span=>
1137 <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::RETURN
1138 );
1139 let message_output = quote_spanned!(message_span=>
1140 <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::Output
1141 );
1142 let deny_payment = quote_spanned!(message_span=>
1143 !<#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::PAYABLE
1144 );
1145 let mutates_storage = quote_spanned!(message_span=>
1146 <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::MUTATES
1147 );
1148
1149 let any_message_accepts_payment =
1150 self.any_message_accepts_payment(messages);
1151
1152 quote_spanned!(message_span=>
1153 #( #cfg_attrs )*
1154 Self::#message_ident(input) => {
1155 if #any_message_accepts_payment && #deny_payment {
1156 ::ink::codegen::deny_payment()?;
1157 }
1158
1159 let result: #message_output = #message_callable(&mut contract, input);
1160 let is_reverted = ::ink::is_result_type!(#message_output)
1161 && ::ink::is_result_err!(result);
1162
1163 let mut flag = ::ink::env::ReturnFlags::REVERT;
1167
1168 if !is_reverted {
1170 flag = ::ink::env::ReturnFlags::empty();
1171 push_contract(contract, #mutates_storage);
1172 }
1173
1174 #message_return(flag, result);
1175
1176 #[cfg(feature = "std")]
1177 return ::core::result::Result::Ok(());
1178
1179 #[cfg(not(feature = "std"))]
1180 #[cfg_attr(not(feature = "std"), allow(unreachable_code))]
1181 {
1182 ::core::unreachable!("either `return_value` or the `return` before will already have returned");
1183 }
1184 }
1185 )
1186 });
1187
1188 quote_spanned!(span=>
1189 const _: () = {
1190 #[allow(non_camel_case_types)]
1191 pub enum __ink_MessageDecoder {
1192 #( #message_variants ),*
1193 }
1194
1195 impl ::ink::env::DecodeDispatch for __ink_MessageDecoder {
1196 fn decode_dispatch(input: &mut &[::core::primitive::u8])
1197 -> ::core::result::Result<Self, ::ink::env::DispatchError> {
1198 #(
1199 #message_selector
1200 )*
1201 match <[::core::primitive::u8; 4usize] as ::ink::scale::Decode>::decode(input)
1202 .map_err(|_| ::ink::env::DispatchError::InvalidSelector)?
1203 {
1204 #( #message_match , )*
1205 _invalid => #possibly_wildcard_selector_message
1206 }
1207 }
1208 }
1209
1210 fn push_contract(contract: ::core::mem::ManuallyDrop<#storage_ident>, mutates: bool) {
1211 if mutates {
1212 ::ink::env::set_contract_storage::<::ink::primitives::Key, #storage_ident>(
1213 &<#storage_ident as ::ink::storage::traits::StorageKey>::KEY,
1214 &contract,
1215 );
1216 }
1217 }
1218
1219 impl ::ink::reflect::ExecuteDispatchable for __ink_MessageDecoder {
1220 #[allow(clippy::nonminimal_bool, clippy::let_unit_value, dead_code)]
1221 fn execute_dispatchable(
1222 self
1223 ) -> ::core::result::Result<(), ::ink::env::DispatchError> {
1224 let key = <#storage_ident as ::ink::storage::traits::StorageKey>::KEY;
1225 let mut contract: ::core::mem::ManuallyDrop<#storage_ident> =
1226 ::core::mem::ManuallyDrop::new(
1227 match ::ink::env::get_contract_storage(&key) {
1228 ::core::result::Result::Ok(::core::option::Option::Some(value)) => value,
1229 ::core::result::Result::Ok(::core::option::Option::None) => {
1230 ::core::panic!("storage entry was empty")
1231 },
1232 ::core::result::Result::Err(_) => {
1233 ::core::panic!("could not properly decode storage entry")
1234 },
1235 }
1236 );
1237
1238 match self {
1239 #( #message_execute ),*
1240 }
1241 }
1242 }
1243
1244 impl ::ink::reflect::ContractMessageDecoder for #storage_ident {
1245 type Type = __ink_MessageDecoder;
1246 }
1247 };
1248 )
1249 }
1250
1251 fn any_message_accepts_payment(
1261 &self,
1262 messages: &[MessageDispatchable],
1263 ) -> TokenStream2 {
1264 let span = self.contract.module().storage().span();
1265 let storage_ident = self.contract.module().storage().ident();
1266 let message_is_payable = messages
1267 .iter()
1268 .enumerate()
1269 .map(|(index, item)| {
1270 let message_span = item.message.span();
1271 let cfg_attrs = item.message.get_cfg_attrs(message_span);
1272 let id = item.id.clone();
1273 let ident = quote::format_ident!("message_{}", index);
1274 quote_spanned!(message_span=>
1275 {
1276 let #ident = false;
1277 #( #cfg_attrs )*
1278 let #ident = <#storage_ident as ::ink::reflect::DispatchableMessageInfo< #id >>::PAYABLE;
1279 #ident
1280 }
1281 )
1282 });
1283 quote_spanned!(span=>
1284 {
1285 false #( || #message_is_payable )*
1286 }
1287 )
1288 }
1289
1290 fn any_constructor_accepts_payment(
1300 &self,
1301 constructors: &[ConstructorDispatchable],
1302 ) -> TokenStream2 {
1303 let span = self.contract.module().storage().span();
1304 let storage_ident = self.contract.module().storage().ident();
1305 let constructor_is_payable = constructors.iter().enumerate().map(|(index, item)| {
1306 let constructor_span = item.constructor.span();
1307 let cfg_attrs = item.constructor.get_cfg_attrs(constructor_span);
1308 let id = item.id.clone();
1309 let ident = quote::format_ident!("constructor_{}", index);
1310 quote_spanned!(constructor_span=>
1311 {
1312 let #ident = false;
1313 #( #cfg_attrs )*
1314 let #ident = <#storage_ident as ::ink::reflect::DispatchableConstructorInfo< #id >>::PAYABLE;
1315 #ident
1316 }
1317 )
1318 });
1319 quote_spanned!(span=>
1320 {
1321 false #( || #constructor_is_payable )*
1322 }
1323 )
1324 }
1325}