ink_codegen/generator/trait_def/
call_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 traits::GenerateCode,
30};
31
32impl TraitDefinition<'_> {
33 pub fn generate_call_builder(&self, abi: Option<Abi>) -> TokenStream2 {
43 CallBuilder::from((*self, abi)).generate_code()
44 }
45
46 pub fn call_builder_ident(&self) -> syn::Ident {
48 self.append_trait_suffix(CallBuilder::SUFFIX)
49 }
50}
51
52#[derive(From)]
54struct CallBuilder<'a> {
55 trait_def: TraitDefinition<'a>,
56 abi: Option<Abi>,
57}
58
59impl GenerateCode for CallBuilder<'_> {
60 fn generate_code(&self) -> TokenStream2 {
61 let struct_definition = self.generate_struct_definition();
62 let storage_layout_impl = self.generate_storage_layout_impl();
63 let auxiliary_trait_impls = self.generate_auxiliary_trait_impls();
64 let to_from_addr_impls = self.generate_to_from_addr_impls();
65 let message_builder_trait_impl = self.generate_message_builder_trait_impl();
66 let ink_trait_impl = self.generate_ink_trait_impl();
67 quote! {
68 #struct_definition
69 #storage_layout_impl
70 #auxiliary_trait_impls
71 #to_from_addr_impls
72 #message_builder_trait_impl
73 #ink_trait_impl
74 }
75 }
76}
77
78impl CallBuilder<'_> {
79 const SUFFIX: &'static str = "TraitCallBuilder";
81
82 fn span(&self) -> Span {
84 self.trait_def.span()
85 }
86
87 fn ident(&self) -> syn::Ident {
89 self.trait_def.call_builder_ident()
90 }
91
92 fn generate_struct_definition(&self) -> TokenStream2 {
105 let span = self.span();
106 let call_builder_ident = self.ident();
107 quote_spanned!(span =>
108 #[doc(hidden)]
112 #[allow(non_camel_case_types)]
113 #[::ink::scale_derive(Encode, Decode)]
114 #[repr(transparent)]
115 pub struct #call_builder_ident<E, Abi>
116 where
117 E: ::ink::env::Environment,
118 {
119 addr: ::ink::Address,
120 _marker: ::core::marker::PhantomData<fn() -> (E, Abi)>,
121 }
122 )
123 }
124
125 fn generate_storage_layout_impl(&self) -> TokenStream2 {
133 let span = self.span();
134 let call_builder_ident = self.ident();
135 quote_spanned!(span=>
136 #[cfg(feature = "std")]
137 impl<E, Abi> ::ink::storage::traits::StorageLayout
138 for #call_builder_ident<E, Abi>
139 where
140 E: ::ink::env::Environment,
141 ::ink::Address: ::ink::storage::traits::StorageLayout,
142 {
143 fn layout(
144 __key: &::ink::primitives::Key,
145 ) -> ::ink::metadata::layout::Layout {
146 ::ink::metadata::layout::Layout::Struct(
147 ::ink::metadata::layout::StructLayout::new(
148 ::core::stringify!(#call_builder_ident),
149 [
150 ::ink::metadata::layout::FieldLayout::new(
151 "addr",
152 <::ink::Address
153 as ::ink::storage::traits::StorageLayout>::layout(__key)
154 )
155 ]
156 )
157 )
158 }
159 }
160 )
161 }
162
163 fn generate_auxiliary_trait_impls(&self) -> TokenStream2 {
172 let span = self.span();
173 let call_builder_ident = self.ident();
174 let sol_codec = if matches!(self.abi, Some(Abi::Sol))
175 || cfg!(any(ink_abi = "sol", ink_abi = "all"))
176 {
177 quote_spanned!(span=>
180 impl<E, Abi> ::ink::SolDecode for #call_builder_ident<E, Abi>
181 where
182 E: ::ink::env::Environment,
183 {
184 type SolType = ::ink::Address;
185
186 fn from_sol_type(value: Self::SolType) -> ::core::result::Result<Self, ::ink::sol::Error> {
187 Ok(Self {
188 addr: value,
189 _marker: ::core::marker::PhantomData,
190 })
191 }
192 }
193
194 impl<'a, E, Abi> ::ink::SolEncode<'a> for #call_builder_ident<E, Abi>
195 where
196 E: ::ink::env::Environment,
197 {
198 type SolType = &'a ::ink::Address;
199
200 fn to_sol_type(&'a self) -> Self::SolType {
201 &self.addr
202 }
203 }
204 )
205 } else {
206 quote!()
207 };
208 quote_spanned!(span=>
209 impl<E, Abi> ::core::clone::Clone for #call_builder_ident<E, Abi>
211 where
212 E: ::ink::env::Environment,
213 ::ink::Address: ::core::clone::Clone,
214 {
215 #[inline]
216 fn clone(&self) -> Self {
217 Self {
218 addr: ::core::clone::Clone::clone(&self.addr),
219 _marker: self._marker,
220 }
221 }
222 }
223
224 impl<E, Abi> ::core::fmt::Debug for #call_builder_ident<E, Abi>
226 where
227 E: ::ink::env::Environment,
228 ::ink::Address: ::core::fmt::Debug,
229 {
230 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
231 f.debug_struct(::core::stringify!(#call_builder_ident))
232 .field("addr", &self.addr)
233 .finish()
234 }
235 }
236
237 #[cfg(feature = "std")]
238 impl<E, Abi> ::ink::scale_info::TypeInfo for #call_builder_ident<E, Abi>
241 where
242 E: ::ink::env::Environment,
243 ::ink::Address: ::ink::scale_info::TypeInfo + 'static,
244 {
245 type Identity = ::ink::Address;
246
247 fn type_info() -> ::ink::scale_info::Type {
248 <::ink::Address as ::ink::scale_info::TypeInfo>::type_info()
249 }
250 }
251
252 #sol_codec
253 )
254 }
255
256 fn generate_to_from_addr_impls(&self) -> TokenStream2 {
264 let span = self.span();
265 let call_builder_ident = self.ident();
266 quote_spanned!(span=>
267 impl<E, Abi> ::ink::env::call::FromAddr
268 for #call_builder_ident<E, Abi>
269 where
270 E: ::ink::env::Environment,
271 {
272 #[inline]
273 fn from_addr(addr: ::ink::Address) -> Self {
274 Self {
275 addr,
276 _marker: ::core::default::Default::default(),
277 }
278 }
279 }
280
281 impl<E, Abi> ::core::convert::From<::ink::Address> for #call_builder_ident<E, Abi>
282 where
283 E: ::ink::env::Environment,
284 ::ink::Address: ::ink::env::AccountIdGuard,
285 {
286 fn from(value: ::ink::Address) -> Self {
287 <Self as ::ink::env::call::FromAddr>::from_addr(value)
288 }
289 }
290
291 impl<E, Abi> ::ink::ToAddr for #call_builder_ident<E, Abi>
292 where
293 E: ::ink::env::Environment,
294 {
295 #[inline]
296 fn to_addr(&self) -> ::ink::Address {
297 <::ink::Address as ::core::clone::Clone>::clone(&self.addr)
298 }
299 }
300
301 impl<E, Abi> ::core::convert::AsRef<::ink::Address> for #call_builder_ident<E, Abi>
302 where
303 E: ::ink::env::Environment,
304 {
305 fn as_ref(&self) -> &::ink::Address {
306 &self.addr
307 }
308 }
309
310 impl<E, Abi> ::core::convert::AsMut<::ink::Address> for #call_builder_ident<E, Abi>
311 where
312 E: ::ink::env::Environment,
313 {
314 fn as_mut(&mut self) -> &mut ::ink::Address {
315 &mut self.addr
316 }
317 }
318
319 impl<E, Abi> ::ink::env::ContractEnv for #call_builder_ident<E, Abi>
320 where
321 E: ::ink::env::Environment,
322 {
323 type Env = E;
324 }
325 )
326 }
327
328 fn generate_message_builder_trait_impl(&self) -> TokenStream2 {
336 let span = self.trait_def.span();
337 let call_builder_ident = self.ident();
338 let message_builder_ident = self.trait_def.message_builder_ident();
339 quote_spanned!(span=>
340 impl<E, TypeAbi> ::ink::codegen::TraitMessageBuilder for #call_builder_ident<E, TypeAbi>
342 where
343 E: ::ink::env::Environment
344 {
345 type MessageBuilder<TraitAbi> = #message_builder_ident<E, TypeAbi>;
346 }
347 )
348 }
349
350 fn generate_ink_trait_impl(&self) -> TokenStream2 {
360 let span = self.trait_def.span();
361 let trait_ident = self.trait_def.trait_def.item().ident();
362 let trait_info_ident = self.trait_def.trait_info_ident();
363 let builder_ident = self.ident();
364 let generator = |abi: TokenStream2| {
365 let message_impls = self.generate_ink_trait_impl_messages(abi.clone());
366 quote_spanned!(span=>
367 impl<E> #trait_ident for #builder_ident<E, #abi>
368 where
369 E: ::ink::env::Environment,
370 {
371 #[allow(non_camel_case_types)]
372 type __ink_TraitInfo = #trait_info_ident<E>;
373
374 #message_impls
375 }
376 )
377 };
378 match self.abi {
379 None => generate_abi_impls!(@tokens generator),
380 Some(abi) => {
381 let abi_ty = match abi {
382 Abi::Ink => quote!(::ink::abi::Ink),
383 Abi::Sol => quote!(::ink::abi::Sol),
384 };
385 generator(abi_ty)
386 }
387 }
388 }
389
390 fn generate_ink_trait_impl_messages(&self, abi: TokenStream2) -> TokenStream2 {
393 let messages = self.trait_def.trait_def.item().iter_items().filter_map(
394 |(item, _selector)| {
395 item.filter_map_message().map(|message| {
396 self.generate_ink_trait_impl_for_message(&message, abi.clone())
397 })
398 },
399 );
400 quote! {
401 #( #messages )*
402 }
403 }
404
405 fn generate_ink_trait_impl_for_message(
408 &self,
409 message: &ir::InkTraitMessage,
410 abi: TokenStream2,
411 ) -> TokenStream2 {
412 let span = message.span();
413 let trait_ident = self.trait_def.trait_def.item().ident();
414 let message_ident = message.ident();
415 let attrs = self
416 .trait_def
417 .trait_def
418 .config()
419 .whitelisted_attributes()
420 .filter_attr(message.attrs());
421 let output_ident = generator::output_ident(message_ident);
422 let output = message.output();
423 let output_type =
424 output.map_or_else(|| quote! { () }, |output| quote! { #output });
425 let input_bindings = generator::input_bindings(message.inputs());
426 let input_types = generator::input_types(message.inputs());
427 let mut_tok = message.mutates().then(|| quote! { mut });
428 let arg_list =
429 generator::generate_argument_list(input_types.iter().cloned(), abi.clone());
430 let cfg_attrs = message.get_cfg_attrs(span);
431 quote_spanned!(span =>
432 #[allow(clippy::type_complexity)]
433 #( #cfg_attrs )*
434 type #output_ident = ::ink::env::call::CallBuilder<
435 Self::Env,
436 ::ink::env::call::utils::Set< ::ink::env::call::Call >,
437 ::ink::env::call::utils::Set< ::ink::env::call::ExecutionInput<#arg_list, #abi> >,
438 ::ink::env::call::utils::Set< ::ink::env::call::utils::ReturnType<#output_type> >,
439 >;
440
441 #( #attrs )*
442 #[inline]
443 fn #message_ident(
444 & #mut_tok self
445 #( , #input_bindings : #input_types )*
446 ) -> Self::#output_ident {
447 <::ink::env::call::CallBuilder<
448 Self::Env,
449 ::ink::env::call::utils::Unset< ::ink::env::call::Call >,
450 ::ink::env::call::utils::Set< ::ink::env::call::ExecutionInput<#arg_list, #abi> >,
451 ::ink::env::call::utils::Set< ::ink::env::call::utils::ReturnType<#output_type> >,
452 > as ::core::convert::From::<_>>::from(
453 <<Self as ::ink::codegen::TraitMessageBuilder>::MessageBuilder<#abi> as #trait_ident>
454 ::#message_ident(
455 & #mut_tok <<Self
456 as ::ink::codegen::TraitMessageBuilder>::MessageBuilder<#abi>
457 as ::core::default::Default>::default()
458 #(
459 , #input_bindings
460 )*
461 )
462 )
463 .call(::ink::ToAddr::to_addr(self))
464 }
465 )
466 }
467}