Skip to content

Commit

Permalink
Fully implemented blanket implementation for CallBuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
xgreenx committed Feb 8, 2022
1 parent cb317b5 commit a39b980
Show file tree
Hide file tree
Showing 24 changed files with 276 additions and 665 deletions.
68 changes: 0 additions & 68 deletions crates/lang/codegen/src/enforced_error.rs

This file was deleted.

21 changes: 1 addition & 20 deletions crates/lang/codegen/src/generator/arg_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@
// limitations under the License.

use heck::ToLowerCamelCase as _;
use proc_macro2::{
Span,
TokenStream as TokenStream2,
};
use proc_macro2::TokenStream as TokenStream2;
use quote::{
format_ident,
quote,
Expand Down Expand Up @@ -86,19 +83,3 @@ where
}
)
}

/// Generates code to uniquely identify a trait by its unique ID given only its identifier.
///
/// # Note
///
/// As with all Rust macros identifiers can shadow each other so the given identifier
/// needs to be valid for the scope in which the returned code is generated.
pub fn generate_reference_to_trait_info(
span: Span,
trait_path: &syn::Path,
) -> TokenStream2 {
quote_spanned!(span=>
<::ink_lang::reflect::TraitDefinitionRegistry<Environment>
as #trait_path>::__ink_TraitInfo
)
}
168 changes: 1 addition & 167 deletions crates/lang/codegen/src/generator/as_dependency/call_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,11 @@ impl GenerateCode for CallBuilder<'_> {
fn generate_code(&self) -> TokenStream2 {
let call_builder_struct = self.generate_struct();
let auxiliary_trait_impls = self.generate_auxiliary_trait_impls();
// let call_builder_impls = self.generate_call_forwarder_impls();
let call_builder_inherent_impls = self.generate_call_builder_inherent_impls();
quote! {
const _: () = {
#call_builder_struct
#auxiliary_trait_impls
// #call_builder_impls
#call_builder_inherent_impls
};
}
Expand Down Expand Up @@ -110,7 +108,7 @@ impl CallBuilder<'_> {
type Env = <#storage_ident as ::ink_lang::reflect::ContractEnv>::Env;
}

impl ::ink_lang::reflect::InkStruct for #cb_ident {}
impl ::ink_lang::reflect::CallBuilder for #cb_ident {}
};
)
}
Expand Down Expand Up @@ -139,170 +137,6 @@ impl CallBuilder<'_> {
)
}

/// Generate the `TraitCallForwarder` trait implementations for the call builder
/// for every ink! trait implemented by the associated ink! smart contract.
///
/// These call forwarder trait implementations are used to dispatch to the global
/// call builder for the respective ink! trait definition that is being called.
/// The call builder only forwards the actual calls to those global call builders
/// and does not have its own calling logic.
fn generate_call_forwarder_impls(&self) -> TokenStream2 {
self.contract
.module()
.impls()
.filter_map(|impl_block| {
// We are only interested in ink! trait implementation block.
impl_block.trait_path().map(|trait_path| {
self.generate_code_for_trait_impl(trait_path, impl_block)
})
})
.collect()
}

/// Generates code required by the ink! call builder of an ink! smart contract
/// for a single ink! trait definition that the contract implements.
fn generate_code_for_trait_impl(
&self,
trait_path: &syn::Path,
impl_block: &ir::ItemImpl,
) -> TokenStream2 {
let call_forwarder_impl =
self.generate_call_forwarder_for_trait_impl(trait_path, impl_block);
let ink_trait_impl = self.generate_ink_trait_impl(trait_path, impl_block);
quote! {
#call_forwarder_impl
#ink_trait_impl
}
}

