Tidy subxt-codegen crate interface (#1225)

* first pass tidying codegen crate interface

* fix a codegen test

* macro: keep error spans

* clippy

* fix doc example

* removecommented-out code
This commit is contained in:
James Wilson
2023-10-27 16:35:18 +01:00
committed by GitHub
parent 98170c8fdb
commit 2b21f8dc8c
29 changed files with 503 additions and 554 deletions
+2 -5
View File
@@ -3,10 +3,7 @@
// see LICENSE for license details.
use super::CodegenError;
use crate::{
types::{CompositeDefFields, TypeGenerator},
CratePath,
};
use crate::types::{CompositeDefFields, TypeGenerator};
use heck::{ToSnakeCase as _, ToUpperCamelCase as _};
use proc_macro2::TokenStream as TokenStream2;
use quote::{format_ident, quote};
@@ -25,7 +22,7 @@ pub fn generate_calls(
type_gen: &TypeGenerator,
pallet: &PalletMetadata,
types_mod_ident: &syn::Ident,
crate_path: &CratePath,
crate_path: &syn::Path,
should_gen_docs: bool,
) -> Result<TokenStream2, CodegenError> {
// Early return if the pallet has no calls.
+2 -2
View File
@@ -2,7 +2,7 @@
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
use crate::{types::TypeGenerator, CratePath};
use crate::types::TypeGenerator;
use heck::ToSnakeCase as _;
use proc_macro2::TokenStream as TokenStream2;
use quote::{format_ident, quote};
@@ -37,7 +37,7 @@ pub fn generate_constants(
type_gen: &TypeGenerator,
pallet: &PalletMetadata,
types_mod_ident: &syn::Ident,
crate_path: &CratePath,
crate_path: &syn::Path,
should_gen_docs: bool,
) -> Result<TokenStream2, CodegenError> {
// Early return if the pallet has no constants.
+6 -6
View File
@@ -4,7 +4,7 @@
use std::collections::HashSet;
use crate::{types::TypeGenerator, CratePath};
use crate::types::TypeGenerator;
use heck::ToSnakeCase as _;
use subxt_metadata::{CustomValueMetadata, Metadata};
@@ -12,10 +12,10 @@ use proc_macro2::TokenStream as TokenStream2;
use quote::{quote, ToTokens};
/// Generate the custom values mod, if there are any custom values in the metadata. Else returns None.
pub fn generate_custom_values<'a>(
metadata: &'a Metadata,
type_gen: &'a TypeGenerator,
crate_path: &'a CratePath,
pub fn generate_custom_values(
metadata: &Metadata,
type_gen: &TypeGenerator,
crate_path: &syn::Path,
) -> TokenStream2 {
let mut fn_names_taken = HashSet::new();
let custom = metadata.custom();
@@ -37,7 +37,7 @@ pub fn generate_custom_values<'a>(
fn generate_custom_value_fn(
custom_value: CustomValueMetadata,
type_gen: &TypeGenerator,
crate_path: &CratePath,
crate_path: &syn::Path,
fn_names_taken: &mut HashSet<String>,
) -> Option<TokenStream2> {
// names are transformed to snake case to make for good function identifiers.
+2 -2
View File
@@ -2,7 +2,7 @@
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
use crate::{types::TypeGenerator, CratePath};
use crate::types::TypeGenerator;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use subxt_metadata::PalletMetadata;
@@ -42,7 +42,7 @@ pub fn generate_events(
type_gen: &TypeGenerator,
pallet: &PalletMetadata,
types_mod_ident: &syn::Ident,
crate_path: &CratePath,
crate_path: &syn::Path,
should_gen_docs: bool,
) -> Result<TokenStream2, CodegenError> {
// Early return if the pallet has no events.
+4 -188
View File
@@ -14,203 +14,19 @@ mod storage;
use subxt_metadata::Metadata;
use super::DerivesRegistry;
use crate::api::custom_values::generate_custom_values;
use crate::error::CodegenError;
use crate::types::DerivesRegistry;
use crate::{
ir,
types::{CompositeDef, CompositeDefFields, TypeGenerator, TypeSubstitutes},
CratePath,
};
use codec::Decode;
use heck::ToSnakeCase as _;
use proc_macro2::TokenStream as TokenStream2;
use quote::{format_ident, quote};
use std::{fs, io::Read, path, string::ToString};
use syn::parse_quote;
/// Generate the runtime API for interacting with a substrate runtime.
pub struct GenerateRuntimeApi {
item_mod: syn::ItemMod,
derives: DerivesRegistry,
type_substitutes: TypeSubstitutes,
crate_path: CratePath,
should_gen_docs: bool,
runtime_types_only: bool,
unstable_metadata: bool,
}
impl GenerateRuntimeApi {
/// Construct a new [`GenerateRuntimeApi`].
pub fn new(item_mod: syn::ItemMod, crate_path: CratePath) -> Self {
GenerateRuntimeApi {
item_mod,
derives: DerivesRegistry::new(),
type_substitutes: TypeSubstitutes::new(),
crate_path,
should_gen_docs: false,
runtime_types_only: false,
unstable_metadata: false,
}
}
/// Provide custom derives for the generated types.
///
/// Default is no derives.
pub fn derives_registry(mut self, derives: DerivesRegistry) -> Self {
self.derives = derives;
self
}
/// Provide custom type substitutes.
///
/// Default is no substitutes.
pub fn type_substitutes(mut self, type_substitutes: TypeSubstitutes) -> Self {
self.type_substitutes = type_substitutes;
self
}
/// True if the generated API contains the documentation from the metadata.
///
/// Default: false.
pub fn generate_docs(mut self, should_gen_docs: bool) -> Self {
self.should_gen_docs = should_gen_docs;
self
}
/// Whether to limit code generation to only runtime types.
///
/// Default: false.
pub fn runtime_types_only(mut self, runtime_types_only: bool) -> Self {
self.runtime_types_only = runtime_types_only;
self
}
/// Whether to fetch the unstable metadata first.
///
/// # Note
///
/// This takes effect only if the API is generated from URL.
///
/// Default: false.
pub fn unstable_metadata(mut self, unstable_metadata: bool) -> Self {
self.unstable_metadata = unstable_metadata;
self
}
/// Generate the runtime API from path.
pub fn generate_from_path<P>(self, path: P) -> Result<TokenStream2, CodegenError>
where
P: AsRef<path::Path>,
{
let to_err = |err| CodegenError::Io(path.as_ref().to_string_lossy().into(), err);
let mut file = fs::File::open(&path).map_err(to_err)?;
let mut bytes = Vec::new();
file.read_to_end(&mut bytes).map_err(to_err)?;
let metadata = Metadata::decode(&mut &bytes[..])?;
generate_runtime_api_with_metadata(
self.item_mod,
metadata,
self.derives,
self.type_substitutes,
self.crate_path,
self.should_gen_docs,
self.runtime_types_only,
)
}
/// Generate the runtime API from the provided metadata bytes.
pub fn generate_from_bytes(self, bytes: &[u8]) -> Result<TokenStream2, CodegenError> {
let metadata = Metadata::decode(&mut &bytes[..])?;
generate_runtime_api_with_metadata(
self.item_mod,
metadata,
self.derives,
self.type_substitutes,
self.crate_path,
self.should_gen_docs,
self.runtime_types_only,
)
}
/// Generate the runtime API from URL.
///
/// The metadata will be downloaded from a node at the provided URL.
/// This function blocks while retrieving the metadata.
///
/// # Warning
///
/// Not recommended to be used in production environments.
#[cfg(feature = "fetch-metadata")]
pub fn generate_from_url(self, url: crate::utils::Url) -> Result<TokenStream2, CodegenError> {
use crate::utils::{fetch_metadata_bytes_blocking, MetadataVersion, Url};
fn fetch_metadata(url: Url, version: MetadataVersion) -> Result<Metadata, CodegenError> {
let bytes = fetch_metadata_bytes_blocking(url, version)?;
Ok(Metadata::decode(&mut &bytes[..])?)
}
let metadata = self
.unstable_metadata
.then(|| fetch_metadata(url.clone(), MetadataVersion::Unstable).ok())
.flatten();
let metadata = if let Some(unstable) = metadata {
unstable
} else {
match fetch_metadata(url.clone(), MetadataVersion::Version(15)) {
Ok(metadata) => metadata,
Err(_) => fetch_metadata(url, MetadataVersion::Version(14))?,
}
};
generate_runtime_api_with_metadata(
self.item_mod,
metadata,
self.derives,
self.type_substitutes,
self.crate_path,
self.should_gen_docs,
self.runtime_types_only,
)
}
}
/// Generates the API for interacting with a substrate runtime, using the `subxt::Metadata`.
fn generate_runtime_api_with_metadata(
item_mod: syn::ItemMod,
metadata: Metadata,
derives: DerivesRegistry,
type_substitutes: TypeSubstitutes,
crate_path: CratePath,
should_gen_docs: bool,
runtime_types_only: bool,
) -> Result<TokenStream2, CodegenError> {
let generator = RuntimeGenerator::new(metadata);
if runtime_types_only {
generator.generate_runtime_types(
item_mod,
derives,
type_substitutes,
crate_path,
should_gen_docs,
)
} else {
generator.generate_runtime(
item_mod,
derives,
type_substitutes,
crate_path,
should_gen_docs,
)
}
}
/// Create the API for interacting with a Substrate runtime.
pub struct RuntimeGenerator {
metadata: Metadata,
@@ -246,7 +62,7 @@ impl RuntimeGenerator {
item_mod: syn::ItemMod,
derives: DerivesRegistry,
type_substitutes: TypeSubstitutes,
crate_path: CratePath,
crate_path: syn::Path,
should_gen_docs: bool,
) -> Result<TokenStream2, CodegenError> {
let item_mod_attrs = item_mod.attrs.clone();
@@ -300,7 +116,7 @@ impl RuntimeGenerator {
item_mod: syn::ItemMod,
derives: DerivesRegistry,
type_substitutes: TypeSubstitutes,
crate_path: CratePath,
crate_path: syn::Path,
should_gen_docs: bool,
) -> Result<TokenStream2, CodegenError> {
let item_mod_attrs = item_mod.attrs.clone();
@@ -545,7 +361,7 @@ pub fn generate_structs_from_variants<F>(
type_id: u32,
variant_to_struct_name: F,
error_message_type_name: &str,
crate_path: &CratePath,
crate_path: &syn::Path,
should_gen_docs: bool,
) -> Result<Vec<(String, CompositeDef)>, CodegenError>
where
+3 -3
View File
@@ -2,7 +2,7 @@
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
use crate::{types::TypeGenerator, CodegenError, CratePath};
use crate::{types::TypeGenerator, CodegenError};
use heck::ToSnakeCase as _;
use heck::ToUpperCamelCase as _;
use subxt_metadata::{Metadata, RuntimeApiMetadata};
@@ -15,7 +15,7 @@ fn generate_runtime_api(
api: RuntimeApiMetadata,
type_gen: &TypeGenerator,
types_mod_ident: &syn::Ident,
crate_path: &CratePath,
crate_path: &syn::Path,
should_gen_docs: bool,
) -> Result<(TokenStream2, TokenStream2), CodegenError> {
// Trait name must remain as is (upper case) to identity the runtime call.
@@ -130,7 +130,7 @@ pub fn generate_runtime_apis(
metadata: &Metadata,
type_gen: &TypeGenerator,
types_mod_ident: &syn::Ident,
crate_path: &CratePath,
crate_path: &syn::Path,
should_gen_docs: bool,
) -> Result<TokenStream2, CodegenError> {
let runtime_fns: Vec<_> = metadata
+4 -4
View File
@@ -2,8 +2,8 @@
// 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::TypePath;
use crate::{types::TypeGenerator, CratePath};
use heck::ToSnakeCase as _;
use proc_macro2::{Ident, TokenStream as TokenStream2, TokenStream};
use quote::{format_ident, quote};
@@ -27,7 +27,7 @@ pub fn generate_storage(
type_gen: &TypeGenerator,
pallet: &PalletMetadata,
types_mod_ident: &syn::Ident,
crate_path: &CratePath,
crate_path: &syn::Path,
should_gen_docs: bool,
) -> Result<TokenStream2, CodegenError> {
let Some(storage) = pallet.storage() else {
@@ -59,7 +59,7 @@ fn generate_storage_entry_fns(
type_gen: &TypeGenerator,
pallet: &PalletMetadata,
storage_entry: &StorageEntryMetadata,
crate_path: &CratePath,
crate_path: &syn::Path,
should_gen_docs: bool,
) -> Result<TokenStream2, CodegenError> {
let keys: Vec<(Ident, TypePath)> = match storage_entry.entry_type() {
@@ -269,7 +269,7 @@ mod tests {
item_mod,
Default::default(),
Default::default(),
"::subxt_path".into(),
syn::parse_str("::subxt_path").unwrap(),
false,
)
.expect("should be able to generate runtime");
+8 -3
View File
@@ -16,9 +16,6 @@ pub enum CodegenError {
/// Cannot fetch the metadata bytes.
#[error("Failed to fetch metadata, make sure that you're pointing at a node which is providing substrate-based metadata: {0}")]
Fetch(#[from] FetchMetadataError),
/// Failed IO for the metadata file.
#[error("Failed IO for {0}, make sure that you are providing the correct file path for metadata: {1}")]
Io(String, std::io::Error),
/// Cannot decode the metadata bytes.
#[error("Could not decode metadata, only V14 and V15 metadata are supported: {0}")]
Decode(#[from] codec::Error),
@@ -85,15 +82,23 @@ impl CodegenError {
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum FetchMetadataError {
/// Error decoding from a hex value.
#[error("Cannot decode hex value: {0}")]
DecodeError(#[from] hex::FromHexError),
/// Some SCALE codec error.
#[error("Cannot scale encode/decode value: {0}")]
CodecError(#[from] codec::Error),
/// JSON-RPC error fetching metadata.
#[cfg(feature = "fetch-metadata")]
#[error("Request error: {0}")]
RequestError(#[from] jsonrpsee::core::Error),
/// Failed IO when fetching from a file.
#[error("Failed IO for {0}, make sure that you are providing the correct file path for metadata: {1}")]
Io(String, std::io::Error),
/// URL scheme is not http, https, ws or wss.
#[error("'{0}' not supported, supported URI schemes are http, https, ws or wss.")]
InvalidScheme(String),
/// Some other error.
#[error("Other error: {0}")]
Other(String),
}
@@ -2,17 +2,22 @@
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
//! Helper methods for fetching metadata from a file or URL.
use crate::error::FetchMetadataError;
use codec::{Decode, Encode};
use jsonrpsee::{
async_client::ClientBuilder,
client_transport::ws::{Url, WsTransportClientBuilder},
client_transport::ws::WsTransportClientBuilder,
core::{client::ClientT, Error},
http_client::HttpClientBuilder,
rpc_params,
};
use std::time::Duration;
// Part of the public interface:
pub use jsonrpsee::client_transport::ws::Url;
/// The metadata version that is fetched from the node.
#[derive(Default, Debug, Clone, Copy)]
pub enum MetadataVersion {
@@ -44,20 +49,24 @@ impl std::str::FromStr for MetadataVersion {
}
}
/// Fetch metadata from a file.
pub fn fetch_metadata_from_file_blocking(
path: &std::path::Path,
) -> Result<Vec<u8>, FetchMetadataError> {
use std::io::Read;
let to_err = |err| FetchMetadataError::Io(path.to_string_lossy().into(), err);
let mut file = std::fs::File::open(path).map_err(to_err)?;
let mut bytes = Vec::new();
file.read_to_end(&mut bytes).map_err(to_err)?;
Ok(bytes)
}
/// Returns the metadata bytes from the provided URL, blocking the current thread.
pub fn fetch_metadata_bytes_blocking(
pub fn fetch_metadata_from_url_blocking(
url: Url,
version: MetadataVersion,
) -> Result<Vec<u8>, FetchMetadataError> {
tokio_block_on(fetch_metadata_bytes(url, version))
}
/// Returns the raw, 0x prefixed metadata hex from the provided URL, blocking the current thread.
pub fn fetch_metadata_hex_blocking(
url: Url,
version: MetadataVersion,
) -> Result<String, FetchMetadataError> {
tokio_block_on(fetch_metadata_hex(url, version))
tokio_block_on(fetch_metadata_from_url(url, version))
}
// Block on some tokio runtime for sync contexts
@@ -70,7 +79,7 @@ fn tokio_block_on<T, Fut: std::future::Future<Output = T>>(fut: Fut) -> T {
}
/// Returns the metadata bytes from the provided URL.
pub async fn fetch_metadata_bytes(
pub async fn fetch_metadata_from_url(
url: Url,
version: MetadataVersion,
) -> Result<Vec<u8>, FetchMetadataError> {
@@ -83,16 +92,6 @@ pub async fn fetch_metadata_bytes(
Ok(bytes)
}
/// Returns the raw, 0x prefixed metadata hex from the provided URL.
pub async fn fetch_metadata_hex(
url: Url,
version: MetadataVersion,
) -> Result<String, FetchMetadataError> {
let bytes = fetch_metadata_bytes(url, version).await?;
let hex_data = format!("0x{}", hex::encode(bytes));
Ok(hex_data)
}
async fn fetch_metadata_ws(
url: Url,
version: MetadataVersion,
+252 -50
View File
@@ -2,65 +2,267 @@
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
//! Library to generate an API for a Substrate runtime from its metadata.
//!
//! ## Generated Structure
//!
//! The API generator logic:
//! - At the root there is the `item_mod` provided (ie `pub mod api {}`)
//! - Pallets are represented by a child module (ie `pub mod PalletName {}`) of the root
//! - Each pallet exposes as child modules (if applicable):
//! - Calls (`pub mod calls {}`)
//! - Events (`pub mod events {}`)
//! - Storage (`pub mod storage {}`)
//! - Constants (`pub mod constants {}`)
//!
//! ## Example
//!
//! ```no_run
//! use std::fs;
//! use codec::Decode;
//! use subxt_metadata::Metadata;
//! use subxt_codegen::{CratePath, DerivesRegistry, TypeSubstitutes};
//!
//! let encoded = fs::read("../artifacts/polkadot_metadata_full.scale").unwrap();
//!
//! // Runtime metadata obtained from a node.
//! let metadata = Metadata::decode(&mut &*encoded).unwrap();
//! // Module under which the API is generated.
//! let item_mod = syn::parse_quote!(
//! pub mod api {}
//! );
//! // Default module derivatives.
//! let mut derives = DerivesRegistry::with_default_derives(&CratePath::default());
//! // Default type substitutes.
//! let substs = TypeSubstitutes::with_default_substitutes(&CratePath::default());
//! // Generate the Runtime API.
//! let generator = subxt_codegen::RuntimeGenerator::new(metadata);
//! // Include metadata documentation in the Runtime API.
//! let generate_docs = true;
//! let runtime_api = generator.generate_runtime(item_mod, derives, substs, CratePath::default(), generate_docs).unwrap();
//! println!("{}", runtime_api);
//! ```
//! Generate a type safe Subxt interface for a Substrate runtime from its metadata.
//! This is used by the `#[subxt]` macro and `subxt codegen` CLI command, but can also
//! be used directly if preferable.
#![deny(unused_crate_dependencies, missing_docs)]
mod api;
mod error;
mod ir;
mod types;
pub mod error;
// These should probably be in a separate crate; they are used by the
// macro and CLI tool, so they only live here because this is a common
// crate that both depend on.
#[cfg(feature = "fetch-metadata")]
pub mod utils;
pub mod fetch_metadata;
#[cfg(feature = "web")]
use getrandom as _;
pub use self::{
api::{GenerateRuntimeApi, RuntimeGenerator},
error::{CodegenError, TypeSubstitutionError},
types::{
CratePath, Derives, DerivesRegistry, Module, TypeDefGen, TypeDefParameters, TypeGenerator,
TypeSubstitutes,
},
};
use api::RuntimeGenerator;
use proc_macro2::TokenStream as TokenStream2;
use std::collections::HashMap;
// We expose these only because they are currently needed in subxt-explorer.
// Eventually we'll move the type generation stuff out into a separate crate.
#[doc(hidden)]
pub mod __private {
pub use crate::types::{DerivesRegistry, TypeDefGen, TypeGenerator, TypeSubstitutes};
}
// Part of the public interface, so expose:
pub use error::CodegenError;
pub use subxt_metadata::Metadata;
pub use syn;
/// Generate a type safe interface to use with `subxt`.
/// The options exposed here are similar to those exposed via
/// the `#[subxt]` macro or via the `subxt codegen` CLI command.
/// Both use this under the hood.
///
/// # Example
///
/// Generating an interface using all of the defaults:
///
/// ```rust
/// use codec::Decode;
/// use subxt_codegen::{ Metadata, CodegenBuilder };
///
/// // Get hold of and decode some metadata:
/// let encoded = std::fs::read("../artifacts/polkadot_metadata_full.scale").unwrap();
/// let metadata = Metadata::decode(&mut &*encoded).unwrap();
///
/// // Generate a TokenStream representing the code for the interface.
/// // This can be converted to a string, displayed as-is or output from a macro.
/// let token_stream = CodegenBuilder::new().generate(metadata);
/// ````
pub struct CodegenBuilder {
crate_path: syn::Path,
use_default_derives: bool,
use_default_substitutions: bool,
generate_docs: bool,
runtime_types_only: bool,
item_mod: syn::ItemMod,
extra_global_derives: Vec<syn::Path>,
extra_global_attributes: Vec<syn::Attribute>,
type_substitutes: HashMap<syn::Path, syn::Path>,
derives_for_type: HashMap<syn::TypePath, Vec<syn::Path>>,
attributes_for_type: HashMap<syn::TypePath, Vec<syn::Attribute>>,
}
impl Default for CodegenBuilder {
fn default() -> Self {
CodegenBuilder {
crate_path: syn::parse_quote!(::subxt),
use_default_derives: true,
use_default_substitutions: true,
generate_docs: true,
runtime_types_only: false,
item_mod: syn::parse_quote!(
pub mod api {}
),
extra_global_derives: Vec::new(),
extra_global_attributes: Vec::new(),
type_substitutes: HashMap::new(),
derives_for_type: HashMap::new(),
attributes_for_type: HashMap::new(),
}
}
}
impl CodegenBuilder {
/// Construct a builder to configure and generate a type-safe interface for Subxt.
pub fn new() -> Self {
CodegenBuilder::default()
}
/// Disable the default derives that are applied to all types.
///
/// # Warning
///
/// This is not recommended, and is highly likely to break some part of the
/// generated interface. Expect compile errors.
pub fn disable_default_derives(&mut self) {
self.use_default_derives = false;
}
/// Disable the default type substitutions that are applied to the generated
/// code.
///
/// # Warning
///
/// This is not recommended, and is highly likely to break some part of the
/// generated interface. Expect compile errors.
pub fn disable_default_substitutes(&mut self) {
self.use_default_substitutions = false;
}
/// Disable the output of doc comments associated with the generated types and
/// methods. This can reduce the generated code size at the expense of losing
/// documentation.
pub fn no_docs(&mut self) {
self.generate_docs = false;
}
/// Only generate the types, and don't generate the rest of the Subxt specific
/// interface.
pub fn runtime_types_only(&mut self) {
self.runtime_types_only = true;
}
/// Set the additional derives that will be applied to all types. By default,
/// a set of derives required for Subxt are automatically added for all types.
///
/// # Warning
///
/// Invalid derives, or derives that cannot be applied to _all_ of the generated
/// types (taking into account that some types are substituted for hand written ones
/// that we cannot add extra derives for) will lead to compile errors in the
/// generated code.
pub fn set_additional_global_derives(&mut self, derives: Vec<syn::Path>) {
self.extra_global_derives = derives;
}
/// Set the additional attributes that will be applied to all types. By default,
/// a set of attributes required for Subxt are automatically added for all types.
///
/// # Warning
///
/// Invalid attributes can very easily lead to compile errors in the generated code.
pub fn set_additional_global_attributes(&mut self, attributes: Vec<syn::Attribute>) {
self.extra_global_attributes = attributes;
}
/// Set additional derives for a specific type at the path given.
///
/// # Warning
///
/// For composite types, you may also need to set the same additional derives on all of
/// the contained types as well to avoid compile errors in the generated code.
pub fn add_derives_for_type(
&mut self,
ty: syn::TypePath,
derives: impl IntoIterator<Item = syn::Path>,
) {
self.derives_for_type.entry(ty).or_default().extend(derives);
}
/// Set additional attributes for a specific type at the path given.
///
/// # Warning
///
/// For composite types, you may also need to consider contained types and whether they need
/// similar attributes setting.
pub fn add_attributes_for_type(
&mut self,
ty: syn::TypePath,
attributes: impl IntoIterator<Item = syn::Attribute>,
) {
self.attributes_for_type
.entry(ty)
.or_default()
.extend(attributes);
}
/// Substitute a type at the given path with some type at the second path. During codegen,
/// we will avoid generating the type at the first path given, and instead point any references
/// to that type to the second path given.
///
/// The substituted type will need to implement the relevant traits to be compatible with the
/// original, and it will need to SCALE encode and SCALE decode in a compatible way.
pub fn set_type_substitute(&mut self, ty: syn::Path, with: syn::Path) {
self.type_substitutes.insert(ty, with);
}
/// By default, all of the code is generated inside a module `pub mod api {}`. We decorate
/// this module with a few attributes to reduce compile warnings and things. You can provide a
/// target module here, allowing you to add additional attributes or inner code items (with the
/// warning that duplicate identifiers will lead to compile errors).
pub fn set_target_module(&mut self, item_mod: syn::ItemMod) {
self.item_mod = item_mod;
}
/// Set the path to the `subxt` crate. By default, we expect it to be at `::subxt`.
pub fn set_subxt_crate_path(&mut self, crate_path: syn::Path) {
self.crate_path = crate_path;
}
/// Generate an interface, assuming that the default path to the `subxt` crate is `::subxt`.
/// If the `subxt` crate is not available as a top level dependency, use `generate` and provide
/// a valid path to the `subxt¦ crate.
pub fn generate(self, metadata: Metadata) -> Result<TokenStream2, CodegenError> {
let crate_path = self.crate_path;
let mut derives_registry = if self.use_default_derives {
types::DerivesRegistry::with_default_derives(&crate_path)
} else {
types::DerivesRegistry::new()
};
derives_registry.extend_for_all(self.extra_global_derives, self.extra_global_attributes);
for (ty, derives) in self.derives_for_type {
derives_registry.extend_for_type(ty, derives, vec![]);
}
for (ty, attributes) in self.attributes_for_type {
derives_registry.extend_for_type(ty, vec![], attributes);
}
let mut type_substitutes = if self.use_default_substitutions {
types::TypeSubstitutes::with_default_substitutes(&crate_path)
} else {
types::TypeSubstitutes::new()
};
for (from, with) in self.type_substitutes {
let abs_path = with.try_into()?;
type_substitutes.insert(from, abs_path)?;
}
let item_mod = self.item_mod;
let generator = RuntimeGenerator::new(metadata);
let should_gen_docs = self.generate_docs;
if self.runtime_types_only {
generator.generate_runtime_types(
item_mod,
derives_registry,
type_substitutes,
crate_path,
should_gen_docs,
)
} else {
generator.generate_runtime(
item_mod,
derives_registry,
type_substitutes,
crate_path,
should_gen_docs,
)
}
}
}
+2 -2
View File
@@ -4,7 +4,7 @@
use crate::error::CodegenError;
use super::{CratePath, Derives, Field, TypeDefParameters, TypeGenerator, TypeParameter, TypePath};
use super::{Derives, Field, TypeDefParameters, TypeGenerator, TypeParameter, TypePath};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use scale_info::{form::PortableForm, Type, TypeDef, TypeDefPrimitive};
@@ -36,7 +36,7 @@ impl CompositeDef {
field_visibility: Option<syn::Visibility>,
type_gen: &TypeGenerator,
docs: &[String],
crate_path: &CratePath,
crate_path: &syn::Path,
) -> Result<Self, CodegenError> {
let mut derives = type_gen.type_derives(ty)?;
let fields: Vec<_> = fields_def.field_types().collect();
+3 -4
View File
@@ -2,7 +2,6 @@
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
use crate::CratePath;
use syn::{parse_quote, Path};
use std::collections::{HashMap, HashSet};
@@ -35,7 +34,7 @@ impl DerivesRegistry {
///
/// The `crate_path` denotes the `subxt` crate access path in the
/// generated code.
pub fn with_default_derives(crate_path: &CratePath) -> Self {
pub fn with_default_derives(crate_path: &syn::Path) -> Self {
Self {
default_derives: Derives::with_defaults(crate_path),
specific_type_derives: Default::default(),
@@ -117,7 +116,7 @@ impl Derives {
/// Creates a new instance of `Derives` with the `crate_path` prepended
/// to the set of default derives that reside in `subxt`.
pub fn with_defaults(crate_path: &CratePath) -> Self {
pub fn with_defaults(crate_path: &syn::Path) -> Self {
let mut derives = HashSet::new();
let mut attributes = HashSet::new();
@@ -148,7 +147,7 @@ impl Derives {
}
/// Add `#crate_path::ext::codec::CompactAs` to the derives.
pub fn insert_codec_compact_as(&mut self, crate_path: &CratePath) {
pub fn insert_codec_compact_as(&mut self, crate_path: &syn::Path) {
self.insert_derive(parse_quote!(#crate_path::ext::codec::CompactAs));
}
+2 -54
View File
@@ -41,7 +41,7 @@ pub struct TypeGenerator<'a> {
/// Set of derives with which to annotate generated types.
derives: DerivesRegistry,
/// The `subxt` crate access path in the generated code.
crate_path: CratePath,
crate_path: syn::Path,
/// True if codegen should generate the documentation for the API.
should_gen_docs: bool,
}
@@ -53,7 +53,7 @@ impl<'a> TypeGenerator<'a> {
root_mod: &'static str,
type_substitutes: TypeSubstitutes,
derives: DerivesRegistry,
crate_path: CratePath,
crate_path: syn::Path,
should_gen_docs: bool,
) -> Self {
let root_mod_ident = Ident::new(root_mod, Span::call_site());
@@ -334,55 +334,3 @@ impl Module {
&self.root_mod
}
}
/// A newtype wrapper which stores the path to the Subxt crate.
#[derive(Debug, Clone)]
pub struct CratePath(syn::Path);
impl CratePath {
/// Create a new `CratePath` from a `syn::Path`.
pub fn new(path: syn::Path) -> Self {
Self(path)
}
}
impl Default for CratePath {
fn default() -> Self {
Self(syn::parse_quote!(::subxt))
}
}
impl From<syn::Path> for CratePath {
fn from(path: syn::Path) -> Self {
CratePath::new(path)
}
}
impl ToTokens for CratePath {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.0.to_tokens(tokens)
}
}
impl From<&str> for CratePath {
fn from(crate_path: &str) -> Self {
Self(syn::parse_str(crate_path).unwrap_or_else(|err| {
panic!("failed converting {crate_path:?} to `syn::Path`: {err:?}");
}))
}
}
impl From<String> for CratePath {
fn from(crate_path: String) -> Self {
CratePath::from(crate_path.as_str())
}
}
impl From<Option<String>> for CratePath {
fn from(maybe_crate_path: Option<String>) -> Self {
match maybe_crate_path {
None => CratePath::default(),
Some(crate_path) => crate_path.into(),
}
}
}
+2 -2
View File
@@ -2,7 +2,7 @@
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
use crate::{error::TypeSubstitutionError, CratePath};
use crate::error::TypeSubstitutionError;
use std::{borrow::Borrow, collections::HashMap};
use syn::{parse_quote, spanned::Spanned as _};
@@ -55,7 +55,7 @@ impl TypeSubstitutes {
///
/// The `crate_path` denotes the `subxt` crate access path in the
/// generated code.
pub fn with_default_substitutes(crate_path: &CratePath) -> Self {
pub fn with_default_substitutes(crate_path: &syn::Path) -> Self {
// Some hardcoded default type substitutes, can be overridden by user
let defaults = [
(
+22 -22
View File
@@ -34,7 +34,7 @@ fn generate_struct_with_primitives() {
registry.register_type(&meta_type::<S>());
let portable_types: PortableRegistry = registry.into();
let crate_path = "::subxt_path".into();
let crate_path = syn::parse_str("::subxt_path").unwrap();
let type_gen = TypeGenerator::new(
&portable_types,
"root",
@@ -86,7 +86,7 @@ fn generate_struct_with_a_struct_field() {
registry.register_type(&meta_type::<Parent>());
let portable_types: PortableRegistry = registry.into();
let crate_path = "::subxt_path".into();
let crate_path = syn::parse_str("::subxt_path").unwrap();
let type_gen = TypeGenerator::new(
&portable_types,
"root",
@@ -140,7 +140,7 @@ fn generate_tuple_struct() {
registry.register_type(&meta_type::<Parent>());
let portable_types: PortableRegistry = registry.into();
let crate_path = "::subxt_path".into();
let crate_path = syn::parse_str("::subxt_path").unwrap();
let type_gen = TypeGenerator::new(
&portable_types,
"root",
@@ -231,7 +231,7 @@ fn derive_compact_as_for_uint_wrapper_structs() {
registry.register_type(&meta_type::<TSu128>());
let portable_types: PortableRegistry = registry.into();
let crate_path = "::subxt_path".into();
let crate_path = syn::parse_str("::subxt_path").unwrap();
let type_gen = TypeGenerator::new(
&portable_types,
"root",
@@ -328,7 +328,7 @@ fn generate_enum() {
registry.register_type(&meta_type::<E>());
let portable_types: PortableRegistry = registry.into();
let crate_path = "::subxt_path".into();
let crate_path = syn::parse_str("::subxt_path").unwrap();
let type_gen = TypeGenerator::new(
&portable_types,
"root",
@@ -392,7 +392,7 @@ fn compact_fields() {
registry.register_type(&meta_type::<E>());
let portable_types: PortableRegistry = registry.into();
let crate_path = "::subxt_path".into();
let crate_path = syn::parse_str("::subxt_path").unwrap();
let type_gen = TypeGenerator::new(
&portable_types,
"root",
@@ -460,7 +460,7 @@ fn compact_generic_parameter() {
registry.register_type(&meta_type::<S>());
let portable_types: PortableRegistry = registry.into();
let crate_path = "::subxt_path".into();
let crate_path = syn::parse_str("::subxt_path").unwrap();
let type_gen = TypeGenerator::new(
&portable_types,
"root",
@@ -507,7 +507,7 @@ fn generate_array_field() {
registry.register_type(&meta_type::<S>());
let portable_types: PortableRegistry = registry.into();
let crate_path = "::subxt_path".into();
let crate_path = syn::parse_str("::subxt_path").unwrap();
let type_gen = TypeGenerator::new(
&portable_types,
"root",
@@ -550,7 +550,7 @@ fn option_fields() {
registry.register_type(&meta_type::<S>());
let portable_types: PortableRegistry = registry.into();
let crate_path = "::subxt_path".into();
let crate_path = syn::parse_str("::subxt_path").unwrap();
let type_gen = TypeGenerator::new(
&portable_types,
"root",
@@ -596,7 +596,7 @@ fn box_fields_struct() {
registry.register_type(&meta_type::<S>());
let portable_types: PortableRegistry = registry.into();
let crate_path = "::subxt_path".into();
let crate_path = syn::parse_str("::subxt_path").unwrap();
let type_gen = TypeGenerator::new(
&portable_types,
"root",
@@ -642,7 +642,7 @@ fn box_fields_enum() {
registry.register_type(&meta_type::<E>());
let portable_types: PortableRegistry = registry.into();
let crate_path = "::subxt_path".into();
let crate_path = syn::parse_str("::subxt_path").unwrap();
let type_gen = TypeGenerator::new(
&portable_types,
"root",
@@ -688,7 +688,7 @@ fn range_fields() {
registry.register_type(&meta_type::<S>());
let portable_types: PortableRegistry = registry.into();
let crate_path = "::subxt_path".into();
let crate_path = syn::parse_str("::subxt_path").unwrap();
let type_gen = TypeGenerator::new(
&portable_types,
"root",
@@ -738,7 +738,7 @@ fn generics() {
registry.register_type(&meta_type::<Bar>());
let portable_types: PortableRegistry = registry.into();
let crate_path = "::subxt_path".into();
let crate_path = syn::parse_str("::subxt_path").unwrap();
let type_gen = TypeGenerator::new(
&portable_types,
"root",
@@ -795,7 +795,7 @@ fn generics_nested() {
registry.register_type(&meta_type::<Bar<bool>>());
let portable_types: PortableRegistry = registry.into();
let crate_path = "::subxt_path".into();
let crate_path = syn::parse_str("::subxt_path").unwrap();
let type_gen = TypeGenerator::new(
&portable_types,
"root",
@@ -852,7 +852,7 @@ fn generate_bitvec() {
registry.register_type(&meta_type::<S>());
let portable_types: PortableRegistry = registry.into();
let crate_path = "::subxt_path".into();
let crate_path = syn::parse_str("::subxt_path").unwrap();
let type_gen = TypeGenerator::new(
&portable_types,
"root",
@@ -911,7 +911,7 @@ fn generics_with_alias_adds_phantom_data_marker() {
registry.register_type(&meta_type::<UnnamedFields<bool, bool>>());
let portable_types: PortableRegistry = registry.into();
let crate_path = "::subxt_path".into();
let crate_path = syn::parse_str("::subxt_path").unwrap();
let type_gen = TypeGenerator::new(
&portable_types,
"root",
@@ -982,7 +982,7 @@ fn modules() {
registry.register_type(&meta_type::<m::c::Foo>());
let portable_types: PortableRegistry = registry.into();
let crate_path = "::subxt_path".into();
let crate_path = syn::parse_str("::subxt_path").unwrap();
let type_gen = TypeGenerator::new(
&portable_types,
"root",
@@ -1051,7 +1051,7 @@ fn dont_force_struct_names_camel_case() {
registry.register_type(&meta_type::<AB>());
let portable_types: PortableRegistry = registry.into();
let crate_path = "::subxt_path".into();
let crate_path = syn::parse_str("::subxt_path").unwrap();
let type_gen = TypeGenerator::new(
&portable_types,
"root",
@@ -1094,7 +1094,7 @@ fn apply_user_defined_derives_for_all_types() {
registry.register_type(&meta_type::<A>());
let portable_types: PortableRegistry = registry.into();
let crate_path = "::subxt_path".into();
let crate_path = syn::parse_str("::subxt_path").unwrap();
// configure derives
let mut derives = DerivesRegistry::with_default_derives(&crate_path);
derives.extend_for_all(
@@ -1156,7 +1156,7 @@ fn apply_user_defined_derives_for_specific_types() {
registry.register_type(&meta_type::<A>());
let portable_types: PortableRegistry = registry.into();
let crate_path = "::subxt_path".into();
let crate_path = syn::parse_str("::subxt_path").unwrap();
// configure derives
let mut derives = DerivesRegistry::with_default_derives(&crate_path);
// for all types
@@ -1233,7 +1233,7 @@ fn opt_out_from_default_derives() {
registry.register_type(&meta_type::<A>());
let portable_types: PortableRegistry = registry.into();
let crate_path = "::subxt_path".into();
let crate_path = syn::parse_str("::subxt_path").unwrap();
// configure derives
let mut derives = DerivesRegistry::new();
derives.extend_for_all(
@@ -1293,7 +1293,7 @@ fn opt_out_from_default_substitutes() {
registry.register_type(&meta_type::<S>());
let portable_types: PortableRegistry = registry.into();
let crate_path = "::subxt_path".into();
let crate_path = syn::parse_str("::subxt_path").unwrap();
let type_gen = TypeGenerator::new(
&portable_types,
"root",
+2 -3
View File
@@ -5,8 +5,7 @@
use crate::error::CodegenError;
use super::{
CompositeDef, CompositeDefFields, CratePath, Derives, TypeDefParameters, TypeGenerator,
TypeParameter,
CompositeDef, CompositeDefFields, Derives, TypeDefParameters, TypeGenerator, TypeParameter,
};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
@@ -34,7 +33,7 @@ impl TypeDefGen {
pub fn from_type(
ty: &Type<PortableForm>,
type_gen: &TypeGenerator,
crate_path: &CratePath,
crate_path: &syn::Path,
should_gen_docs: bool,
) -> Result<Self, CodegenError> {
let derives = type_gen.type_derives(ty)?;
+2 -4
View File
@@ -2,8 +2,6 @@
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
use crate::CratePath;
use proc_macro2::{Ident, TokenStream};
use quote::format_ident;
use scale_info::{form::PortableForm, Path, TypeDefPrimitive};
@@ -121,12 +119,12 @@ pub enum TypePathType {
Compact {
inner: Box<TypePath>,
is_field: bool,
crate_path: CratePath,
crate_path: syn::Path,
},
BitVec {
bit_order_type: Box<TypePath>,
bit_store_type: Box<TypePath>,
crate_path: CratePath,
crate_path: syn::Path,
},
}
-15
View File
@@ -1,15 +0,0 @@
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.
//! Utilities to help with fetching and decoding metadata.
mod fetch_metadata;
// easy access to this type needed for fetching metadata:
pub use jsonrpsee::client_transport::ws::Url;
pub use fetch_metadata::{
fetch_metadata_bytes, fetch_metadata_bytes_blocking, fetch_metadata_hex,
fetch_metadata_hex_blocking, MetadataVersion,
};