-
Notifications
You must be signed in to change notification settings - Fork 248
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use scale-typegen
as a backend for the codegen
#1260
Changes from 38 commits
e163e57
1760792
b297fc8
7a2678a
60c1e62
297d2c6
f47fd4e
03591a6
9e56546
50ed54e
dabc88c
cd73d31
fd718bf
985a46c
a6b580f
44c42c3
0724735
ee1e096
58b8fee
0c7d373
42643d8
8196b63
bbda16a
4259572
14775ab
69af6d1
f125b2b
602d459
b18d472
aaf9ded
05dbe3f
e54cb73
24cb3d7
3d1fdec
f0ef2a9
72fee7d
a96c90f
70d3de0
00aee3d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -228,11 +228,11 @@ impl StorageEntryDiff { | |||||
let value_1_ty_id = storage_entry_1.entry_type().value_ty(); | ||||||
let value_1_hash = metadata_1 | ||||||
.type_hash(value_1_ty_id) | ||||||
.expect("type should be present"); | ||||||
.expect("type is in metadata; qed"); | ||||||
let value_2_ty_id = storage_entry_2.entry_type().value_ty(); | ||||||
let value_2_hash = metadata_1 | ||||||
.type_hash(value_2_ty_id) | ||||||
.expect("type should be present"); | ||||||
.expect("type is in metadata; qed"); | ||||||
let value_different = value_1_hash != value_2_hash; | ||||||
|
||||||
let key_1_hash = storage_entry_1 | ||||||
|
@@ -241,7 +241,7 @@ impl StorageEntryDiff { | |||||
.map(|key_ty| { | ||||||
metadata_1 | ||||||
.type_hash(key_ty) | ||||||
.expect("type should be present") | ||||||
.expect("type is in metadata; qed") | ||||||
}) | ||||||
.unwrap_or_default(); | ||||||
let key_2_hash = storage_entry_2 | ||||||
|
@@ -250,7 +250,7 @@ impl StorageEntryDiff { | |||||
.map(|key_ty| { | ||||||
metadata_2 | ||||||
.type_hash(key_ty) | ||||||
.expect("type should be present") | ||||||
.expect("type is in metadata; qed") | ||||||
}) | ||||||
.unwrap_or_default(); | ||||||
let key_different = key_1_hash != key_2_hash; | ||||||
|
@@ -309,12 +309,12 @@ fn storage_differences<'a>( | |||||
|e| { | ||||||
pallet_metadata_1 | ||||||
.storage_hash(e.name()) | ||||||
.expect("storage entry should be present") | ||||||
.expect("storage entry is in medadata; qed") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
}, | ||||||
|e| { | ||||||
pallet_metadata_2 | ||||||
.storage_hash(e.name()) | ||||||
.expect("storage entry should be present") | ||||||
.expect("storage entry is in medadata; qed") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
}, | ||||||
|e| e.name(), | ||||||
) | ||||||
|
@@ -330,12 +330,12 @@ fn calls_differences<'a>( | |||||
|e| { | ||||||
pallet_metadata_1 | ||||||
.call_hash(&e.name) | ||||||
.expect("call should be present") | ||||||
.expect("call is in metadata; qed") | ||||||
}, | ||||||
|e| { | ||||||
pallet_metadata_2 | ||||||
.call_hash(&e.name) | ||||||
.expect("call should be present") | ||||||
.expect("call is in metadata; qed") | ||||||
}, | ||||||
|e| &e.name, | ||||||
); | ||||||
|
@@ -351,12 +351,12 @@ fn constants_differences<'a>( | |||||
|e| { | ||||||
pallet_metadata_1 | ||||||
.constant_hash(e.name()) | ||||||
.expect("constant should be present") | ||||||
.expect("constant is in metadata; qed") | ||||||
}, | ||||||
|e| { | ||||||
pallet_metadata_2 | ||||||
.constant_hash(e.name()) | ||||||
.expect("constant should be present") | ||||||
.expect("constant is in metadata; qed") | ||||||
}, | ||||||
|e| e.name(), | ||||||
) | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,92 +3,80 @@ | |
// see LICENSE for license details. | ||
|
||
use super::CodegenError; | ||
use crate::types::{CompositeDefFields, TypeGenerator}; | ||
use heck::{ToSnakeCase as _, ToUpperCamelCase as _}; | ||
use proc_macro2::TokenStream as TokenStream2; | ||
use quote::{format_ident, quote}; | ||
use scale_typegen::{typegen::ir::type_ir::CompositeIRKind, TypeGenerator}; | ||
use subxt_metadata::PalletMetadata; | ||
|
||
/// 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. | ||
/// - `type_gen` - [`scale_typegen::TypeGenerator`] that contains settings and all types from the runtime 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. | ||
/// - `crate_path` - The crate path under which subxt is located, e.g. `::subxt` when using subxt as a dependency. | ||
pub fn generate_calls( | ||
type_gen: &TypeGenerator, | ||
pallet: &PalletMetadata, | ||
niklasad1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
types_mod_ident: &syn::Ident, | ||
crate_path: &syn::Path, | ||
should_gen_docs: bool, | ||
) -> Result<TokenStream2, CodegenError> { | ||
// Early return if the pallet has no calls. | ||
let Some(call_ty) = pallet.call_ty_id() else { | ||
return Ok(quote!()); | ||
}; | ||
|
||
let mut struct_defs = super::generate_structs_from_variants( | ||
let variant_names_and_struct_defs = super::generate_structs_from_variants( | ||
type_gen, | ||
types_mod_ident, | ||
call_ty, | ||
|name| name.to_upper_camel_case().into(), | ||
"Call", | ||
crate_path, | ||
should_gen_docs, | ||
)?; | ||
|
||
let result = struct_defs | ||
.iter_mut() | ||
.map(|(variant_name, struct_def, aliases)| { | ||
let fn_name = format_ident!("{}", variant_name.to_snake_case()); | ||
|
||
let result: Vec<_> = match struct_def.fields { | ||
CompositeDefFields::Named(ref named_fields) => named_fields | ||
let (call_structs, call_fns): (Vec<_>, Vec<_>) = variant_names_and_struct_defs | ||
.into_iter() | ||
.map(|var| { | ||
let (call_fn_args, call_args): (Vec<_>, Vec<_>) = match &var.composite.kind { | ||
CompositeIRKind::Named(named_fields) => named_fields | ||
.iter() | ||
.map(|(name, field)| { | ||
let call_arg = if field.is_boxed() { | ||
// Note: fn_arg_type this is relative the type path of the type alias when prefixed with `types::`, e.g. `set_max_code_size::New` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could there be a variant of the metadata where this does not correspond to the expected alias? Or it would be different from the previous There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good question, when calling |
||
let fn_arg_type = &field.type_path; | ||
let call_arg = if field.is_boxed { | ||
quote! { #name: ::std::boxed::Box::new(#name) } | ||
} else { | ||
quote! { #name } | ||
}; | ||
|
||
let alias_name = | ||
format_ident!("{}", name.to_string().to_upper_camel_case()); | ||
|
||
(quote!( #name: types::#fn_name::#alias_name ), call_arg) | ||
(quote!( #name: types::#fn_arg_type ), call_arg) | ||
}) | ||
.collect(), | ||
CompositeDefFields::NoFields => Default::default(), | ||
CompositeDefFields::Unnamed(_) => { | ||
.unzip(), | ||
CompositeIRKind::NoFields => Default::default(), | ||
CompositeIRKind::Unnamed(_) => { | ||
return Err(CodegenError::InvalidCallVariant(call_ty)) | ||
} | ||
}; | ||
|
||
let call_fn_args = result.iter().map(|(call_fn_arg, _)| call_fn_arg); | ||
let call_args = result.iter().map(|(_, call_arg)| call_arg); | ||
|
||
let pallet_name = pallet.name(); | ||
let call_name = &variant_name; | ||
let struct_name = &struct_def.name; | ||
let call_name = &var.variant_name; | ||
let struct_name = &var.composite.name; | ||
let Some(call_hash) = pallet.call_hash(call_name) else { | ||
return Err(CodegenError::MissingCallMetadata( | ||
pallet_name.into(), | ||
call_name.to_string(), | ||
)); | ||
}; | ||
|
||
let fn_name = format_ident!("{}", var.variant_name.to_snake_case()); | ||
// Propagate the documentation just to `TransactionApi` methods, while | ||
// draining the documentation of inner call structures. | ||
let docs = should_gen_docs.then_some(struct_def.docs.take()).flatten(); | ||
let docs = &var.composite.docs; | ||
|
||
// this converts the composite into a full struct type. No Type Parameters needed here. | ||
let struct_def = type_gen.upcast_composite(&var.composite); | ||
let alias_mod = var.type_alias_mod; | ||
// The call structure's documentation was stripped above. | ||
let call_struct = quote! { | ||
#struct_def | ||
|
||
#aliases | ||
#alias_mod | ||
|
||
impl #crate_path::blocks::StaticExtrinsic for #struct_name { | ||
const PALLET: &'static str = #pallet_name; | ||
|
@@ -113,17 +101,15 @@ pub fn generate_calls( | |
|
||
Ok((call_struct, client_fn)) | ||
}) | ||
.collect::<Result<Vec<_>, _>>()?; | ||
.collect::<Result<Vec<_>, _>>()? | ||
.into_iter() | ||
.unzip(); | ||
|
||
let call_structs = result.iter().map(|(call_struct, _)| call_struct); | ||
let call_fns = result.iter().map(|(_, client_fn)| client_fn); | ||
let call_type = type_gen.resolve_type_path(call_ty)?; | ||
let call_ty = type_gen.resolve_type(call_ty)?; | ||
let docs = type_gen.docs_from_scale_info(&call_ty.docs); | ||
|
||
let call_type = type_gen.resolve_type_path(call_ty); | ||
let call_ty = type_gen.resolve_type(call_ty); | ||
let docs = &call_ty.docs; | ||
let docs = should_gen_docs | ||
.then_some(quote! { #( #[doc = #docs ] )* }) | ||
.unwrap_or_default(); | ||
let types_mod_ident = type_gen.types_mod_ident(); | ||
|
||
Ok(quote! { | ||
#docs | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would we want to support recursive derives in the CLI? Might be worth a separate issue to remind us of it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, maybe. Or maybe we just make everything recursive by default in the CLI, I think it is already quite hard to specify derives in the CLI.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be great if you could open an issue for it :)