ink_codegen/generator/trait_def/
call_builder.rs1use super::TraitDefinition;
16use crate::{
17 generator,
18 traits::GenerateCode,
19};
20use derive_more::From;
21use proc_macro2::{
22 Span,
23 TokenStream as TokenStream2,
24};
25use quote::{
26 quote,
27 quote_spanned,
28};
29
30impl TraitDefinition<'_> {
31 pub fn generate_call_builder(&self) -> TokenStream2 {
41 CallBuilder::from(*self).generate_code()
42 }
43
44 pub fn call_builder_ident(&self) -> syn::Ident {
46 self.append_trait_suffix(CallBuilder::SUFFIX)
47 }
48}
49
50#[derive(From)]
52struct CallBuilder<'a> {
53 trait_def: TraitDefinition<'a>,
54}
55
56impl GenerateCode for CallBuilder<'_> {
57 fn generate_code(&self) -> TokenStream2 {
58 let struct_definition = self.generate_struct_definition();
59 let storage_layout_impl = self.generate_storage_layout_impl();
60 let auxiliary_trait_impls = self.generate_auxiliary_trait_impls();
61 let to_from_addr_impls = self.generate_to_from_addr_impls();
62 let message_builder_trait_impl = self.generate_message_builder_trait_impl();
63 let ink_trait_impl = self.generate_ink_trait_impl();
64 quote! {
65 #struct_definition
66 #storage_layout_impl
67 #auxiliary_trait_impls
68 #to_from_addr_impls
69 #message_builder_trait_impl
70 #ink_trait_impl
71 }
72 }
73}
74
75impl CallBuilder<'_> {
76 const SUFFIX: &'static str = "TraitCallBuilder";
78
79 fn span(&self) -> Span {
81 self.trait_def.span()
82 }
83
84 fn ident(&self) -> syn::Ident {
86 self.trait_def.call_builder_ident()
87 }
88
89 fn generate_struct_definition(&self) -> TokenStream2 {
102 let span = self.span();
103 let call_builder_ident = self.ident();
104 quote_spanned!(span =>
105 #[doc(hidden)]
109 #[allow(non_camel_case_types)]
110 #[::ink::scale_derive(Encode, Decode)]
111 #[repr(transparent)]
112 pub struct #call_builder_ident<E, Abi>
113 where
114 E: ::ink::env::Environment,
115 {
116 addr: ::ink::Address,
117 _marker: ::core::marker::PhantomData<fn() -> (E, Abi)>,
118 }
119 )
120 }
121
122 fn generate_storage_layout_impl(&self) -> TokenStream2 {
130 let span = self.span();
131 let call_builder_ident = self.ident();
132 quote_spanned!(span=>
133 #[cfg(feature = "std")]
134 impl<E, Abi> ::ink::storage::traits::StorageLayout
135 for #call_builder_ident<E, Abi>
136 where
137 E: ::ink::env::Environment,
138 ::ink::Address: ::ink::storage::traits::StorageLayout,
139 {
140 fn layout(
141 __key: &::ink::primitives::Key,
142 ) -> ::ink::metadata::layout::Layout {
143 ::ink::metadata::layout::Layout::Struct(
144 ::ink::metadata::layout::StructLayout::new(
145 ::core::stringify!(#call_builder_ident),
146 [
147 ::ink::metadata::layout::FieldLayout::new(
148 "addr",
149 <::ink::Address
150 as ::ink::storage::traits::StorageLayout>::layout(__key)
151 )
152 ]
153 )
154 )
155 }
156 }
157 )
158 }
159
160 fn generate_auxiliary_trait_impls(&self) -> TokenStream2 {
169 let span = self.span();
170 let call_builder_ident = self.ident();
171 let sol_codec = if cfg!(any(ink_abi = "sol", ink_abi = "all")) {
172 quote_spanned!(span=>
175 impl<E, Abi> ::ink::SolDecode for #call_builder_ident<E, Abi>
176 where
177 E: ::ink::env::Environment,
178 {
179 type SolType = ::ink::Address;
180
181 fn from_sol_type(value: Self::SolType) -> ::core::result::Result<Self, ::ink::sol::Error> {
182 Ok(Self {
183 addr: value,
184 _marker: ::core::marker::PhantomData,
185 })
186 }
187 }
188
189 impl<'a, E, Abi> ::ink::SolEncode<'a> for #call_builder_ident<E, Abi>
190 where
191 E: ::ink::env::Environment,
192 {
193 type SolType = &'a ::ink::Address;
194
195 fn to_sol_type(&'a self) -> Self::SolType {
196 &self.addr
197 }
198 }
199 )
200 } else {
201 quote!()
202 };
203 quote_spanned!(span=>
204 impl<E, Abi> ::core::clone::Clone for #call_builder_ident<E, Abi>
206 where
207 E: ::ink::env::Environment,
208 ::ink::Address: ::core::clone::Clone,
209 {
210 #[inline]
211 fn clone(&self) -> Self {
212 Self {
213 addr: ::core::clone::Clone::clone(&self.addr),
214 _marker: self._marker,
215 }
216 }
217 }
218
219 impl<E, Abi> ::core::fmt::Debug for #call_builder_ident<E, Abi>
221 where
222 E: ::ink::env::Environment,
223 ::ink::Address: ::core::fmt::Debug,
224 {
225 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
226 f.debug_struct(::core::stringify!(#call_builder_ident))
227 .field("addr", &self.addr)
228 .finish()
229 }
230 }
231
232 #[cfg(feature = "std")]
233 impl<E, Abi> ::ink::scale_info::TypeInfo for #call_builder_ident<E, Abi>
236 where
237 E: ::ink::env::Environment,
238 ::ink::Address: ::ink::scale_info::TypeInfo + 'static,
239 {
240 type Identity = ::ink::Address;
241
242 fn type_info() -> ::ink::scale_info::Type {
243 <::ink::Address as ::ink::scale_info::TypeInfo>::type_info()
244 }
245 }
246
247 #sol_codec
248 )
249 }
250
251 fn generate_to_from_addr_impls(&self) -> TokenStream2 {
259 let span = self.span();
260 let call_builder_ident = self.ident();
261 quote_spanned!(span=>
262 impl<E, Abi> ::ink::env::call::FromAddr
263 for #call_builder_ident<E, Abi>
264 where
265 E: ::ink::env::Environment,
266 {
267 #[inline]
268 fn from_addr(addr: ::ink::Address) -> Self {
269 Self {
270 addr,
271 _marker: ::core::default::Default::default(),
272 }
273 }
274 }
275
276 impl<E, Abi> ::core::convert::From<::ink::Address> for #call_builder_ident<E, Abi>
277 where
278 E: ::ink::env::Environment,
279 ::ink::Address: ::ink::env::AccountIdGuard,
280 {
281 fn from(value: ::ink::Address) -> Self {
282 <Self as ::ink::env::call::FromAddr>::from_addr(value)
283 }
284 }
285
286 impl<E, Abi> ::ink::ToAddr for #call_builder_ident<E, Abi>
287 where
288 E: ::ink::env::Environment,
289 {
290 #[inline]
291 fn to_addr(&self) -> ::ink::Address {
292 <::ink::Address as ::core::clone::Clone>::clone(&self.addr)
293 }
294 }
295
296 impl<E, Abi> ::core::convert::AsRef<::ink::Address> for #call_builder_ident<E, Abi>
297 where
298 E: ::ink::env::Environment,
299 {
300 fn as_ref(&self) -> &::ink::Address {
301 &self.addr
302 }
303 }
304
305 impl<E, Abi> ::core::convert::AsMut<::ink::Address> for #call_builder_ident<E, Abi>
306 where
307 E: ::ink::env::Environment,
308 {
309 fn as_mut(&mut self) -> &mut ::ink::Address {
310 &mut self.addr
311 }
312 }
313
314 impl<E, Abi> ::ink::env::ContractEnv for #call_builder_ident<E, Abi>
315 where
316 E: ::ink::env::Environment,
317 {
318 type Env = E;
319 }
320 )
321 }
322
323 fn generate_message_builder_trait_impl(&self) -> TokenStream2 {
331 let span = self.trait_def.span();
332 let call_builder_ident = self.ident();
333 let message_builder_ident = self.trait_def.message_builder_ident();
334 quote_spanned!(span=>
335 impl<E, TypeAbi> ::ink::codegen::TraitMessageBuilder for #call_builder_ident<E, TypeAbi>
337 where
338 E: ::ink::env::Environment
339 {
340 type MessageBuilder<TraitAbi> = #message_builder_ident<E, TypeAbi>;
341 }
342 )
343 }
344
345 fn generate_ink_trait_impl(&self) -> TokenStream2 {
355 let span = self.trait_def.span();
356 let trait_ident = self.trait_def.trait_def.item().ident();
357 let trait_info_ident = self.trait_def.trait_info_ident();
358 let builder_ident = self.ident();
359 generate_abi_impls!(@tokens |abi: TokenStream2| {
360 let message_impls = self.generate_ink_trait_impl_messages(abi.clone());
361 quote_spanned!(span=>
362 impl<E> #trait_ident for #builder_ident<E, #abi>
363 where
364 E: ::ink::env::Environment,
365 {
366 #[allow(non_camel_case_types)]
367 type __ink_TraitInfo = #trait_info_ident<E>;
368
369 #message_impls
370 }
371 )
372 })
373 }
374
375 fn generate_ink_trait_impl_messages(&self, abi: TokenStream2) -> TokenStream2 {
378 let messages = self.trait_def.trait_def.item().iter_items().filter_map(
379 |(item, _selector)| {
380 item.filter_map_message().map(|message| {
381 self.generate_ink_trait_impl_for_message(&message, abi.clone())
382 })
383 },
384 );
385 quote! {
386 #( #messages )*
387 }
388 }
389
390 fn generate_ink_trait_impl_for_message(
393 &self,
394 message: &ir::InkTraitMessage,
395 abi: TokenStream2,
396 ) -> TokenStream2 {
397 let span = message.span();
398 let trait_ident = self.trait_def.trait_def.item().ident();
399 let message_ident = message.ident();
400 let attrs = self
401 .trait_def
402 .trait_def
403 .config()
404 .whitelisted_attributes()
405 .filter_attr(message.attrs());
406 let output_ident = generator::output_ident(message_ident);
407 let output = message.output();
408 let output_type =
409 output.map_or_else(|| quote! { () }, |output| quote! { #output });
410 let input_bindings = generator::input_bindings(message.inputs());
411 let input_types = generator::input_types(message.inputs());
412 let mut_tok = message.mutates().then(|| quote! { mut });
413 let arg_list =
414 generator::generate_argument_list(input_types.iter().cloned(), abi.clone());
415 let cfg_attrs = message.get_cfg_attrs(span);
416 quote_spanned!(span =>
417 #[allow(clippy::type_complexity)]
418 #( #cfg_attrs )*
419 type #output_ident = ::ink::env::call::CallBuilder<
420 Self::Env,
421 ::ink::env::call::utils::Set< ::ink::env::call::Call >,
422 ::ink::env::call::utils::Set< ::ink::env::call::ExecutionInput<#arg_list, #abi> >,
423 ::ink::env::call::utils::Set< ::ink::env::call::utils::ReturnType<#output_type> >,
424 >;
425
426 #( #attrs )*
427 #[inline]
428 fn #message_ident(
429 & #mut_tok self
430 #( , #input_bindings : #input_types )*
431 ) -> Self::#output_ident {
432 <::ink::env::call::CallBuilder<
433 Self::Env,
434 ::ink::env::call::utils::Unset< ::ink::env::call::Call >,
435 ::ink::env::call::utils::Set< ::ink::env::call::ExecutionInput<#arg_list, #abi> >,
436 ::ink::env::call::utils::Set< ::ink::env::call::utils::ReturnType<#output_type> >,
437 > as ::core::convert::From::<_>>::from(
438 <<Self as ::ink::codegen::TraitMessageBuilder>::MessageBuilder<#abi> as #trait_ident>
439 ::#message_ident(
440 & #mut_tok <<Self
441 as ::ink::codegen::TraitMessageBuilder>::MessageBuilder<#abi>
442 as ::core::default::Default>::default()
443 #(
444 , #input_bindings
445 )*
446 )
447 )
448 .call(::ink::ToAddr::to_addr(self))
449 }
450 )
451 }
452}