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