ink_codegen/generator/trait_def/
call_forwarder.rs
1use 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_forwarder(&self) -> TokenStream2 {
42 CallForwarder::from(*self).generate_code()
43 }
44
45 pub fn call_forwarder_ident(&self) -> syn::Ident {
47 self.append_trait_suffix(CallForwarder::SUFFIX)
48 }
49}
50
51#[derive(From)]
53struct CallForwarder<'a> {
54 trait_def: TraitDefinition<'a>,
55}
56
57impl GenerateCode for CallForwarder<'_> {
58 fn generate_code(&self) -> TokenStream2 {
59 let struct_definition = self.generate_struct_definition();
60 let storage_layout_impl = self.generate_storage_layout_impl();
61 let auxiliary_trait_impls = self.generate_auxiliary_trait_impls();
62 let to_from_addr_impls = self.generate_to_from_addr_impls();
63 let call_builder_impl = self.generate_call_builder_trait_impl();
64 let ink_trait_impl = self.generate_ink_trait_impl();
65 quote! {
66 #struct_definition
67 #storage_layout_impl
68 #auxiliary_trait_impls
69 #to_from_addr_impls
70 #call_builder_impl
71 #ink_trait_impl
72 }
73 }
74}
75
76impl CallForwarder<'_> {
77 const SUFFIX: &'static str = "TraitCallForwarder";
79
80 fn span(&self) -> Span {
82 self.trait_def.span()
83 }
84
85 fn ident(&self) -> syn::Ident {
87 self.trait_def.call_forwarder_ident()
88 }
89
90 fn generate_struct_definition(&self) -> TokenStream2 {
103 let span = self.span();
104 let call_forwarder_ident = self.ident();
105 quote_spanned!(span =>
106 #[doc(hidden)]
111 #[allow(non_camel_case_types)]
112 #[::ink::scale_derive(Encode, Decode)]
113 #[repr(transparent)]
114 pub struct #call_forwarder_ident<E>
115 where
116 E: ::ink::env::Environment,
117 {
118 builder: <Self as ::ink::codegen::TraitCallBuilder>::Builder,
119 }
120 )
121 }
122
123 fn generate_storage_layout_impl(&self) -> TokenStream2 {
131 let span = self.span();
132 let call_forwarder_ident = self.ident();
133 quote_spanned!(span=>
134 #[cfg(feature = "std")]
135 impl<E> ::ink::storage::traits::StorageLayout
136 for #call_forwarder_ident<E>
137 where
138 E: ::ink::env::Environment,
139 ::ink::H160: ::ink::storage::traits::StorageLayout,
140 {
141 fn layout(
142 __key: &::ink::primitives::Key,
143 ) -> ::ink::metadata::layout::Layout {
144 <<Self as ::ink::codegen::TraitCallBuilder>::Builder
145 as ::ink::storage::traits::StorageLayout>::layout(__key)
146 }
147 }
148 )
149 }
150
151 fn generate_auxiliary_trait_impls(&self) -> TokenStream2 {
160 let span = self.span();
161 let call_forwarder_ident = self.ident();
162 quote_spanned!(span=>
163 impl<E> ::core::clone::Clone for #call_forwarder_ident<E>
165 where
166 E: ::ink::env::Environment,
167 ::ink::H160: ::core::clone::Clone,
168 {
169 #[inline]
170 fn clone(&self) -> Self {
171 Self {
172 builder: <<Self as ::ink::codegen::TraitCallBuilder>::Builder
173 as ::core::clone::Clone>::clone(&self.builder),
174 }
175 }
176 }
177
178 impl<E> ::core::fmt::Debug for #call_forwarder_ident<E>
180 where
181 E: ::ink::env::Environment,
182 ::ink::H160: ::core::fmt::Debug,
183 {
184 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
185 f.debug_struct(::core::stringify!(#call_forwarder_ident))
186 .field("addr", &self.builder.addr)
187 .finish()
188 }
189 }
190
191 #[cfg(feature = "std")]
192 impl<E> ::ink::scale_info::TypeInfo for #call_forwarder_ident<E>
194 where
195 E: ::ink::env::Environment,
196 ::ink::H160: ::ink::scale_info::TypeInfo + 'static,
197 {
198 type Identity = <
199 <Self as ::ink::codegen::TraitCallBuilder>::Builder as ::ink::scale_info::TypeInfo
200 >::Identity;
201
202 fn type_info() -> ::ink::scale_info::Type {
203 <
204 <Self as ::ink::codegen::TraitCallBuilder>::Builder as ::ink::scale_info::TypeInfo
205 >::type_info()
206 }
207 }
208 )
209 }
210
211 fn generate_to_from_addr_impls(&self) -> TokenStream2 {
219 let span = self.span();
220 let call_forwarder_ident = self.ident();
221 quote_spanned!(span=>
222 impl<E> ::ink::env::call::FromAddr
223 for #call_forwarder_ident<E>
224 where
225 E: ::ink::env::Environment,
226 {
227 #[inline]
228 fn from_addr(addr: ::ink::H160) -> Self {
229 Self { builder: <<Self as ::ink::codegen::TraitCallBuilder>::Builder
230 as ::ink::env::call::FromAddr>::from_addr(addr) }
231 }
232 }
233
234 impl<E> ::core::convert::From<::ink::H160> for #call_forwarder_ident<E>
235 where
236 E: ::ink::env::Environment,
237 {
238 fn from(addr: ::ink::H160) -> Self {
239 <Self as ::ink::env::call::FromAddr>::from_addr(addr)
240 }
241 }
242
243 impl<E> ::ink::ToAddr for #call_forwarder_ident<E>
244 where
245 E: ::ink::env::Environment,
246 {
247 #[inline]
248 fn to_addr(&self) -> ::ink::H160 {
249 <<Self as ::ink::codegen::TraitCallBuilder>::Builder
250 as ::ink::ToAddr>::to_addr(&self.builder)
251 }
252 }
253
254 impl<E> ::core::convert::AsRef<::ink::H160> for #call_forwarder_ident<E>
255 where
256 E: ::ink::env::Environment,
257 {
258 fn as_ref(&self) -> &::ink::H160 {
259 <_ as ::core::convert::AsRef<::ink::H160>>::as_ref(&self.builder)
260 }
261 }
262
263 impl<E> ::core::convert::AsMut<::ink::H160> for #call_forwarder_ident<E>
264 where
265 E: ::ink::env::Environment,
266 {
267 fn as_mut(&mut self) -> &mut ::ink::H160 {
268 <_ as ::core::convert::AsMut<::ink::H160>>::as_mut(&mut self.builder)
269 }
270 }
271 )
272 }
273
274 fn generate_call_builder_trait_impl(&self) -> TokenStream2 {
282 let span = self.trait_def.span();
283 let call_forwarder_ident = self.ident();
284 let call_builder_ident = self.trait_def.call_builder_ident();
285 quote_spanned!(span=>
286 impl<E> ::ink::codegen::TraitCallBuilder for #call_forwarder_ident<E>
292 where
293 E: ::ink::env::Environment,
294 {
295 type Builder = #call_builder_ident<E>;
296
297 #[inline]
298 fn call(&self) -> &<Self as ::ink::codegen::TraitCallBuilder>::Builder {
299 &self.builder
300 }
301
302 #[inline]
303 fn call_mut(&mut self) -> &mut <Self as ::ink::codegen::TraitCallBuilder>::Builder {
304 &mut self.builder
305 }
306 }
307 )
308 }
309
310 fn generate_ink_trait_impl(&self) -> TokenStream2 {
317 let span = self.trait_def.span();
318 let trait_ident = self.trait_def.trait_def.item().ident();
319 let trait_info_ident = self.trait_def.trait_info_ident();
320 let forwarder_ident = self.ident();
321 let message_impls = self.generate_ink_trait_impl_messages();
322 quote_spanned!(span=>
323 impl<E> ::ink::env::ContractEnv for #forwarder_ident<E>
324 where
325 E: ::ink::env::Environment,
326 {
327 type Env = E;
328 }
329
330 impl<E> #trait_ident for #forwarder_ident<E>
331 where
332 E: ::ink::env::Environment,
333 {
334 #[allow(non_camel_case_types)]
335 type __ink_TraitInfo = #trait_info_ident<E>;
336
337 #message_impls
338 }
339 )
340 }
341
342 fn generate_ink_trait_impl_messages(&self) -> TokenStream2 {
345 let messages =
346 self.trait_def
347 .trait_def
348 .item()
349 .iter_items()
350 .filter_map(|(item, _)| {
351 item.filter_map_message()
352 .map(|message| self.generate_ink_trait_impl_for_message(&message))
353 });
354 quote! {
355 #( #messages )*
356 }
357 }
358
359 fn generate_ink_trait_impl_for_message(
362 &self,
363 message: &ir::InkTraitMessage,
364 ) -> TokenStream2 {
365 let span = message.span();
366 let trait_ident = self.trait_def.trait_def.item().ident();
367 let forwarder_ident = self.ident();
368 let message_ident = message.ident();
369 let attrs = self
370 .trait_def
371 .trait_def
372 .config()
373 .whitelisted_attributes()
374 .filter_attr(message.attrs());
375 let output_ident = generator::output_ident(message_ident);
376 let output_type = message
377 .output()
378 .cloned()
379 .unwrap_or_else(|| syn::parse_quote!(()));
380 let input_bindings = message.inputs().map(|input| &input.pat).collect::<Vec<_>>();
381 let input_types = message.inputs().map(|input| &input.ty).collect::<Vec<_>>();
382 let call_op = match message.receiver() {
383 ir::Receiver::Ref => quote! { call },
384 ir::Receiver::RefMut => quote! { call_mut },
385 };
386 let mut_tok = message.mutates().then(|| quote! { mut });
387 let panic_str = format!(
388 "encountered error while calling <{forwarder_ident} as {trait_ident}>::{message_ident}",
389 );
390 let cfg_attrs = message.get_cfg_attrs(span);
391 quote_spanned!(span =>
392 #( #cfg_attrs )*
393 type #output_ident = #output_type;
394
395 #( #attrs )*
396 #[inline]
397 fn #message_ident(
398 & #mut_tok self
399 #( , #input_bindings : #input_types )*
400 ) -> Self::#output_ident {
401 <<Self as ::ink::codegen::TraitCallBuilder>::Builder as #trait_ident>::#message_ident(
402 <Self as ::ink::codegen::TraitCallBuilder>::#call_op(self)
403 #(
404 , #input_bindings
405 )*
406 )
407 .try_invoke()
408 .unwrap_or_else(|env_err| ::core::panic!("{}: {:?}", #panic_str, env_err))
409 .unwrap_or_else(|lang_err| ::core::panic!("{}: {:?}", #panic_str, lang_err))
410 }
411 )
412 }
413}