mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-22 14:58:04 +00:00
codegen: Generate type aliases for better API ergonomics (#1249)
* codegen: Generate type alias for storage return types
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* codegen: Generate type alias for call function arguments
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* testing: Update polkadot.rs code from commit 2e2a75ff81
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* codegen: Type aliases for runtime API parameters
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* codegen: Type alias for runtime apis output
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* storage: Change path of the aliased module
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* codegen: Adjust module indentation
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* codegen: Do not alias for api::runtime_types with unresolved generics
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* codegen: Fix and document runtime API alias generation
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* Update artifacts
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* Update cargo.lock file
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* codegen: Generate composite structs with alias unnamed fields
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* testing: Update polkadot.rs file
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* codegen: Alias storage unnamed parameters
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* Update polkadot.rs
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* examples: Change polkadot to rococo runtime
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* codegen: Fix compiling tests in the codegen crate
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* codegen: Extend storage test with alias module
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* cli/tests: Adjust exepcted commands to the latest metadata
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* codegen: Remove missleading comment and docs
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* codegen: Ensure unique names for generated runtime API types
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* codegen/tests: Test expected runtime type generation
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* codegen/tests: Check duplicate params in runtime APIs
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* codegen/tests: Test colliding names of type aliases and parameters
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* Fix clippy
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* codegen: Separate alias module from struct definition
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* Update polkadot.rs
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
* codegen: Remove outdated docs from composite def
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
---------
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
This commit is contained in:
+82
-26
@@ -5,6 +5,7 @@
|
||||
use crate::types::TypeGenerator;
|
||||
use crate::types::TypePath;
|
||||
use heck::ToSnakeCase as _;
|
||||
use heck::ToUpperCamelCase as _;
|
||||
use proc_macro2::{Ident, TokenStream as TokenStream2, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
use scale_info::TypeDef;
|
||||
@@ -34,18 +35,33 @@ pub fn generate_storage(
|
||||
return Ok(quote!());
|
||||
};
|
||||
|
||||
let storage_fns = storage
|
||||
let (storage_fns, alias_modules): (Vec<_>, Vec<_>) = storage
|
||||
.entries()
|
||||
.iter()
|
||||
.map(|entry| {
|
||||
generate_storage_entry_fns(type_gen, pallet, entry, crate_path, should_gen_docs)
|
||||
generate_storage_entry_fns(
|
||||
type_gen,
|
||||
pallet,
|
||||
entry,
|
||||
crate_path,
|
||||
should_gen_docs,
|
||||
types_mod_ident,
|
||||
)
|
||||
})
|
||||
.collect::<Result<Vec<_>, CodegenError>>()?;
|
||||
.collect::<Result<Vec<_>, CodegenError>>()?
|
||||
.into_iter()
|
||||
.unzip();
|
||||
|
||||
Ok(quote! {
|
||||
pub mod storage {
|
||||
use super::#types_mod_ident;
|
||||
|
||||
pub mod types {
|
||||
use super::#types_mod_ident;
|
||||
|
||||
#( #alias_modules )*
|
||||
}
|
||||
|
||||
pub struct StorageApi;
|
||||
|
||||
impl StorageApi {
|
||||
@@ -61,8 +77,30 @@ fn generate_storage_entry_fns(
|
||||
storage_entry: &StorageEntryMetadata,
|
||||
crate_path: &syn::Path,
|
||||
should_gen_docs: bool,
|
||||
) -> Result<TokenStream2, CodegenError> {
|
||||
let keys: Vec<(Ident, TypePath)> = match storage_entry.entry_type() {
|
||||
types_mod_ident: &syn::Ident,
|
||||
) -> Result<(TokenStream2, TokenStream2), CodegenError> {
|
||||
let snake_case_name = storage_entry.name().to_snake_case();
|
||||
let storage_entry_ty = storage_entry.entry_type().value_ty();
|
||||
let storage_entry_value_ty = type_gen.resolve_type_path(storage_entry_ty);
|
||||
|
||||
let alias_name = format_ident!("{}", storage_entry.name().to_upper_camel_case());
|
||||
let alias_module_name = format_ident!("{snake_case_name}");
|
||||
let alias_storage_path = quote!( types::#alias_module_name::#alias_name );
|
||||
|
||||
let storage_entry_map = |idx, id| {
|
||||
let ident: Ident = format_ident!("_{}", idx);
|
||||
let ty_path = type_gen.resolve_type_path(id);
|
||||
|
||||
let alias_name = format_ident!("Param{}", idx);
|
||||
let alias_type = primitive_type_alias(&ty_path);
|
||||
|
||||
let alias_type = quote!( pub type #alias_name = #alias_type; );
|
||||
let path_to_alias = quote!( types::#alias_module_name::#alias_name );
|
||||
|
||||
(ident, alias_type, path_to_alias)
|
||||
};
|
||||
|
||||
let keys: Vec<(Ident, TokenStream, TokenStream)> = match storage_entry.entry_type() {
|
||||
StorageEntryType::Plain(_) => vec![],
|
||||
StorageEntryType::Map { key_ty, .. } => {
|
||||
match &type_gen.resolve_type(*key_ty).type_def {
|
||||
@@ -71,17 +109,11 @@ fn generate_storage_entry_fns(
|
||||
.fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, f)| {
|
||||
let ident: Ident = format_ident!("_{}", syn::Index::from(i));
|
||||
let ty_path = type_gen.resolve_type_path(f.id);
|
||||
(ident, ty_path)
|
||||
})
|
||||
.map(|(idx, f)| storage_entry_map(idx, f.id))
|
||||
.collect::<Vec<_>>(),
|
||||
// A map with a single key; return the single key.
|
||||
_ => {
|
||||
let ident = format_ident!("_0");
|
||||
let ty_path = type_gen.resolve_type_path(*key_ty);
|
||||
vec![(ident, ty_path)]
|
||||
vec![storage_entry_map(0, *key_ty)]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,9 +127,6 @@ fn generate_storage_entry_fns(
|
||||
));
|
||||
};
|
||||
|
||||
let snake_case_name = storage_entry.name().to_snake_case();
|
||||
let storage_entry_ty = storage_entry.entry_type().value_ty();
|
||||
let storage_entry_value_ty = type_gen.resolve_type_path(storage_entry_ty);
|
||||
let docs = storage_entry.docs();
|
||||
let docs = should_gen_docs
|
||||
.then_some(quote! { #( #[doc = #docs ] )* })
|
||||
@@ -123,10 +152,9 @@ fn generate_storage_entry_fns(
|
||||
};
|
||||
let is_fetchable_type = is_fetchable.then_some(quote!(#crate_path::storage::address::Yes)).unwrap_or(quote!(()));
|
||||
let is_iterable_type = is_iterable.then_some(quote!(#crate_path::storage::address::Yes)).unwrap_or(quote!(()));
|
||||
let key_impls = keys_slice.iter().map(|(field_name, _)| quote!( #crate_path::storage::address::make_static_storage_map_key(#field_name.borrow()) ));
|
||||
let key_args = keys_slice.iter().map(|(field_name, field_type)| {
|
||||
let field_ty = primitive_type_alias(field_type);
|
||||
quote!( #field_name: impl ::std::borrow::Borrow<#field_ty> )
|
||||
let key_impls = keys_slice.iter().map(|(field_name, _, _)| quote!( #crate_path::storage::address::make_static_storage_map_key(#field_name.borrow()) ));
|
||||
let key_args = keys_slice.iter().map(|(field_name, _, path_to_alias )| {
|
||||
quote!( #field_name: impl ::std::borrow::Borrow<#path_to_alias> )
|
||||
});
|
||||
|
||||
quote!(
|
||||
@@ -136,7 +164,7 @@ fn generate_storage_entry_fns(
|
||||
#(#key_args,)*
|
||||
) -> #crate_path::storage::address::Address::<
|
||||
#crate_path::storage::address::StaticStorageMapKey,
|
||||
#storage_entry_value_ty,
|
||||
#alias_storage_path,
|
||||
#is_fetchable_type,
|
||||
#is_defaultable_type,
|
||||
#is_iterable_type
|
||||
@@ -151,11 +179,26 @@ fn generate_storage_entry_fns(
|
||||
)
|
||||
});
|
||||
|
||||
Ok(quote! {
|
||||
#( #all_fns
|
||||
let alias_types = keys.iter().map(|(_, alias_type, _)| alias_type);
|
||||
|
||||
)*
|
||||
})
|
||||
// Generate type alias for the return type only, since
|
||||
// the keys of the storage entry are not explicitly named.
|
||||
let alias_module = quote! {
|
||||
pub mod #alias_module_name {
|
||||
use super::#types_mod_ident;
|
||||
|
||||
pub type #alias_name = #storage_entry_value_ty;
|
||||
|
||||
#( #alias_types )*
|
||||
}
|
||||
};
|
||||
|
||||
Ok((
|
||||
quote! {
|
||||
#( #all_fns )*
|
||||
},
|
||||
alias_module,
|
||||
))
|
||||
}
|
||||
|
||||
fn primitive_type_alias(type_path: &TypePath) -> TokenStream {
|
||||
@@ -174,6 +217,7 @@ fn primitive_type_alias(type_path: &TypePath) -> TokenStream {
|
||||
mod tests {
|
||||
use crate::RuntimeGenerator;
|
||||
use frame_metadata::v15;
|
||||
use heck::ToUpperCamelCase as _;
|
||||
use quote::{format_ident, quote};
|
||||
use scale_info::{meta_type, MetaType};
|
||||
use std::borrow::Cow;
|
||||
@@ -283,10 +327,22 @@ mod tests {
|
||||
let expected_storage_constructor = quote!(
|
||||
fn #name_ident(
|
||||
&self,
|
||||
_0: impl ::std::borrow::Borrow<#expected_type>,
|
||||
_0: impl ::std::borrow::Borrow<types::#name_ident::Param0>,
|
||||
)
|
||||
);
|
||||
assert!(generated_str.contains(&expected_storage_constructor.to_string()));
|
||||
|
||||
let alias_name = format_ident!("{}", name.to_upper_camel_case());
|
||||
let expected_alias_module = quote!(
|
||||
pub mod #name_ident {
|
||||
use super::runtime_types;
|
||||
|
||||
pub type #alias_name = ::core::primitive::bool;
|
||||
pub type Param0 = #expected_type;
|
||||
}
|
||||
);
|
||||
|
||||
assert!(generated_str.contains(&expected_alias_module.to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user