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 Attribute,
28 Type,
29 spanned::Spanned,
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>` doesn't implement `ink::SolEncode` nor `ink::SolDecode`,
45/// but instead implements `ink::sol::SolResultEncode` and `ink::sol::SolResultDecode`.
46pub fn sol_return_type(ty: &Type) -> TokenStream2 {
47 quote! {
48 <#ty as ::ink::sol::SolResultEncode>::SOL_NAME
49 }
50}
51
52/// Returns Solidity ABI compatible selector of an ink! message.
53pub fn selector(message: &Message) -> TokenStream2 {
54 let name = message.normalized_name();
55 let signature = call_signature(name, message.inputs());
56 quote! {
57 const {
58 ::ink::codegen::sol::selector_bytes(#signature)
59 }
60 }
61}
62
63/// Returns a `u32` representation of the Solidity ABI compatible selector of an ink!
64/// message.
65pub fn selector_id(message: &Message) -> TokenStream2 {
66 let selector_bytes = selector(message);
67 quote!(
68 {
69 const {
70 ::core::primitive::u32::from_be_bytes(#selector_bytes)
71 }
72 }
73 )
74}
75
76/// Returns the Solidity ABI call signature for the given message name and inputs.
77pub fn call_signature(name: String, inputs: InputsIter) -> TokenStream2 {
78 let mut input_types_len = 0;
79 let sig_param_tys: Vec<_> = inputs
80 .map(|input| {
81 let ty = &*input.ty;
82 let sol_ty = sol_type(ty);
83 let span = input.span();
84 input_types_len += 1;
85
86 quote_spanned!(span=>
87 #sol_ty
88 )
89 })
90 .collect();
91 let sig_arg_fmt_params = (0..input_types_len)
92 .map(|_| "{}")
93 .collect::<Vec<_>>()
94 .join(",");
95 let sig_fmt_lit = format!("{{}}({sig_arg_fmt_params})");
96 quote! {
97 ::ink::codegen::utils::const_format!(#sig_fmt_lit, #name #(,#sig_param_tys)*)
98 }
99}
100
101/// Returns the rustdoc string from the given item attributes.
102pub fn extract_docs(attrs: &[Attribute]) -> String {
103 attrs
104 .iter()
105 .filter_map(|attr| attr.extract_docs())
106 .collect::<Vec<_>>()
107 .join("\n")
108}