/// Generates code for a single ink! trait implementation to forward calls for
/// the associated ink! smart contract call builder.
fn generate_call_forwarder_for_trait_impl(
&self,
trait_path: &syn::Path,
impl_block: &ir::ItemImpl,
) -> TokenStream2 {
let span = impl_block.span();
let cb_ident = Self::call_builder_ident();
let trait_info = generator::generate_reference_to_trait_info(span, trait_path);
quote_spanned!(span=>
#[doc(hidden)]
impl ::ink_lang::codegen::TraitCallForwarderFor<#trait_info> for #cb_ident {
type Forwarder = <<Self as #trait_path>::__ink_TraitInfo as ::ink_lang::codegen::TraitCallForwarder>::Forwarder;

#[inline]
fn forward(&self) -> &Self::Forwarder {
// SAFETY:
//
// We convert from a shared reference to a type that thinly wraps
// only an `AccountId` to a shared reference to another type of which
// we know that it also thinly wraps an `AccountId`.
// Furthermore both types use `repr(transparent)`.
unsafe {
&*(&self.account_id as *const AccountId as *const Self::Forwarder)
}
}

#[inline]
fn forward_mut(&mut self) -> &mut Self::Forwarder {
// SAFETY:
//
// We convert from a exclusive reference to a type that thinly wraps
// only an `AccountId` to a exclusive reference to another type of which
// we know that it also thinly wraps an `AccountId`.
// Furthermore both types use `repr(transparent)`.
unsafe {
&mut *(&mut self.account_id as *mut AccountId as *mut Self::Forwarder)
}
}

#[inline]
fn build(&self) -> &<Self::Forwarder as ::ink_lang::codegen::TraitCallBuilder>::Builder {
<_ as ::ink_lang::codegen::TraitCallBuilder>::call(
<Self as ::ink_lang::codegen::TraitCallForwarderFor<#trait_info>>::forward(self)
)
}

#[inline]
fn build_mut(&mut self)
-> &mut <Self::Forwarder as ::ink_lang::codegen::TraitCallBuilder>::Builder
{
<_ as ::ink_lang::codegen::TraitCallBuilder>::call_mut(
<Self as ::ink_lang::codegen::TraitCallForwarderFor<#trait_info>>::forward_mut(self)
)
}
}
)
}

/// Generates the actual ink! trait implementation for the generated call builder.
fn generate_ink_trait_impl(
&self,
trait_path: &syn::Path,
impl_block: &ir::ItemImpl,
) -> TokenStream2 {
let span = impl_block.span();
let cb_ident = Self::call_builder_ident();
let messages = impl_block
.iter_messages()
.map(|message| self.generate_ink_trait_impl_for_message(trait_path, message));
quote_spanned!(span=>
impl #trait_path for #cb_ident {
type __ink_TraitInfo = <::ink_lang::reflect::TraitDefinitionRegistry<Environment>
as #trait_path>::__ink_TraitInfo;

#( #messages )*
}
)
}

/// Generates the code for the ink! trait implementation of the call builder
/// of a single ink! trait message and its associated output type.
fn generate_ink_trait_impl_for_message(
&self,
trait_path: &syn::Path,
message: ir::CallableWithSelector<ir::Message>,
) -> TokenStream2 {
use ir::Callable as _;
let span = message.span();
let message_ident = message.ident();
let output_ident = generator::output_ident(message_ident);
let trait_info = generator::generate_reference_to_trait_info(span, trait_path);
let (input_bindings, input_types): (Vec<_>, Vec<_>) = message
.callable()
.inputs()
.map(|input| (&input.pat, &input.ty))
.unzip();
let mut_token = message
.receiver()
.is_ref_mut()
.then(|| Some(quote! { mut }));
let build_cmd = match message.receiver() {
ir::Receiver::Ref => quote! { build },
ir::Receiver::RefMut => quote! { build_mut },
};
let attrs = message.attrs();
quote_spanned!(span=>
type #output_ident = <<<
Self
as ::ink_lang::codegen::TraitCallForwarderFor<#trait_info>>::Forwarder
as ::ink_lang::codegen::TraitCallBuilder>::Builder
as #trait_path>::#output_ident;

#[inline]
#( #attrs )*
fn #message_ident(
& #mut_token self
#( , #input_bindings: #input_types )*
) -> Self::#output_ident {
<_ as #trait_path>::#message_ident(
<Self as ::ink_lang::codegen::TraitCallForwarderFor<#trait_info>>::#build_cmd(self)
#( , #input_bindings )*
)
}
)
}

/// Generate call builder code for all ink! inherent ink! implementation blocks.
///
/// # Note
Expand Down
Loading

0 comments on commit a39b980

Please sign in to comment.