Skip to content

Commit

Permalink
Merge pull request #2 from paritytech/aj-metadata-vnext
Browse files Browse the repository at this point in the history
Aj metadata vnext
  • Loading branch information
paulormart authored Oct 13, 2021
2 parents 5678fa9 + d0b0bb1 commit 6f413d2
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 125 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = [".", "macro", "tests"]
members = [".", "codegen", "macro", "tests"]

[package]
name = "substrate-subxt"
Expand Down
21 changes: 21 additions & 0 deletions codegen/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
124 changes: 12 additions & 112 deletions macro/src/generate_runtime.rs → codegen/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@
// along with substrate-subxt. If not, see <http://www.gnu.org/licenses/>.

use crate::{
TokenStream2,
TypeGenerator,
TypePath,
struct_def::StructDef,
types::TypeGenerator,
};
use codec::Decode;
use darling::FromMeta;
Expand All @@ -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,
Expand Down Expand Up @@ -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!(
Expand Down Expand Up @@ -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<TypePath>),
}

impl StructDef {
pub fn from_variant(
variant: &scale_info::Variant<PortableForm>,
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::<Vec<_>>();

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 ),*
);
}
}
})
}
}
23 changes: 23 additions & 0 deletions codegen/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.

//! 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;
136 changes: 136 additions & 0 deletions codegen/src/struct_def.rs
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.

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<syn::Visibility>,
}

#[derive(Debug)]
pub enum StructDefFields {
Named(Vec<(syn::Ident, TypePath)>),
Unnamed(Vec<TypePath>),
}

impl StructDef {
pub fn new(
ident: &str,
fields: &[scale_info::Field<PortableForm>],
field_visibility: Option<syn::Visibility>,
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::<Vec<_>>();

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 ),*
);
}
}
})
}
}
4 changes: 2 additions & 2 deletions macro/src/generate_types.rs → codegen/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
})
}

Expand Down Expand Up @@ -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> (
Expand Down
3 changes: 2 additions & 1 deletion macro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
10 changes: 1 addition & 9 deletions macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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()
}

0 comments on commit 6f413d2

Please sign in to comment.