ink_codegen/generator/trait_def/
message_builder.rs1use derive_more::From;
16use ink_primitives::abi::Abi;
17use proc_macro2::{
18 Span,
19 TokenStream as TokenStream2,
20};
21use quote::{
22 quote,
23 quote_spanned,
24};
25
26use super::TraitDefinition;
27use crate::{
28 generator,
29 generator::sol,
30 traits::GenerateCode,
31};
32
33impl TraitDefinition<'_> {
34 pub fn generate_message_builder(&self, abi: Option<Abi>) -> TokenStream2 {
44 MessageBuilder::from((*self, abi)).generate_code()
45 }
46
47 pub fn message_builder_ident(&self) -> syn::Ident {
49 self.append_trait_suffix(MessageBuilder::SUFFIX)
50 }
51}
52
53#[derive(From)]
55struct MessageBuilder<'a> {
56 trait_def: TraitDefinition<'a>,
57 abi: Option<Abi>,
58}
59
60impl GenerateCode for MessageBuilder<'_> {
61 fn generate_code(&self) -> TokenStream2 {
62 let struct_definition = self.generate_struct_definition();
63 let auxiliary_trait_impls = self.generate_auxiliary_trait_impls();
64 let ink_trait_impl = self.generate_ink_trait_impl();
65 quote! {
66 #struct_definition
67 #auxiliary_trait_impls
68 #ink_trait_impl
69 }
70 }
71}
72
73impl MessageBuilder<'_> {
74 const SUFFIX: &'static str = "TraitMessageBuilder";
76
77 fn span(&self) -> Span {
79 self.trait_def.span()
80 }
81
82 fn generate_struct_definition(&self) -> TokenStream2 {
88 let span = self.span();
89 let message_builder_ident = self.trait_def.message_builder_ident();
90 quote_spanned!(span =>
91 #[doc(hidden)]
95 #[allow(non_camel_case_types)]
96 #[::ink::scale_derive(Encode, Decode, TypeInfo)]
97 pub struct #message_builder_ident<E, Abi> {
98 _marker: ::core::marker::PhantomData<fn() -> (E, Abi)>,
99 }
100 )
101 }
102
103 fn generate_auxiliary_trait_impls(&self) -> TokenStream2 {
111 let span = self.span();
112 let message_builder_ident = self.trait_def.message_builder_ident();
113 let sol_codec = if matches!(self.abi, Some(Abi::Sol))
114 || cfg!(any(ink_abi = "sol", ink_abi = "all"))
115 {
116 quote_spanned!(span=>
119 impl<E, Abi> ::ink::SolDecode for #message_builder_ident<E, Abi>
120 where
121 E: ::ink::env::Environment,
122 {
123 type SolType = ();
124
125 fn from_sol_type(_: Self::SolType) -> ::core::result::Result<Self, ::ink::sol::Error> {
126 Ok(Self {
127 _marker: ::core::marker::PhantomData,
128 })
129 }
130 }
131
132 impl<'a, E, Abi> ::ink::SolEncode<'a> for #message_builder_ident<E, Abi>
133 where
134 E: ::ink::env::Environment,
135 {
136 type SolType = ();
137
138 fn to_sol_type(&'a self) {}
139 }
140 )
141 } else {
142 quote!()
143 };
144 quote_spanned!(span=>
145 impl<E, Abi> ::core::default::Default for #message_builder_ident<E, Abi>
146 where
147 E: ::ink::env::Environment,
148 {
149 fn default() -> Self {
150 Self {
151 _marker: ::core::default::Default::default()
152 }
153 }
154 }
155
156 impl<E, Abi> ::ink::env::ContractEnv for #message_builder_ident<E, Abi>
157 where
158 E: ::ink::env::Environment,
159 {
160 type Env = E;
161 }
162
163 #sol_codec
164 )
165 }
166
167 fn generate_ink_trait_impl(&self) -> TokenStream2 {
175 let span = self.trait_def.span();
176 let trait_ident = self.trait_def.trait_def.item().ident();
177 let trait_info_ident = self.trait_def.trait_info_ident();
178 let message_builder_ident = self.trait_def.message_builder_ident();
179 let generator = |abi| {
180 let abi_ty = match abi {
181 Abi::Ink => quote!(::ink::abi::Ink),
182 Abi::Sol => quote!(::ink::abi::Sol),
183 };
184 let message_impls = self.generate_ink_trait_impl_messages(abi);
185 quote_spanned!(span=>
186 impl<E> #trait_ident for #message_builder_ident<E, #abi_ty>
187 where
188 E: ::ink::env::Environment,
189 {
190 #[allow(non_camel_case_types)]
191 type __ink_TraitInfo = #trait_info_ident<E>;
192
193 #message_impls
194 }
195 )
196 };
197 match self.abi {
198 None => generate_abi_impls!(@type generator),
199 Some(abi) => generator(abi),
200 }
201 }
202
203 fn generate_ink_trait_impl_messages(&self, abi: Abi) -> TokenStream2 {
206 let messages = self.trait_def.trait_def.item().iter_items().filter_map(
207 |(item, selector)| {
208 item.filter_map_message().map(|message| {
209 let (selector_bytes, abi_ty) = match abi {
210 Abi::Ink => {
211 let selector_bytes = selector.hex_lits();
212 (quote!([ #( #selector_bytes ),* ]), quote!(::ink::abi::Ink))
213 }
214 Abi::Sol => {
215 let name = message.normalized_name();
216 let signature =
217 sol::utils::call_signature(name, message.inputs());
218 (
219 quote!(::ink::codegen::sol::selector_bytes(#signature)),
220 quote!(::ink::abi::Sol),
221 )
222 }
223 };
224 self.generate_ink_trait_impl_for_message(
225 &message,
226 selector_bytes,
227 abi_ty,
228 )
229 })
230 },
231 );
232 quote! {
233 #( #messages )*
234 }
235 }
236
237 fn generate_ink_trait_impl_for_message(
240 &self,
241 message: &ir::InkTraitMessage,
242 selector_bytes: TokenStream2,
243 abi: TokenStream2,
244 ) -> TokenStream2 {
245 let span = message.span();
246 let message_ident = message.ident();
247 let attrs = self
248 .trait_def
249 .trait_def
250 .config()
251 .whitelisted_attributes()
252 .filter_attr(message.attrs());
253 let output_ident = generator::output_ident(message_ident);
254 let output = message.output();
255 let output_type =
256 output.map_or_else(|| quote! { () }, |output| quote! { #output });
257 let input_bindings = generator::input_bindings(message.inputs());
258 let input_types = generator::input_types(message.inputs());
259 let mut_tok = message.mutates().then(|| quote! { mut });
260 let arg_list =
261 generator::generate_argument_list(input_types.iter().cloned(), abi.clone());
262 let cfg_attrs = message.get_cfg_attrs(span);
263 quote_spanned!(span =>
264 #( #cfg_attrs )*
265 type #output_ident = ::ink::env::call::Execution<
266 #arg_list,
267 #output_type,
268 #abi
269 >;
270
271 #( #attrs )*
272 #[inline]
273 fn #message_ident(
274 & #mut_tok self
275 #( , #input_bindings : #input_types )*
276 ) -> Self::#output_ident {
277 ::ink::env::call::Execution::new(
278 ::ink::env::call::ExecutionInput::new(
279 ::ink::env::call::Selector::new(#selector_bytes)
280 )
281 #(
282 .push_arg(#input_bindings)
283 )*
284 )
285 }
286 )
287 }
288}