Introduce Metadata type (#974)

* WIP new Metadata type

* Finish basic Metadata impl inc hashing and validation

* remove caching from metadata; can add that higher up

* remove caches

* update retain to use Metadata

* clippy fixes

* update codegen to use Metadata

* clippy

* WIP fixing subxt lib

* WIP fixing tests, rebuild artifacts, fix OrderedMap::retain

* get --all-targets compiling

* move DispatchError type lookup back to being optional

* cargo clippy

* fix docs

* re-use VariantIndex to get variants

* add docs and enforce docs on metadata crate

* fix docs

* add test and fix docs

* cargo fmt

* address review comments

* update lockfiles

* ExactSizeIter so we can ask for len() of things (and hopefully soon is_empty()
This commit is contained in:
James Wilson
2023-05-25 10:35:21 +01:00
committed by GitHub
parent f344d0dd4d
commit b9f5419095
64 changed files with 6818 additions and 5719 deletions
+26 -38
View File
@@ -3,45 +3,42 @@
// see LICENSE for license details.
use crate::{types::TypeGenerator, CodegenError, CratePath};
use frame_metadata::v15::{RuntimeApiMetadata, RuntimeMetadataV15};
use heck::ToSnakeCase as _;
use heck::ToUpperCamelCase as _;
use subxt_metadata::{Metadata, RuntimeApiMetadata};
use proc_macro2::TokenStream as TokenStream2;
use quote::{format_ident, quote};
use scale_info::form::PortableForm;
/// Generates runtime functions for the given API metadata.
fn generate_runtime_api(
metadata: &RuntimeMetadataV15,
api: &RuntimeApiMetadata<PortableForm>,
api: RuntimeApiMetadata,
type_gen: &TypeGenerator,
types_mod_ident: &syn::Ident,
crate_path: &CratePath,
should_gen_docs: bool,
) -> Result<(TokenStream2, TokenStream2), CodegenError> {
// Trait name must remain as is (upper case) to identity the runtime call.
let trait_name = &api.name;
let trait_name_str = api.name();
// The snake case for the trait name.
let trait_name_snake = format_ident!("{}", api.name.to_snake_case());
let docs = &api.docs;
let trait_name_snake = format_ident!("{}", api.name().to_snake_case());
let docs = api.docs();
let docs: TokenStream2 = should_gen_docs
.then_some(quote! { #( #[doc = #docs ] )* })
.unwrap_or_default();
let structs_and_methods: Vec<_> = api.methods.iter().map(|method| {
let method_name = format_ident!("{}", method.name);
let structs_and_methods: Vec<_> = api.methods().map(|method| {
let method_name = format_ident!("{}", method.name());
let method_name_str = method.name();
// Runtime function name is `TraitName_MethodName`.
let runtime_fn_name = format!("{}_{}", trait_name, method_name);
let docs = &method.docs;
let docs = method.docs();
let docs: TokenStream2 = should_gen_docs
.then_some(quote! { #( #[doc = #docs ] )* })
.unwrap_or_default();
let inputs: Vec<_> = method.inputs.iter().map(|input| {
let inputs: Vec<_> = method.inputs().map(|input| {
let name = format_ident!("{}", &input.name);
let ty = type_gen.resolve_type_path(input.ty.id);
let ty = type_gen.resolve_type_path(input.ty);
let param = quote!(#name: #ty);
(param, name)
@@ -54,7 +51,7 @@ fn generate_runtime_api(
// all parameter types. This structure is used with metadata
// to encode parameters to the call via `encode_as_fields_to`.
let derives = type_gen.default_derives();
let struct_name = format_ident!("{}", method.name.to_upper_camel_case());
let struct_name = format_ident!("{}", method.name().to_upper_camel_case());
let struct_params = params.clone();
let struct_input = quote!(
#derives
@@ -63,21 +60,21 @@ fn generate_runtime_api(
}
);
let output = type_gen.resolve_type_path(method.output.id);
let output = type_gen.resolve_type_path(method.output_ty());
let Ok(call_hash) =
subxt_metadata::get_runtime_api_hash(metadata, trait_name, &method.name) else {
return Err(CodegenError::MissingRuntimeApiMetadata(
trait_name.into(),
method.name.clone(),
))
};
let Some(call_hash) = api.method_hash(method.name()) else {
return Err(CodegenError::MissingRuntimeApiMetadata(
trait_name_str.to_owned(),
method_name_str.to_owned(),
))
};
let method = quote!(
#docs
pub fn #method_name(&self, #( #params, )* ) -> #crate_path::runtime_api::Payload<types::#struct_name, #output> {
#crate_path::runtime_api::Payload::new_static(
#runtime_fn_name,
#trait_name_str,
#method_name_str,
types::#struct_name { #( #param_names, )* },
[#(#call_hash,)*],
)
@@ -87,7 +84,7 @@ fn generate_runtime_api(
Ok((struct_input, method))
}).collect::<Result<_, _>>()?;
let trait_name = format_ident!("{}", trait_name);
let trait_name = format_ident!("{}", trait_name_str);
let structs = structs_and_methods.iter().map(|(struct_, _)| struct_);
let methods = structs_and_methods.iter().map(|(_, method)| method);
@@ -124,25 +121,16 @@ fn generate_runtime_api(
/// Generate the runtime APIs.
pub fn generate_runtime_apis(
metadata: &RuntimeMetadataV15,
metadata: &Metadata,
type_gen: &TypeGenerator,
types_mod_ident: &syn::Ident,
crate_path: &CratePath,
should_gen_docs: bool,
) -> Result<TokenStream2, CodegenError> {
let apis = &metadata.apis;
let runtime_fns: Vec<_> = apis
.iter()
let runtime_fns: Vec<_> = metadata
.runtime_api_traits()
.map(|api| {
generate_runtime_api(
metadata,
api,
type_gen,
types_mod_ident,
crate_path,
should_gen_docs,
)
generate_runtime_api(api, type_gen, types_mod_ident, crate_path, should_gen_docs)
})
.collect::<Result<_, _>>()?;