Remove codec::Encode and codec::Decode derives from generated APIs by default (#2008)

* Remove codec::Encode and codec::Decode from generated APIs by default

* clippy fixes

* clippy

* More fixes, and CompactAs only if Encode/Decode

* revert println in example

* fix lightclient test

* fix docs

* Fix another rust doc comment

* Fix failing storage test

* Remove now-unnecessary test

* clippy

* clippy

* Remove pointless clone
This commit is contained in:
James Wilson
2025-05-29 14:43:42 +01:00
committed by GitHub
parent 0473cfd292
commit ed25a3ac26
22 changed files with 627 additions and 8974 deletions
+7 -91
View File
@@ -6,7 +6,7 @@ use heck::{ToSnakeCase as _, ToUpperCamelCase};
use proc_macro2::{Ident, TokenStream as TokenStream2, TokenStream};
use quote::{format_ident, quote};
use scale_info::TypeDef;
use scale_typegen::{TypeGenerator, typegen::type_path::TypePath};
use scale_typegen::TypeGenerator;
use subxt_metadata::{
PalletMetadata, StorageEntryMetadata, StorageEntryModifier, StorageEntryType, StorageHasher,
};
@@ -92,7 +92,7 @@ fn generate_storage_entry_fns(
.expect("type is in metadata; qed");
let alias_name = format_ident!("Param{}", idx);
let alias_type = primitive_type_alias(&ty_path, type_gen.settings());
let alias_type = ty_path.to_token_stream(type_gen.settings());
let alias_type_def = quote!( pub type #alias_name = #alias_type; );
let alias_type_path = quote!( types::#alias_module_name::#alias_name );
@@ -206,7 +206,7 @@ fn generate_storage_entry_fns(
let key = &keys_slice[0];
if key.hasher.ends_with_key() {
let arg = &key.arg_name;
let keys = quote!(#static_storage_key::new(#arg.borrow()));
let keys = quote!(#static_storage_key::new(#arg));
let path = &key.alias_type_path;
let path = quote!(#static_storage_key<#path>);
(keys, path)
@@ -220,7 +220,7 @@ fn generate_storage_entry_fns(
arg_name, hasher, ..
}| {
if hasher.ends_with_key() {
quote!( #static_storage_key::new(#arg_name.borrow()) )
quote!( #static_storage_key::new(#arg_name) )
} else {
quote!(())
}
@@ -250,7 +250,7 @@ fn generate_storage_entry_fns(
arg_name,
alias_type_path,
..
}| quote!( #arg_name: impl ::core::borrow::Borrow<#alias_type_path> ),
}| quote!( #arg_name: #alias_type_path ),
);
quote!(
@@ -300,34 +300,14 @@ fn generate_storage_entry_fns(
))
}
fn primitive_type_alias(
type_path: &TypePath,
settings: &scale_typegen::TypeGeneratorSettings,
) -> TokenStream {
// Vec<T> is cast to [T]
if let Some(ty) = type_path.vec_type_param() {
let ty = ty.to_token_stream(settings);
return quote!([#ty]);
}
// String is cast to str
if type_path.is_string() {
return quote!(::core::primitive::str);
}
type_path.to_token_stream(settings)
}
#[cfg(test)]
mod tests {
use crate::RuntimeGenerator;
use frame_metadata::v15;
use heck::ToUpperCamelCase;
use quote::{format_ident, quote};
use scale_info::{MetaType, meta_type};
use std::borrow::Cow;
use subxt_metadata::Metadata;
// TODO: Think about adding tests for storage codegen which can use this sort of function.
#[allow(dead_code)]
fn metadata_with_storage_entries(
storage_entries: impl IntoIterator<Item = (&'static str, MetaType)>,
) -> Metadata {
@@ -387,68 +367,4 @@ mod tests {
.expect("can build valid metadata");
metadata
}
#[test]
fn borrow_type_replacements() {
let storage_entries = [
("vector", meta_type::<Vec<u8>>()),
("boxed", meta_type::<Box<u16>>()),
("string", meta_type::<String>()),
("static_string", meta_type::<&'static str>()),
("cow_string", meta_type::<Cow<'_, str>>()),
];
let expected_borrowed_types = [
quote!([::core::primitive::u8]),
quote!(::core::primitive::u16),
quote!(::core::primitive::str),
quote!(::core::primitive::str),
quote!(::core::primitive::str),
];
let metadata = metadata_with_storage_entries(storage_entries);
let item_mod = syn::parse_quote!(
pub mod api {}
);
let generator = RuntimeGenerator::new(metadata);
let generated = generator
.generate_runtime(
item_mod,
Default::default(),
Default::default(),
syn::parse_str("::subxt_path").unwrap(),
false,
)
.expect("should be able to generate runtime");
let generated_str = generated.to_string();
for ((name, _), expected_type) in storage_entries
.into_iter()
.zip(expected_borrowed_types.into_iter())
{
let name_ident = format_ident!("{}", name);
let expected_storage_constructor = quote!(
fn #name_ident(
&self,
_0: impl ::core::borrow::Borrow<types::#name_ident::Param0>,
)
);
dbg!(&generated_str);
dbg!(&expected_storage_constructor.to_string());
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()));
}
}
}
+24 -8
View File
@@ -312,15 +312,35 @@ fn subxt_type_gen_settings(
crate_path: &syn::Path,
should_gen_docs: bool,
) -> TypeGeneratorSettings {
// If we're using codec::Encode or codec::Decode derives, then we want to
// output #[codec(index = N)] and #[codec(compact)] attrs, else we don't.
let insert_codec_attributes = derives.default_derives().derives().iter().any(|path| {
let mut segments_backwards = path.segments.iter().rev();
let ident = segments_backwards.next();
let module = segments_backwards.next();
let is_ident_match = ident.is_some_and(|s| s.ident == "Encode" || s.ident == "Decode");
let is_module_match = module.is_some_and(|s| s.ident == "codec");
is_ident_match && is_module_match
});
// If we're inserting the codec attributes, we also should use `CompactAs` where necessary.
let compact_as_type_path = if insert_codec_attributes {
Some(parse_quote!(#crate_path::ext::codec::CompactAs))
} else {
None
};
TypeGeneratorSettings {
types_mod_ident: parse_quote!(runtime_types),
should_gen_docs,
derives,
substitutes,
decoded_bits_type_path: Some(parse_quote!(#crate_path::utils::bits::DecodedBits)),
compact_as_type_path: Some(parse_quote!(#crate_path::ext::codec::CompactAs)),
compact_as_type_path,
compact_type_path: Some(parse_quote!(#crate_path::ext::codec::Compact)),
insert_codec_attributes: true,
insert_codec_attributes,
alloc_crate_path: AllocCratePath::Custom(parse_quote!(#crate_path::alloc)),
}
}
@@ -329,19 +349,15 @@ fn default_derives(crate_path: &syn::Path) -> DerivesRegistry {
let encode_crate_path = quote::quote! { #crate_path::ext::scale_encode }.to_string();
let decode_crate_path = quote::quote! { #crate_path::ext::scale_decode }.to_string();
let derives: [syn::Path; 5] = [
let derives: [syn::Path; 3] = [
parse_quote!(#crate_path::ext::scale_encode::EncodeAsType),
parse_quote!(#crate_path::ext::scale_decode::DecodeAsType),
parse_quote!(#crate_path::ext::codec::Encode),
parse_quote!(#crate_path::ext::codec::Decode),
parse_quote!(Debug),
];
let attributes: [syn::Attribute; 4] = [
let attributes: [syn::Attribute; 2] = [
parse_quote!(#[encode_as_type(crate_path = #encode_crate_path)]),
parse_quote!(#[decode_as_type(crate_path = #decode_crate_path)]),
parse_quote!(#[codec(crate = #crate_path::ext::codec)]),
parse_quote!(#[codec(dumb_trait_bound)]),
];
let mut derives_registry = DerivesRegistry::new();