ink_codegen/generator/sol/
utils.rs

1// Copyright (C) ink! contributors.
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 ir::{
16    Callable,
17    InputsIter,
18    IsDocAttribute,
19    Message,
20};
21use proc_macro2::TokenStream as TokenStream2;
22use quote::{
23    quote,
24    quote_spanned,
25};
26use syn::{
27    spanned::Spanned,
28    Attribute,
29    Type,
30};
31
32/// Returns the equivalent Solidity ABI type for the given Rust/ink! type.
33pub fn sol_type(ty: &Type) -> TokenStream2 {
34    quote! {
35        <#ty as ::ink::SolDecode>::SOL_NAME
36    }
37}
38
39/// Returns the equivalent Solidity ABI type for the given Rust/ink! return type.
40///
41/// # Note
42///
43/// Use this function (instead of [`sol_type`]) when return type may be `Result<T, E>`,
44/// because `Result<T, E>` implements `ink::SolEncode` but doesn't implement
45/// `ink::SolDecode`.
46pub fn sol_return_type(ty: &Type) -> TokenStream2 {
47    quote! {
48        <#ty as ::ink::SolEncode>::SOL_NAME
49    }
50}
51
52/// Returns Solidity ABI compatible selector of an ink! message.
53pub fn selector(message: &Message) -> TokenStream2 {
54    let signature = call_signature(message.ident().to_string(), message.inputs());
55    quote! {
56        const {
57            ::ink::codegen::sol::selector_bytes(#signature)
58        }
59    }
60}
61
62/// Returns a `u32` representation of the Solidity ABI compatible selector of an ink!
63/// message.
64pub fn selector_id(message: &Message) -> TokenStream2 {
65    let selector_bytes = selector(message);
66    quote!(
67        {
68            const {
69                ::core::primitive::u32::from_be_bytes(#selector_bytes)
70            }
71        }
72    )
73}
74
75/// Returns the Solidity ABI call signature for the given message name and inputs.
76pub fn call_signature(name: String, inputs: InputsIter) -> TokenStream2 {
77    let mut input_types_len = 0;
78    let sig_param_tys: Vec<_> = inputs
79        .map(|input| {
80            let ty = &*input.ty;
81            let sol_ty = sol_type(ty);
82            let span = input.span();
83            input_types_len += 1;
84
85            quote_spanned!(span=>
86                #sol_ty
87            )
88        })
89        .collect();
90    let sig_arg_fmt_params = (0..input_types_len)
91        .map(|_| "{}")
92        .collect::<Vec<_>>()
93        .join(",");
94    let sig_fmt_lit = format!("{{}}({sig_arg_fmt_params})");
95    quote! {
96        ::ink::codegen::utils::const_format!(#sig_fmt_lit, #name #(,#sig_param_tys)*)
97    }
98}
99
100/// Returns the rustdoc string from the given item attributes.
101pub fn extract_docs(attrs: &[Attribute]) -> String {
102    attrs
103        .iter()
104        .filter_map(|attr| attr.extract_docs())
105        .collect::<Vec<_>>()
106        .join("\n")
107}