Skip to content
22 changes: 17 additions & 5 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ enum Command {
/// Additional derives
#[structopt(long = "derive")]
derives: Vec<String>,
/// The `subxt` crate access path in the generated code.
/// Defaults to `::subxt`.
#[structopt(short = "crate")]
crate_path: Option<String>,
},
/// Verify metadata compatibility between substrate nodes.
Compatibility {
Expand Down Expand Up @@ -136,7 +140,12 @@ async fn main() -> color_eyre::Result<()> {
}
}
}
Command::Codegen { url, file, derives } => {
Command::Codegen {
url,
file,
derives,
crate_path,
} => {
if let Some(file) = file.as_ref() {
if url.is_some() {
eyre::bail!("specify one of `--url` or `--file` but not both")
Expand All @@ -145,7 +154,7 @@ async fn main() -> color_eyre::Result<()> {
let mut file = fs::File::open(file)?;
let mut bytes = Vec::new();
file.read_to_end(&mut bytes)?;
codegen(&mut &bytes[..], derives)?;
codegen(&mut &bytes[..], derives, crate_path)?;
return Ok(())
}

Expand All @@ -155,7 +164,7 @@ async fn main() -> color_eyre::Result<()> {
.expect("default url is valid")
});
let (_, bytes) = fetch_metadata(&url).await?;
codegen(&mut &bytes[..], derives)?;
codegen(&mut &bytes[..], derives, crate_path)?;
Ok(())
}
Command::Compatibility { nodes, pallet } => {
Expand Down Expand Up @@ -296,6 +305,7 @@ async fn fetch_metadata(url: &Uri) -> color_eyre::Result<(String, Vec<u8>)> {
fn codegen<I: Input>(
encoded: &mut I,
raw_derives: Vec<String>,
crate_path: Option<String>,
) -> color_eyre::Result<()> {
let metadata = <RuntimeMetadataPrefixed as Decode>::decode(encoded)?;
let generator = subxt_codegen::RuntimeGenerator::new(metadata);
Expand All @@ -307,10 +317,12 @@ fn codegen<I: Input>(
.iter()
.map(|raw| syn::parse_str(raw))
.collect::<Result<Vec<_>, _>>()?;
let mut derives = DerivesRegistry::default();

let crate_path = crate_path.map(Into::into).unwrap_or_default();
let mut derives = DerivesRegistry::new(&crate_path);
derives.extend_for_all(p.into_iter());

let runtime_api = generator.generate_runtime(item_mod, derives);
let runtime_api = generator.generate_runtime(item_mod, derives, crate_path);
println!("{}", runtime_api);
Ok(())
}
16 changes: 11 additions & 5 deletions codegen/src/api/calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.

use crate::types::{
CompositeDefFields,
TypeGenerator,
use crate::{
types::{
CompositeDefFields,
TypeGenerator,
},
CratePath,
};
use frame_metadata::{
v14::RuntimeMetadataV14,
Expand Down Expand Up @@ -36,6 +39,7 @@ pub fn generate_calls(
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 {
Expand All @@ -49,6 +53,7 @@ pub fn generate_calls(
call.ty.id(),
|name| name.to_upper_camel_case().into(),
"Call",
crate_path,
);
let (call_structs, call_fns): (Vec<_>, Vec<_>) = struct_defs
.iter_mut()
Expand Down Expand Up @@ -98,13 +103,14 @@ pub fn generate_calls(
let call_struct = quote! {
#struct_def
};

let client_fn = quote! {
#docs
pub fn #fn_name(
&self,
#( #call_fn_args, )*
) -> ::subxt::tx::StaticTxPayload<#struct_name> {
::subxt::tx::StaticTxPayload::new(
) -> #crate_path::tx::StaticTxPayload<#struct_name> {
#crate_path::tx::StaticTxPayload::new(
#pallet_name,
#call_name,
#struct_name { #( #call_args, )* },
Expand Down
10 changes: 7 additions & 3 deletions codegen/src/api/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.

use crate::types::TypeGenerator;
use crate::{
types::TypeGenerator,
CratePath,
};
use frame_metadata::{
v14::RuntimeMetadataV14,
PalletMetadata,
Expand Down Expand Up @@ -44,6 +47,7 @@ pub fn generate_constants(
type_gen: &TypeGenerator,
pallet: &PalletMetadata<PortableForm>,
types_mod_ident: &syn::Ident,
crate_path: &CratePath,
) -> TokenStream2 {
// Early return if the pallet has no constants.
if pallet.constants.is_empty() {
Expand All @@ -63,8 +67,8 @@ pub fn generate_constants(

quote! {
#( #[doc = #docs ] )*
pub fn #fn_name(&self) -> ::subxt::constants::StaticConstantAddress<::subxt::metadata::DecodeStaticType<#return_ty>> {
::subxt::constants::StaticConstantAddress::new(
pub fn #fn_name(&self) -> #crate_path::constants::StaticConstantAddress<#crate_path::metadata::DecodeStaticType<#return_ty>> {
#crate_path::constants::StaticConstantAddress::new(
#pallet_name,
#constant_name,
[#(#constant_hash,)*]
Expand Down
9 changes: 7 additions & 2 deletions codegen/src/api/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.

use crate::types::TypeGenerator;
use crate::{
types::TypeGenerator,
CratePath,
};
use frame_metadata::PalletMetadata;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
Expand Down Expand Up @@ -41,6 +44,7 @@ pub fn generate_events(
type_gen: &TypeGenerator,
pallet: &PalletMetadata<PortableForm>,
types_mod_ident: &syn::Ident,
crate_path: &CratePath,
) -> TokenStream2 {
// Early return if the pallet has no events.
let event = if let Some(ref event) = pallet.event {
Expand All @@ -54,6 +58,7 @@ pub fn generate_events(
event.ty.id(),
|name| name.into(),
"Event",
crate_path,
);
let event_structs = struct_defs.iter().map(|(variant_name, struct_def)| {
let pallet_name = &pallet.name;
Expand All @@ -63,7 +68,7 @@ pub fn generate_events(
quote! {
#struct_def

impl ::subxt::events::StaticEvent for #event_struct {
impl #crate_path::events::StaticEvent for #event_struct {
const PALLET: &'static str = #pallet_name;
const EVENT: &'static str = #event_name;
}
Expand Down
40 changes: 27 additions & 13 deletions codegen/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use crate::{
CompositeDefFields,
TypeGenerator,
},
CratePath,
};
use codec::Decode;
use frame_metadata::{
Expand Down Expand Up @@ -55,6 +56,7 @@ pub fn generate_runtime_api<P>(
item_mod: syn::ItemMod,
path: P,
derives: DerivesRegistry,
crate_path: CratePath,
) -> TokenStream2
where
P: AsRef<path::Path>,
Expand All @@ -71,7 +73,7 @@ where
.unwrap_or_else(|e| abort_call_site!("Failed to decode metadata: {}", e));

let generator = RuntimeGenerator::new(metadata);
generator.generate_runtime(item_mod, derives)
generator.generate_runtime(item_mod, derives, crate_path)
}

/// Create the API for interacting with a Substrate runtime.
Expand Down Expand Up @@ -101,6 +103,7 @@ impl RuntimeGenerator {
&self,
item_mod: syn::ItemMod,
derives: DerivesRegistry,
crate_path: CratePath,
) -> TokenStream2 {
let item_mod_ir = ir::ItemMod::from(item_mod);
let default_derives = derives.default_derives();
Expand All @@ -109,41 +112,41 @@ impl RuntimeGenerator {
let mut type_substitutes = [
(
"bitvec::order::Lsb0",
parse_quote!(::subxt::ext::bitvec::order::Lsb0),
parse_quote!(#crate_path::ext::bitvec::order::Lsb0),
),
(
"bitvec::order::Msb0",
parse_quote!(::subxt::ext::bitvec::order::Msb0),
parse_quote!(#crate_path::ext::bitvec::order::Msb0),
),
(
"sp_core::crypto::AccountId32",
parse_quote!(::subxt::ext::sp_core::crypto::AccountId32),
parse_quote!(#crate_path::ext::sp_core::crypto::AccountId32),
),
(
"primitive_types::H160",
parse_quote!(::subxt::ext::sp_core::H160),
parse_quote!(#crate_path::ext::sp_core::H160),
),
(
"primitive_types::H256",
parse_quote!(::subxt::ext::sp_core::H256),
parse_quote!(#crate_path::ext::sp_core::H256),
),
(
"primitive_types::H512",
parse_quote!(::subxt::ext::sp_core::H512),
parse_quote!(#crate_path::ext::sp_core::H512),
),
(
"sp_runtime::multiaddress::MultiAddress",
parse_quote!(::subxt::ext::sp_runtime::MultiAddress),
parse_quote!(#crate_path::ext::sp_runtime::MultiAddress),
),
(
"frame_support::traits::misc::WrapperKeepOpaque",
parse_quote!(::subxt::utils::WrapperKeepOpaque),
parse_quote!(#crate_path::utils::WrapperKeepOpaque),
),
// BTreeMap and BTreeSet impose an `Ord` constraint on their key types. This
// can cause an issue with generated code that doesn't impl `Ord` by default.
// Decoding them to Vec by default (KeyedVec is just an alias for Vec with
// suitable type params) avoids these issues.
("BTreeMap", parse_quote!(::subxt::utils::KeyedVec)),
("BTreeMap", parse_quote!(#crate_path::utils::KeyedVec)),
("BTreeSet", parse_quote!(::std::vec::Vec)),
]
.iter()
Expand All @@ -161,6 +164,7 @@ impl RuntimeGenerator {
"runtime_types",
type_substitutes,
derives.clone(),
crate_path.clone(),
);
let types_mod = type_gen.generate_types_mod();
let types_mod_ident = types_mod.ident();
Expand Down Expand Up @@ -190,23 +194,31 @@ impl RuntimeGenerator {
let metadata_hash = get_metadata_per_pallet_hash(&self.metadata, &pallet_names);

let modules = pallets_with_mod_names.iter().map(|(pallet, mod_name)| {
let calls =
calls::generate_calls(&self.metadata, &type_gen, pallet, types_mod_ident);
let calls = calls::generate_calls(
&self.metadata,
&type_gen,
pallet,
types_mod_ident,
&crate_path,
);

let event = events::generate_events(&type_gen, pallet, types_mod_ident);
let event =
events::generate_events(&type_gen, pallet, types_mod_ident, &crate_path);

let storage_mod = storage::generate_storage(
&self.metadata,
&type_gen,
pallet,
types_mod_ident,
&crate_path,
);

let constants_mod = constants::generate_constants(
&self.metadata,
&type_gen,
pallet,
types_mod_ident,
&crate_path,
);

quote! {
Expand Down Expand Up @@ -338,6 +350,7 @@ pub fn generate_structs_from_variants<'a, F>(
type_id: u32,
variant_to_struct_name: F,
error_message_type_name: &str,
crate_path: &CratePath,
) -> Vec<(String, CompositeDef)>
where
F: Fn(&str) -> std::borrow::Cow<str>,
Expand All @@ -363,6 +376,7 @@ where
Some(parse_quote!(pub)),
type_gen,
var.docs(),
crate_path,
);
(var.name().to_string(), struct_def)
})
Expand Down
Loading