ink_codegen/generator/trait_def/
call_forwarder.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_forwarder(&self, abi: Option<Abi>) -> TokenStream2 {
44 CallForwarder::from((*self, abi)).generate_code()
45 }
46
47 pub fn call_forwarder_ident(&self) -> syn::Ident {
49 self.append_trait_suffix(CallForwarder::SUFFIX)
50 }
51}
52
53#[derive(From)]
55struct CallForwarder<'a> {
56 trait_def: TraitDefinition<'a>,
57 abi: Option<Abi>,
58}
59
60impl GenerateCode for CallForwarder<'_> {
61 fn generate_code(&self) -> TokenStream2 {
62 let struct_definition = self.generate_struct_definition();
63 let storage_layout_impl = self.generate_storage_layout_impl();
64 let auxiliary_trait_impls = self.generate_auxiliary_trait_impls();
65 let to_from_addr_impls = self.generate_to_from_addr_impls();
66 let call_builder_impl = self.generate_call_builder_trait_impl();
67 let ink_trait_impl = self.generate_ink_trait_impl();
68 quote! {
69 #struct_definition
70 #storage_layout_impl
71 #auxiliary_trait_impls
72 #to_from_addr_impls
73 #call_builder_impl
74 #ink_trait_impl
75 }
76 }
77}
78
79impl CallForwarder<'_> {
80 const SUFFIX: &'static str = "TraitCallForwarder";
82
83 fn span(&self) -> Span {
85 self.trait_def.span()
86 }
87
88 fn ident(&self) -> syn::Ident {
90 self.trait_def.call_forwarder_ident()
91 }
92
93 fn generate_struct_definition(&self) -> TokenStream2 {
106 let span = self.span();
107 let call_forwarder_ident = self.ident();
108 quote_spanned!(span =>
109 #[doc(hidden)]
114 #[allow(non_camel_case_types)]
115 #[::ink::scale_derive(Encode, Decode)]
116 #[repr(transparent)]
117 pub struct #call_forwarder_ident<E, Abi>
118 where
119 E: ::ink::env::Environment,
120 {
121 builder: <Self as ::ink::codegen::TraitCallBuilder>::Builder,
122 _marker: ::core::marker::PhantomData<fn() -> Abi>,
123 }
124 )
125 }
126
127 fn generate_storage_layout_impl(&self) -> TokenStream2 {
135 let span = self.span();
136 let call_forwarder_ident = self.ident();
137 quote_spanned!(span=>
138 #[cfg(feature = "std")]
139 impl<E, Abi> ::ink::storage::traits::StorageLayout
140 for #call_forwarder_ident<E, Abi>
141 where
142 E: ::ink::env::Environment,
143 ::ink::Address: ::ink::storage::traits::StorageLayout,
144 {
145 fn layout(
146 __key: &::ink::primitives::Key,
147 ) -> ::ink::metadata::layout::Layout {
148 <<Self as ::ink::codegen::TraitCallBuilder>::Builder
149 as ::ink::storage::traits::StorageLayout>::layout(__key)
150 }
151 }
152 )
153 }
154
155 fn generate_auxiliary_trait_impls(&self) -> TokenStream2 {
164 let span = self.span();
165 let call_forwarder_ident = self.ident();
166 let sol_codec = if cfg!(any(ink_abi = "sol", ink_abi = "all")) {
167 quote_spanned!(span=>
170 impl<E, Abi> ::ink::SolDecode for #call_forwarder_ident<E, Abi>
171 where
172 E: ::ink::env::Environment,
173 {
174 type SolType = ::ink::Address;
175
176 fn from_sol_type(value: Self::SolType) -> ::core::result::Result<Self, ::ink::sol::Error> {
177 Ok(Self {
178 builder: <<Self as ::ink::codegen::TraitCallBuilder>::Builder
179 as ::ink::env::call::FromAddr>::from_addr(value),
180 _marker: ::core::marker::PhantomData,
181 })
182 }
183 }
184
185 impl<'a, E, Abi> ::ink::SolEncode<'a> for #call_forwarder_ident<E, Abi>
186 where
187 E: ::ink::env::Environment,
188 {
189 type SolType = &'a ::ink::Address;
190
191 fn to_sol_type(&'a self) -> Self::SolType {
192 self.as_ref()
193 }
194 }
195 )
196 } else {
197 quote!()
198 };
199 quote_spanned!(span=>
200 impl<E, Abi> ::core::clone::Clone for #call_forwarder_ident<E, Abi>
202 where
203 E: ::ink::env::Environment,
204 ::ink::Address: ::core::clone::Clone,
205 {
206 #[inline]
207 fn clone(&self) -> Self {
208 Self {
209 builder: <<Self as ::ink::codegen::TraitCallBuilder>::Builder
210 as ::core::clone::Clone>::clone(&self.builder),
211 _marker: self._marker,
212 }
213 }
214 }
215
216 impl<E, Abi> ::core::fmt::Debug for #call_forwarder_ident<E, Abi>
218 where
219 E: ::ink::env::Environment,
220 ::ink::Address: ::core::fmt::Debug,
221 {
222 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
223 f.debug_struct(::core::stringify!(#call_forwarder_ident))
224 .field("addr", &self.builder.addr)
225 .finish()
226 }
227 }
228
229 #[cfg(feature = "std")]
230 impl<E, Abi> ::ink::scale_info::TypeInfo for #call_forwarder_ident<E, Abi>
232 where
233 E: ::ink::env::Environment,
234 ::ink::Address: ::ink::scale_info::TypeInfo + 'static,
235 {
236 type Identity = <
237 <Self as ::ink::codegen::TraitCallBuilder>::Builder as ::ink::scale_info::TypeInfo
238 >::Identity;
239
240 fn type_info() -> ::ink::scale_info::Type {
241 <
242 <Self as ::ink::codegen::TraitCallBuilder>::Builder as ::ink::scale_info::TypeInfo
243 >::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_forwarder_ident = self.ident();
261 quote_spanned!(span=>
262 impl<E, Abi> ::ink::env::call::FromAddr
263 for #call_forwarder_ident<E, Abi>
264 where
265 E: ::ink::env::Environment,
266 {
267 #[inline]
268 fn from_addr(addr: ::ink::Address) -> Self {
269 Self {
270 builder: <<Self as ::ink::codegen::TraitCallBuilder>::Builder
271 as ::ink::env::call::FromAddr>::from_addr(addr),
272 _marker: ::core::default::Default::default(),
273 }
274 }
275 }
276
277 impl<E, Abi> ::core::convert::From<::ink::Address> for #call_forwarder_ident<E, Abi>
278 where
279 E: ::ink::env::Environment,
280 {
281 fn from(addr: ::ink::Address) -> Self {
282 <Self as ::ink::env::call::FromAddr>::from_addr(addr)
283 }
284 }
285
286 impl<E, Abi> ::ink::ToAddr for #call_forwarder_ident<E, Abi>
287 where
288 E: ::ink::env::Environment,
289 {
290 #[inline]
291 fn to_addr(&self) -> ::ink::Address {
292 <<Self as ::ink::codegen::TraitCallBuilder>::Builder
293 as ::ink::ToAddr>::to_addr(&self.builder)
294 }
295 }
296
297 impl<E, Abi> ::core::convert::AsRef<::ink::Address> for #call_forwarder_ident<E, Abi>
298 where
299 E: ::ink::env::Environment,
300 {
301 fn as_ref(&self) -> &::ink::Address {
302 <_ as ::core::convert::AsRef<::ink::Address>>::as_ref(&self.builder)
303 }
304 }
305
306 impl<E, Abi> ::core::convert::AsMut<::ink::Address> for #call_forwarder_ident<E, Abi>
307 where
308 E: ::ink::env::Environment,
309 {
310 fn as_mut(&mut self) -> &mut ::ink::Address {
311 <_ as ::core::convert::AsMut<::ink::Address>>::as_mut(&mut self.builder)
312 }
313 }
314
315 impl<E, Abi> ::ink::env::ContractEnv for #call_forwarder_ident<E, Abi>
316 where
317 E: ::ink::env::Environment,
318 {
319 type Env = E;
320 }
321 )
322 }
323
324 fn generate_call_builder_trait_impl(&self) -> TokenStream2 {
332 let span = self.trait_def.span();
333 let call_forwarder_ident = self.ident();
334 let call_builder_ident = self.trait_def.call_builder_ident();
335 quote_spanned!(span=>
336 impl<E, Abi> ::ink::codegen::TraitCallBuilder for #call_forwarder_ident<E, Abi>
342 where
343 E: ::ink::env::Environment,
344 {
345 type Builder = #call_builder_ident<E, Abi>;
346
347 #[inline]
348 fn call(&self) -> &<Self as ::ink::codegen::TraitCallBuilder>::Builder {
349 &self.builder
350 }
351
352 #[inline]
353 fn call_mut(&mut self) -> &mut <Self as ::ink::codegen::TraitCallBuilder>::Builder {
354 &mut self.builder
355 }
356 }
357 )
358 }
359
360 fn generate_ink_trait_impl(&self) -> TokenStream2 {
367 let span = self.trait_def.span();
368 let trait_ident = self.trait_def.trait_def.item().ident();
369 let trait_info_ident = self.trait_def.trait_info_ident();
370 let forwarder_ident = self.ident();
371 let message_impls = self.generate_ink_trait_impl_messages();
372 let generator = |abi| {
373 quote_spanned!(span=>
374 impl<E> #trait_ident for #forwarder_ident<E, #abi>
375 where
376 E: ::ink::env::Environment,
377 {
378 #[allow(non_camel_case_types)]
379 type __ink_TraitInfo = #trait_info_ident<E>;
380
381 #message_impls
382 }
383 )
384 };
385 match self.abi {
386 None => generate_abi_impls!(@tokens generator),
387 Some(abi) => {
388 let abi_ty = match abi {
389 Abi::Ink => quote!(::ink::abi::Ink),
390 Abi::Sol => quote!(::ink::abi::Sol),
391 };
392 generator(abi_ty)
393 }
394 }
395 }
396
397 fn generate_ink_trait_impl_messages(&self) -> TokenStream2 {
400 let messages =
401 self.trait_def
402 .trait_def
403 .item()
404 .iter_items()
405 .filter_map(|(item, _)| {
406 item.filter_map_message()
407 .map(|message| self.generate_ink_trait_impl_for_message(&message))
408 });
409 quote! {
410 #( #messages )*
411 }
412 }
413
414 fn generate_ink_trait_impl_for_message(
417 &self,
418 message: &ir::InkTraitMessage,
419 ) -> TokenStream2 {
420 let span = message.span();
421 let trait_ident = self.trait_def.trait_def.item().ident();
422 let forwarder_ident = self.ident();
423 let message_ident = message.ident();
424 let attrs = self
425 .trait_def
426 .trait_def
427 .config()
428 .whitelisted_attributes()
429 .filter_attr(message.attrs());
430 let output_ident = generator::output_ident(message_ident);
431 let output_type = message
432 .output()
433 .cloned()
434 .unwrap_or_else(|| syn::parse_quote!(()));
435 let input_bindings = message.inputs().map(|input| &input.pat).collect::<Vec<_>>();
436 let input_types = message.inputs().map(|input| &input.ty).collect::<Vec<_>>();
437 let call_op = match message.receiver() {
438 ir::Receiver::Ref => quote! { call },
439 ir::Receiver::RefMut => quote! { call_mut },
440 };
441 let mut_tok = message.mutates().then(|| quote! { mut });
442 let panic_str = format!(
443 "encountered error while calling <{forwarder_ident} as {trait_ident}>::{message_ident}",
444 );
445 let cfg_attrs = message.get_cfg_attrs(span);
446 quote_spanned!(span =>
447 #( #cfg_attrs )*
448 type #output_ident = #output_type;
449
450 #( #attrs )*
451 #[inline]
452 fn #message_ident(
453 & #mut_tok self
454 #( , #input_bindings : #input_types )*
455 ) -> Self::#output_ident {
456 <<Self as ::ink::codegen::TraitCallBuilder>::Builder as #trait_ident>::#message_ident(
457 <Self as ::ink::codegen::TraitCallBuilder>::#call_op(self)
458 #(
459 , #input_bindings
460 )*
461 )
462 .try_invoke()
463 .unwrap_or_else(|env_err| ::core::panic!("{}: {:?}", #panic_str, env_err))
464 .unwrap_or_else(|lang_err| ::core::panic!("{}: {:?}", #panic_str, lang_err))
465 }
466 )
467 }
468}