Skip to content

Commit

Permalink
WIP TraitCallBuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
ascjones committed Apr 19, 2024
1 parent 6b500cf commit 667ad39
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 200 deletions.
16 changes: 16 additions & 0 deletions crates/env/src/call/call_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use crate::{
use core::marker::PhantomData;
use num_traits::Zero;
use pallet_contracts_uapi::CallFlags;
use crate::call::Invoke;

/// The final parameters to the cross-contract call.
#[derive(Debug)]
Expand Down Expand Up @@ -597,6 +598,21 @@ where
}
}

impl<E, CallType, Args, RetType> From<Invoke<Args, RetType>> for CallBuilder<E, Unset<CallType>, Args, RetType>
where
E: Environment,
{
fn from(invoke: Invoke<Args, RetType>) -> Self {
CallBuilder {
call_type: Default::default(),
call_flags: CallFlags::empty(),
exec_input: Set(invoke.input),
return_type: Default::default(),
_phantom: Default::default(),
}
}
}

impl<E, CallType, Args, RetType> CallBuilder<E, Unset<CallType>, Args, RetType>
where
E: Environment,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,8 @@ impl CallBuilder<'_> {
as ::ink::codegen::TraitCallBuilder>::Builder
as #trait_path>::#output_ident;

// todo: how to transfort Invoke<Args,RetType> into CallBuilder output ident

#[inline]
#( #attrs )*
fn #message_ident(
Expand Down
177 changes: 17 additions & 160 deletions crates/ink/codegen/src/generator/trait_def/call_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,11 @@ struct CallBuilder<'a> {
impl GenerateCode for CallBuilder<'_> {
fn generate_code(&self) -> TokenStream2 {
let struct_definition = self.generate_struct_definition();
let storage_layout_impl = self.generate_storage_layout_impl();
let auxiliary_trait_impls = self.generate_auxiliary_trait_impls();
let to_from_account_id_impls = self.generate_to_from_account_id_impls();
let ink_trait_impl = self.generate_ink_trait_impl();
quote! {
#struct_definition
#storage_layout_impl
#auxiliary_trait_impls
#to_from_account_id_impls
#ink_trait_impl
}
}
Expand Down Expand Up @@ -107,169 +103,35 @@ impl CallBuilder<'_> {
#[allow(non_camel_case_types)]
#[::ink::scale_derive(Encode, Decode)]
#[repr(transparent)]
pub struct #call_builder_ident<E>
where
E: ::ink::env::Environment,
{
account_id: <E as ::ink::env::Environment>::AccountId,
}
)
}

