diff --git a/Cargo.toml b/Cargo.toml
index a619ba49c7..1c0d059880 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,5 +1,5 @@
[workspace]
-members = [".", "macro", "tests"]
+members = [".", "codegen", "macro", "tests"]
[package]
name = "substrate-subxt"
diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml
new file mode 100644
index 0000000000..0e216f5eb7
--- /dev/null
+++ b/codegen/Cargo.toml
@@ -0,0 +1,21 @@
+[package]
+name = "subxt-codegen"
+version = "0.1.0"
+edition = "2018"
+
+[dependencies]
+async-trait = "0.1.49"
+codec = { package = "parity-scale-codec", version = "2", default-features = false, features = ["derive", "full"] }
+darling = "0.13.0"
+frame-metadata = "14.0"
+heck = "0.3.2"
+proc-macro2 = "1.0.24"
+proc-macro-crate = "0.1.5"
+proc-macro-error = "1.0.4"
+quote = "1.0.8"
+syn = "1.0.58"
+scale-info = "1.0.0"
+
+[dev-dependencies]
+codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] }
+pretty_assertions = "0.6.1"
diff --git a/macro/src/generate_runtime.rs b/codegen/src/api.rs
similarity index 86%
rename from macro/src/generate_runtime.rs
rename to codegen/src/api.rs
index a7b70ae561..3e66ea282d 100644
--- a/macro/src/generate_runtime.rs
+++ b/codegen/src/api.rs
@@ -15,9 +15,8 @@
// along with substrate-subxt. If not, see .
use crate::{
- TokenStream2,
- TypeGenerator,
- TypePath,
+ struct_def::StructDef,
+ types::TypeGenerator,
};
use codec::Decode;
use darling::FromMeta;
@@ -33,10 +32,8 @@ use frame_metadata::{
StorageEntryType,
StorageHasher,
};
-use heck::{
- CamelCase as _,
- SnakeCase as _,
-};
+use heck::SnakeCase as _;
+use proc_macro2::TokenStream as TokenStream2;
use proc_macro_error::{
abort,
abort_call_site,
@@ -430,7 +427,14 @@ impl RuntimeGenerator {
variant
.variants()
.iter()
- .map(|var| StructDef::from_variant(var, type_gen))
+ .map(|var| {
+ StructDef::new(
+ var.name(),
+ var.fields(),
+ Some(syn::parse_quote!(pub)),
+ type_gen,
+ )
+ })
.collect()
} else {
abort_call_site!(
@@ -585,107 +589,3 @@ impl RuntimeGenerator {
(storage_entry_type, client_fn)
}
}
-
-#[derive(Debug)]
-pub struct StructDef {
- name: syn::Ident,
- fields: StructDefFields,
-}
-
-#[derive(Debug)]
-pub enum StructDefFields {
- Named(Vec<(syn::Ident, TypePath)>),
- Unnamed(Vec),
-}
-
-impl StructDef {
- pub fn from_variant(
- variant: &scale_info::Variant,
- type_gen: &TypeGenerator,
- ) -> Self {
- let name = format_ident!("{}", variant.name().to_camel_case());
- let variant_fields = variant
- .fields()
- .iter()
- .map(|field| {
- let name = field.name().map(|f| format_ident!("{}", f));
- let ty = type_gen.resolve_type_path(field.ty().id(), &[]);
- (name, ty)
- })
- .collect::>();
-
- let named = variant_fields.iter().all(|(name, _)| name.is_some());
- let unnamed = variant_fields.iter().all(|(name, _)| name.is_none());
-
- let fields = if named {
- StructDefFields::Named(
- variant_fields
- .iter()
- .map(|(name, field)| {
- let name = name.as_ref().unwrap_or_else(|| {
- abort_call_site!("All fields should have a name")
- });
- (name.clone(), field.clone())
- })
- .collect(),
- )
- } else if unnamed {
- StructDefFields::Unnamed(
- variant_fields
- .iter()
- .map(|(_, field)| field.clone())
- .collect(),
- )
- } else {
- abort_call_site!(
- "Variant '{}': Fields should either be all named or all unnamed.",
- variant.name()
- )
- };
-
- Self { name, fields }
- }
-
- fn named_fields(&self) -> Option<&[(syn::Ident, TypePath)]> {
- if let StructDefFields::Named(ref fields) = self.fields {
- Some(fields)
- } else {
- None
- }
- }
-}
-
-impl quote::ToTokens for StructDef {
- fn to_tokens(&self, tokens: &mut TokenStream2) {
- tokens.extend(match self.fields {
- StructDefFields::Named(ref named_fields) => {
- let fields = named_fields.iter().map(|(name, ty)| {
- let compact_attr =
- ty.is_compact().then(|| quote!( #[codec(compact)] ));
- quote! { #compact_attr pub #name: #ty }
- });
- let name = &self.name;
- quote! {
- #[derive(Debug, Eq, PartialEq, ::codec::Encode, ::codec::Decode)]
- pub struct #name {
- #( #fields ),*
- }
- }
- }
- StructDefFields::Unnamed(ref unnamed_fields) => {
- let fields = unnamed_fields.iter().map(|ty| {
- let compact_attr =
- ty.is_compact().then(|| quote!( #[codec(compact)] ));
- quote! { #compact_attr pub #ty }
- });
- let name = &self.name;
- quote! {
- #[derive(Debug, Eq, PartialEq, ::codec::Encode, ::codec::Decode)]
- pub struct #name (
- #( #fields ),*
- );
- }
- }
- })
- }
-}
diff --git a/codegen/src/lib.rs b/codegen/src/lib.rs
new file mode 100644
index 0000000000..32fec308c2
--- /dev/null
+++ b/codegen/src/lib.rs
@@ -0,0 +1,23 @@
+// Copyright 2019-2021 Parity Technologies (UK) Ltd.
+// This file is part of substrate-subxt.
+//
+// subxt is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// subxt is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with substrate-subxt. If not, see .
+
+//! Library to generate an API for a Substrate runtime from its metadata.
+
+mod api;
+mod struct_def;
+mod types;
+
+pub use self::api::generate_runtime_types;
diff --git a/codegen/src/struct_def.rs b/codegen/src/struct_def.rs
new file mode 100644
index 0000000000..5e90cc7c46
--- /dev/null
+++ b/codegen/src/struct_def.rs
@@ -0,0 +1,136 @@
+// Copyright 2019-2021 Parity Technologies (UK) Ltd.
+// This file is part of substrate-subxt.
+//
+// subxt is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// subxt is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with substrate-subxt. If not, see .
+
+use crate::types::{
+ TypeGenerator,
+ TypePath,
+};
+use heck::CamelCase as _;
+use proc_macro2::TokenStream as TokenStream2;
+use proc_macro_error::abort_call_site;
+use quote::{
+ format_ident,
+ quote,
+};
+use scale_info::form::PortableForm;
+
+#[derive(Debug)]
+pub struct StructDef {
+ pub name: syn::Ident,
+ pub fields: StructDefFields,
+ pub field_visibility: Option,
+}
+
+#[derive(Debug)]
+pub enum StructDefFields {
+ Named(Vec<(syn::Ident, TypePath)>),
+ Unnamed(Vec),
+}
+
+impl StructDef {
+ pub fn new(
+ ident: &str,
+ fields: &[scale_info::Field],
+ field_visibility: Option,
+ type_gen: &TypeGenerator,
+ ) -> Self {
+ let name = format_ident!("{}", ident.to_camel_case());
+ let fields = fields
+ .iter()
+ .map(|field| {
+ let name = field.name().map(|f| format_ident!("{}", f));
+ let ty = type_gen.resolve_type_path(field.ty().id(), &[]);
+ (name, ty)
+ })
+ .collect::>();
+
+ let named = fields.iter().all(|(name, _)| name.is_some());
+ let unnamed = fields.iter().all(|(name, _)| name.is_none());
+
+ let fields = if named {
+ StructDefFields::Named(
+ fields
+ .iter()
+ .map(|(name, field)| {
+ let name = name.as_ref().unwrap_or_else(|| {
+ abort_call_site!("All fields should have a name")
+ });
+ (name.clone(), field.clone())
+ })
+ .collect(),
+ )
+ } else if unnamed {
+ StructDefFields::Unnamed(
+ fields.iter().map(|(_, field)| field.clone()).collect(),
+ )
+ } else {
+ abort_call_site!(
+ "Struct '{}': Fields should either be all named or all unnamed.",
+ name,
+ )
+ };
+
+ Self {
+ name,
+ fields,
+ field_visibility,
+ }
+ }
+
+ pub fn named_fields(&self) -> Option<&[(syn::Ident, TypePath)]> {
+ if let StructDefFields::Named(ref fields) = self.fields {
+ Some(fields)
+ } else {
+ None
+ }
+ }
+}
+
+impl quote::ToTokens for StructDef {
+ fn to_tokens(&self, tokens: &mut TokenStream2) {
+ let visibility = &self.field_visibility;
+ tokens.extend(match self.fields {
+ StructDefFields::Named(ref named_fields) => {
+ let fields = named_fields.iter().map(|(name, ty)| {
+ let compact_attr =
+ ty.is_compact().then(|| quote!( #[codec(compact)] ));
+ quote! { #compact_attr #visibility #name: #ty }
+ });
+ let name = &self.name;
+ quote! {
+ #[derive(Debug, Eq, PartialEq, ::codec::Encode, ::codec::Decode)]
+ pub struct #name {
+ #( #fields ),*
+ }
+ }
+ }
+ StructDefFields::Unnamed(ref unnamed_fields) => {
+ let fields = unnamed_fields.iter().map(|ty| {
+ let compact_attr =
+ ty.is_compact().then(|| quote!( #[codec(compact)] ));
+ quote! { #compact_attr #visibility #ty }
+ });
+ let name = &self.name;
+ quote! {
+ #[derive(Debug, Eq, PartialEq, ::codec::Encode, ::codec::Decode)]
+ pub struct #name (
+ #( #fields ),*
+ );
+ }
+ }
+ })
+ }
+}
diff --git a/macro/src/generate_types.rs b/codegen/src/types.rs
similarity index 99%
rename from macro/src/generate_types.rs
rename to codegen/src/types.rs
index 4170ceec4b..4f10dffd0d 100644
--- a/macro/src/generate_types.rs
+++ b/codegen/src/types.rs
@@ -407,7 +407,7 @@ impl<'a> ModuleType<'a> {
if is_struct && !unused_params.is_empty() {
let phantom = Self::phantom_data(&unused_params);
fields_tokens.push(quote! {
- pub __chameleon_unused_type_params: #phantom
+ pub __subxt_unused_type_params: #phantom
})
}
@@ -1206,7 +1206,7 @@ mod tests {
#[derive(Debug, Eq, PartialEq, ::codec::Encode, ::codec::Decode)]
pub struct NamedFields<_0> {
pub b: u32,
- pub __chameleon_unused_type_params: ::core::marker::PhantomData<_0>,
+ pub __subxt_unused_type_params: ::core::marker::PhantomData<_0>,
}
#[derive(Debug, Eq, PartialEq, ::codec::Encode, ::codec::Decode)]
pub struct UnnamedFields<_0, _1> (
diff --git a/macro/Cargo.toml b/macro/Cargo.toml
index 3d7a1befa3..87b1522226 100644
--- a/macro/Cargo.toml
+++ b/macro/Cargo.toml
@@ -27,8 +27,9 @@ quote = "1.0.8"
syn = "1.0.58"
scale-info = "1.0.0"
+subxt-codegen = { version = "0.1.0", path = "../codegen" }
+
[dev-dependencies]
-codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"] }
pretty_assertions = "0.6.1"
substrate-subxt = { path = ".." }
trybuild = "1.0.38"
diff --git a/macro/src/lib.rs b/macro/src/lib.rs
index d25da219ec..69fb742573 100644
--- a/macro/src/lib.rs
+++ b/macro/src/lib.rs
@@ -16,16 +16,8 @@
extern crate proc_macro;
-mod generate_runtime;
-mod generate_types;
-
use darling::FromMeta;
-use generate_types::{
- TypeGenerator,
- TypePath,
-};
use proc_macro::TokenStream;
-use proc_macro2::TokenStream as TokenStream2;
use proc_macro_error::proc_macro_error;
use syn::parse_macro_input;
@@ -49,5 +41,5 @@ pub fn subxt(args: TokenStream, input: TokenStream) -> TokenStream {
let root_path = std::path::Path::new(&root);
let path = root_path.join(args.runtime_metadata_path);
- generate_runtime::generate_runtime_types(item_mod, &path).into()
+ subxt_codegen::generate_runtime_types(item_mod, &path).into()
}