Files
pezkuwi-subxt/codegen/src/api/calls.rs
T
Michael Müller f115ff975c Allow specifying the subxt crate path for generated code (#664)
* Allow specifying the `subxt` crate path for generated code

* Make `clippy` happy

* Add documentation

* Improve optics

* Remove custom crate path test

* Implement comments

* Update comment

* Make `crate_path` property instead of argument

* Remove unnecessary derives

* Remove `Default` impls in favor of explicit constructors

* Remove unnecessary `into`

* Update codegen/src/types/mod.rs

Co-authored-by: Andrew Jones <ascjones@gmail.com>

Co-authored-by: Andrew Jones <ascjones@gmail.com>
2022-09-27 11:41:36 +01:00

146 lines
4.8 KiB
Rust

// Copyright 2019-2022 Parity Technologies (UK) Ltd.
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
use crate::{
types::{
CompositeDefFields,
TypeGenerator,
},
CratePath,
};
use frame_metadata::{
v14::RuntimeMetadataV14,
PalletMetadata,
};
use heck::{
ToSnakeCase as _,
ToUpperCamelCase as _,
};
use proc_macro2::TokenStream as TokenStream2;
use proc_macro_error::abort_call_site;
use quote::{
format_ident,
quote,
};
use scale_info::form::PortableForm;
/// Generate calls from the provided pallet's metadata. Each call returns a `StaticTxPayload`
/// that can be passed to the subxt client to submit/sign/encode.
///
/// # Arguments
///
/// - `metadata` - Runtime metadata from which the calls are generated.
/// - `type_gen` - The type generator containing all types defined by metadata.
/// - `pallet` - Pallet metadata from which the calls are generated.
/// - `types_mod_ident` - The ident of the base module that we can use to access the generated types from.
pub fn generate_calls(
metadata: &RuntimeMetadataV14,
type_gen: &TypeGenerator,
pallet: &PalletMetadata<PortableForm>,
types_mod_ident: &syn::Ident,
crate_path: &CratePath,
) -> TokenStream2 {
// Early return if the pallet has no calls.
let call = if let Some(ref calls) = pallet.calls {
calls
} else {
return quote!()
};
let mut struct_defs = super::generate_structs_from_variants(
type_gen,
call.ty.id(),
|name| name.to_upper_camel_case().into(),
"Call",
crate_path,
);
let (call_structs, call_fns): (Vec<_>, Vec<_>) = struct_defs
.iter_mut()
.map(|(variant_name, struct_def)| {
let (call_fn_args, call_args): (Vec<_>, Vec<_>) = match struct_def.fields {
CompositeDefFields::Named(ref named_fields) => {
named_fields
.iter()
.map(|(name, field)| {
let fn_arg_type = &field.type_path;
let call_arg = if field.is_boxed() {
quote! { #name: ::std::boxed::Box::new(#name) }
} else {
quote! { #name }
};
(quote!( #name: #fn_arg_type ), call_arg)
})
.unzip()
}
CompositeDefFields::NoFields => Default::default(),
CompositeDefFields::Unnamed(_) => {
abort_call_site!(
"Call variant for type {} must have all named fields",
call.ty.id()
)
}
};
let pallet_name = &pallet.name;
let call_name = &variant_name;
let struct_name = &struct_def.name;
let call_hash =
subxt_metadata::get_call_hash(metadata, pallet_name, call_name)
.unwrap_or_else(|_| {
abort_call_site!(
"Metadata information for the call {}_{} could not be found",
pallet_name,
call_name
)
});
let fn_name = format_ident!("{}", variant_name.to_snake_case());
// Propagate the documentation just to `TransactionApi` methods, while
// draining the documentation of inner call structures.
let docs = struct_def.docs.take();
// The call structure's documentation was stripped above.
let call_struct = quote! {
#struct_def
};
let client_fn = quote! {
#docs
pub fn #fn_name(
&self,
#( #call_fn_args, )*
) -> #crate_path::tx::StaticTxPayload<#struct_name> {
#crate_path::tx::StaticTxPayload::new(
#pallet_name,
#call_name,
#struct_name { #( #call_args, )* },
[#(#call_hash,)*]
)
}
};
(call_struct, client_fn)
})
.unzip();
let call_ty = type_gen.resolve_type(call.ty.id());
let docs = call_ty.docs();
quote! {
#( #[doc = #docs ] )*
pub mod calls {
use super::root_mod;
use super::#types_mod_ident;
type DispatchError = #types_mod_ident::sp_runtime::DispatchError;
#( #call_structs )*
pub struct TransactionApi;
impl TransactionApi {
#( #call_fns )*
}
}
}
}