/// Generates the `StorageLayout` trait implementation for the account wrapper.
///
/// # Note
///
/// Due to the generic parameter `E` and Rust's default rules for derive generated
/// trait bounds it is not recommended to derive the `StorageLayout` trait
/// implementation.
fn generate_storage_layout_impl(&self) -> TokenStream2 {
let span = self.span();
let call_builder_ident = self.ident();
quote_spanned!(span=>
#[cfg(feature = "std")]
impl<E> ::ink::storage::traits::StorageLayout
for #call_builder_ident<E>
where
E: ::ink::env::Environment,
<E as ::ink::env::Environment>::AccountId: ::ink::storage::traits::StorageLayout,
{
fn layout(
__key: &::ink::primitives::Key,
) -> ::ink::metadata::layout::Layout {
::ink::metadata::layout::Layout::Struct(
::ink::metadata::layout::StructLayout::new(
::core::stringify!(#call_builder_ident),
[
::ink::metadata::layout::FieldLayout::new(
"account_id",
<<E as ::ink::env::Environment>::AccountId
as ::ink::storage::traits::StorageLayout>::layout(__key)
)
]
)
)
}
pub struct #call_builder_ident<E> {
marker: ::core::marker::PhantomData<fn() -> E>,
}
)
}

/// Generates trait implementations for auxiliary traits for the account wrapper.
/// Generates trait implementations for auxiliary traits.
///
/// # Note
///
/// Auxiliary traits currently include:
///
/// - `Clone`: To allow cloning contract references in the long run.
/// - `Debug`: To better debug internal contract state.
/// - `Default`: To allow constructing a new instance of the call builder.
fn generate_auxiliary_trait_impls(&self) -> TokenStream2 {
let span = self.span();
let call_builder_ident = self.ident();
quote_spanned!(span=>
/// We require this manual implementation since the derive produces incorrect trait bounds.
impl<E> ::core::clone::Clone for #call_builder_ident<E>
impl<E> ::core::default::Default for #call_builder_ident<E>
where
E: ::ink::env::Environment,
<E as ::ink::env::Environment>::AccountId: ::core::clone::Clone,
{
#[inline]
fn clone(&self) -> Self {
Self {
account_id: ::core::clone::Clone::clone(&self.account_id),
}
}
}

/// We require this manual implementation since the derive produces incorrect trait bounds.
impl<E> ::core::fmt::Debug for #call_builder_ident<E>
where
E: ::ink::env::Environment,
<E as ::ink::env::Environment>::AccountId: ::core::fmt::Debug,
{
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
f.debug_struct(::core::stringify!(#call_builder_ident))
.field("account_id", &self.account_id)
.finish()
}
}

#[cfg(feature = "std")]
/// We require this manual implementation since the derive produces incorrect trait bounds.
impl<E> ::ink::scale_info::TypeInfo for #call_builder_ident<E>
where
E: ::ink::env::Environment,
<E as ::ink::env::Environment>::AccountId: ::ink::scale_info::TypeInfo + 'static,
{
type Identity = <E as ::ink::env::Environment>::AccountId;

fn type_info() -> ::ink::scale_info::Type {
<<E as ::ink::env::Environment>::AccountId as ::ink::scale_info::TypeInfo>::type_info()
fn default() -> Self {
Self { marker: ::core::default::Default::default() }
}
}
)
}

/// Generate trait implementations for `FromAccountId` and `ToAccountId` for the
/// account wrapper.
///
/// # Note
///
/// This allows user code to conveniently transform from and to `AccountId` when
/// interacting with typed contracts.
fn generate_to_from_account_id_impls(&self) -> TokenStream2 {
let span = self.span();
let call_builder_ident = self.ident();
quote_spanned!(span=>
impl<E> ::ink::env::call::FromAccountId<E>
for #call_builder_ident<E>
where
E: ::ink::env::Environment,
{
#[inline]
fn from_account_id(account_id: <E as ::ink::env::Environment>::AccountId) -> Self {
Self { account_id }
}
}

impl<E, AccountId> ::core::convert::From<AccountId> for #call_builder_ident<E>
where
E: ::ink::env::Environment<AccountId = AccountId>,
AccountId: ::ink::env::AccountIdGuard,
{
fn from(value: AccountId) -> Self {
<Self as ::ink::env::call::FromAccountId<E>>::from_account_id(value)
}
}

impl<E> ::ink::ToAccountId<E> for #call_builder_ident<E>
where
E: ::ink::env::Environment,
{
#[inline]
fn to_account_id(&self) -> <E as ::ink::env::Environment>::AccountId {
<<E as ::ink::env::Environment>::AccountId as ::core::clone::Clone>::clone(&self.account_id)
}
}

impl<E, AccountId> ::core::convert::AsRef<AccountId> for #call_builder_ident<E>
where
E: ::ink::env::Environment<AccountId = AccountId>,
{
fn as_ref(&self) -> &AccountId {
&self.account_id
}
}

impl<E, AccountId> ::core::convert::AsMut<AccountId> for #call_builder_ident<E>
where
E: ::ink::env::Environment<AccountId = AccountId>,
{
fn as_mut(&mut self) -> &mut AccountId {
&mut self.account_id
}
}
)
}

/// Generates the implementation of the associated ink! trait definition.
///
Expand Down Expand Up @@ -349,11 +211,9 @@ impl CallBuilder<'_> {
quote_spanned!(span =>
#[allow(clippy::type_complexity)]
#( #cfg_attrs )*
type #output_ident = ::ink::env::call::CallBuilder<
Self::Env,
::ink::env::call::utils::Set< ::ink::env::call::Call< Self::Env > >,
::ink::env::call::utils::Set< ::ink::env::call::ExecutionInput<#arg_list> >,
::ink::env::call::utils::Set< ::ink::env::call::utils::ReturnType<#output_type> >,
type #output_ident = ::ink::env::call::Invoke<
#arg_list,
#output_type,
>;

#( #attrs )*
Expand All @@ -362,17 +222,14 @@ impl CallBuilder<'_> {
& #mut_tok self
#( , #input_bindings : #input_types )*
) -> Self::#output_ident {
::ink::env::call::build_call::<Self::Env>()
.call(::ink::ToAccountId::to_account_id(self))
.exec_input(
::ink::env::call::ExecutionInput::new(
::ink::env::call::Selector::new([ #( #selector_bytes ),* ])
)
#(
.push_arg(#input_bindings)
)*
::ink::env::call::Invoke::new(
::ink::env::call::ExecutionInput::new(
::ink::env::call::Selector::new([ #( #selector_bytes ),* ])
)
.returns::<#output_type>()
#(
.push_arg(#input_bindings)
)*
)
}
)
}
Expand Down
Loading

0 comments on commit 667ad39

Please sign in to comment.