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