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>
113 where
114 E: ::ink::env::Environment,
115 {
116 addr: ::ink::H160,
117 marker: ::core::marker::PhantomData<fn() -> E>,
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> ::ink::storage::traits::StorageLayout
135 for #call_builder_ident<E>
136 where
137 E: ::ink::env::Environment,
138 ::ink::H160: ::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::H160
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 quote_spanned!(span=>
172 impl<E> ::core::clone::Clone for #call_builder_ident<E>
174 where
175 E: ::ink::env::Environment,
176 ::ink::H160: ::core::clone::Clone,
177 {
178 #[inline]
179 fn clone(&self) -> Self {
180 Self {
181 addr: ::core::clone::Clone::clone(&self.addr),
182 marker: self.marker,
183 }
184 }
185 }
186
187 impl<E> ::core::fmt::Debug for #call_builder_ident<E>
189 where
190 E: ::ink::env::Environment,
191 ::ink::H160: ::core::fmt::Debug,
192 {
193 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
194 f.debug_struct(::core::stringify!(#call_builder_ident))
195 .field("addr", &self.addr)
196 .finish()
197 }
198 }
199
200 #[cfg(feature = "std")]
201 impl<E> ::ink::scale_info::TypeInfo for #call_builder_ident<E>
204 where
205 E: ::ink::env::Environment,
206 ::ink::H160: ::ink::scale_info::TypeInfo + 'static,
207 {
208 type Identity = ::ink::H160;
209
210 fn type_info() -> ::ink::scale_info::Type {
211 <::ink::H160 as ::ink::scale_info::TypeInfo>::type_info()
212 }
213 }
214 )
215 }
216
217 fn generate_to_from_addr_impls(&self) -> TokenStream2 {
225 let span = self.span();
226 let call_builder_ident = self.ident();
227 quote_spanned!(span=>
228 impl<E> ::ink::env::call::FromAddr
229 for #call_builder_ident<E>
230 where
231 E: ::ink::env::Environment,
232 {
233 #[inline]
234 fn from_addr(addr: ::ink::H160) -> Self {
235 Self {
236 addr,
237 marker: ::core::default::Default::default(),
238 }
239 }
240 }
241
242 impl<E> ::core::convert::From<::ink::H160> for #call_builder_ident<E>
243 where
244 E: ::ink::env::Environment,
245 ::ink::H160: ::ink::env::AccountIdGuard,
246 {
247 fn from(value: ::ink::H160) -> Self {
248 <Self as ::ink::env::call::FromAddr>::from_addr(value)
249 }
250 }
251
252 impl<E> ::ink::ToAddr for #call_builder_ident<E>
253 where
254 E: ::ink::env::Environment,
255 {
256 #[inline]
257 fn to_addr(&self) -> ::ink::H160 {
258 <::ink::H160 as ::core::clone::Clone>::clone(&self.addr)
259 }
260 }
261
262 impl<E> ::core::convert::AsRef<::ink::H160> for #call_builder_ident<E>
263 where
264 E: ::ink::env::Environment,
265 {
266 fn as_ref(&self) -> &::ink::H160 {
267 &self.addr
268 }
269 }
270
271 impl<E> ::core::convert::AsMut<::ink::H160> for #call_builder_ident<E>
272 where
273 E: ::ink::env::Environment,
274 {
275 fn as_mut(&mut self) -> &mut ::ink::H160 {
276 &mut self.addr
277 }
278 }
279 )
280 }
281
282 fn generate_message_builder_trait_impl(&self) -> TokenStream2 {
290 let span = self.trait_def.span();
291 let call_builder_ident = self.ident();
292 let message_builder_ident = self.trait_def.message_builder_ident();
293 quote_spanned!(span=>
294 impl<E> ::ink::codegen::TraitMessageBuilder for #call_builder_ident<E>
296 where
297 E: ::ink::env::Environment
298 {
299 type MessageBuilder = #message_builder_ident<E>;
300 }
301 )
302 }
303
304 fn generate_ink_trait_impl(&self) -> TokenStream2 {
314 let span = self.trait_def.span();
315 let trait_ident = self.trait_def.trait_def.item().ident();
316 let trait_info_ident = self.trait_def.trait_info_ident();
317 let builder_ident = self.ident();
318 let message_impls = self.generate_ink_trait_impl_messages();
319 quote_spanned!(span=>
320 impl<E> ::ink::env::ContractEnv for #builder_ident<E>
321 where
322 E: ::ink::env::Environment,
323 {
324 type Env = E;
325 }
326
327 impl<E> #trait_ident for #builder_ident<E>
328 where
329 E: ::ink::env::Environment,
330 {
331 #[allow(non_camel_case_types)]
332 type __ink_TraitInfo = #trait_info_ident<E>;
333
334 #message_impls
335 }
336 )
337 }
338
339 fn generate_ink_trait_impl_messages(&self) -> TokenStream2 {
342 let messages = self.trait_def.trait_def.item().iter_items().filter_map(
343 |(item, _selector)| {
344 item.filter_map_message()
345 .map(|message| self.generate_ink_trait_impl_for_message(&message))
346 },
347 );
348 quote! {
349 #( #messages )*
350 }
351 }
352
353 fn generate_ink_trait_impl_for_message(
356 &self,
357 message: &ir::InkTraitMessage,
358 ) -> TokenStream2 {
359 let span = message.span();
360 let trait_ident = self.trait_def.trait_def.item().ident();
361 let message_ident = message.ident();
362 let attrs = self
363 .trait_def
364 .trait_def
365 .config()
366 .whitelisted_attributes()
367 .filter_attr(message.attrs());
368 let output_ident = generator::output_ident(message_ident);
369 let output = message.output();
370 let output_type =
371 output.map_or_else(|| quote! { () }, |output| quote! { #output });
372 let input_bindings = generator::input_bindings(message.inputs());
373 let input_types = generator::input_types(message.inputs());
374 let encoding_strategy = quote!(::ink::reflect::ScaleEncoding);
377 let arg_list = generator::generate_argument_list(
378 input_types.iter().cloned(),
379 encoding_strategy.clone(),
380 );
381 let mut_tok = message.mutates().then(|| quote! { mut });
382 let cfg_attrs = message.get_cfg_attrs(span);
383 quote_spanned!(span =>
384 #[allow(clippy::type_complexity)]
385 #( #cfg_attrs )*
386 type #output_ident = ::ink::env::call::CallBuilder<
387 Self::Env,
388 ::ink::env::call::utils::Set< ::ink::env::call::Call >,
389 ::ink::env::call::utils::Set< ::ink::env::call::ExecutionInput<#arg_list, #encoding_strategy> >,
390 ::ink::env::call::utils::Set< ::ink::env::call::utils::ReturnType<#output_type> >,
391 >;
392
393 #( #attrs )*
394 #[inline]
395 fn #message_ident(
396 & #mut_tok self
397 #( , #input_bindings : #input_types )*
398 ) -> Self::#output_ident {
399 <::ink::env::call::CallBuilder<
400 Self::Env,
401 ::ink::env::call::utils::Unset< ::ink::env::call::Call >,
402 ::ink::env::call::utils::Set< ::ink::env::call::ExecutionInput<#arg_list, #encoding_strategy> >,
403 ::ink::env::call::utils::Set< ::ink::env::call::utils::ReturnType<#output_type> >,
404 > as ::core::convert::From::<_>>::from(
405 <<Self as ::ink::codegen::TraitMessageBuilder>::MessageBuilder as #trait_ident>
406 ::#message_ident(
407 & #mut_tok <<Self
408 as ::ink::codegen::TraitMessageBuilder>::MessageBuilder
409 as ::core::default::Default>::default()
410 #(
411 , #input_bindings
412 )*
413 )
414 )
415 .call(::ink::ToAddr::to_addr(self))
416 }
417 )
418 }
419}