ink_codegen/generator/
arg_list.rs

1// Copyright (C) Use Ink (UK) Ltd.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use heck::ToLowerCamelCase as _;
16use proc_macro2::{
17    Span,
18    TokenStream as TokenStream2,
19    TokenStream,
20};
21use quote::{
22    format_ident,
23    quote,
24    quote_spanned,
25};
26
27/// Returns the associated output type for an ink! trait message.
28pub fn output_ident(message_name: &syn::Ident) -> syn::Ident {
29    format_ident!("{}Output", message_name.to_string().to_lower_camel_case())
30}
31
32/// Returns the sequence of artificial input parameter bindings
33/// for the message or constructor.
34///
35/// # Note
36///
37/// This returns `__ink_binding_N` for every message input where `N` is the number
38/// of the input from first to last.
39pub fn input_bindings(inputs: ir::InputsIter) -> Vec<syn::Ident> {
40    inputs
41        .enumerate()
42        .map(|(n, _)| format_ident!("__ink_binding_{}", n))
43        .collect::<Vec<_>>()
44}
45
46/// Returns the sequence of input types for the message.
47pub fn input_types(inputs: ir::InputsIter) -> Vec<&syn::Type> {
48    inputs.map(|pat_type| &*pat_type.ty).collect::<Vec<_>>()
49}
50
51/// Returns the sequence of input idents for the message.
52pub fn input_message_idents(inputs: ir::InputsIter) -> Vec<&syn::Ident> {
53    inputs
54        .map(|input| {
55            match &*input.pat {
56                syn::Pat::Ident(ident) => &ident.ident,
57                _ => {
58                    unreachable!(
59                        "encountered ink! dispatch input with missing identifier"
60                    )
61                }
62            }
63        })
64        .collect::<Vec<_>>()
65}
66
67/// Returns a tuple type representing the types yielded by the input types.
68pub fn input_types_tuple(inputs: ir::InputsIter) -> TokenStream2 {
69    let input_types = input_types(inputs);
70    // println!("input_types_tuple {}", input_types.len());
71    if input_types.len() != 1 {
72        // Pack all types into a tuple if they are not exactly 1.
73        // This results in `()` for zero input types.
74        quote! { ( #( #input_types ),* ) }
75    } else {
76        // Return the single type without turning it into a tuple.
77        quote! { #( #input_types )* }
78    }
79}
80
81/// Returns a tuple expression representing the bindings yielded by the inputs.
82pub fn input_bindings_tuple(inputs: ir::InputsIter) -> TokenStream2 {
83    let input_bindings = input_bindings(inputs);
84    match input_bindings.len() {
85        0 => quote! { _ },
86        1 => quote! { #( #input_bindings ),* },
87        _ => quote! { ( #( #input_bindings ),* ) },
88    }
89}
90
91/// Builds up the `ink_env::call::utils::ArgumentList` type structure for the given types.
92pub fn generate_argument_list<'b, Args>(args: Args, abi: TokenStream) -> TokenStream2
93where
94    Args: IntoIterator<Item = &'b syn::Type>,
95    <Args as IntoIterator>::IntoIter: Iterator,
96{
97    use syn::spanned::Spanned as _;
98    args.into_iter().fold(
99        quote! { ::ink::env::call::utils::EmptyArgumentList<#abi>},
100        |rest, arg| {
101            let span = arg.span();
102            quote_spanned!(span=>
103                ::ink::env::call::utils::ArgumentList<::ink::env::call::utils::Argument<#arg>, #rest, #abi>
104            )
105        }
106    )
107}
108
109/// Generates code to uniquely identify a trait by its unique ID given only its
110/// identifier.
111///
112/// # Note
113///
114/// As with all Rust macros identifiers can shadow each other so the given identifier
115/// needs to be valid for the scope in which the returned code is generated.
116pub fn generate_reference_to_trait_info(
117    span: Span,
118    trait_path: &syn::Path,
119) -> TokenStream2 {
120    quote_spanned!(span=>
121        <<::ink::reflect::TraitDefinitionRegistry<Environment>
122            as #trait_path>::__ink_TraitInfo as ::ink::reflect::TraitInfo>::ID
123    )
124}