Skip to content
This repository has been archived by the owner on Nov 1, 2021. It is now read-only.

Commit

Permalink
Update to latest changes in scale-info (#5)
Browse files Browse the repository at this point in the history
* Update to latest changes in scale-info

* Use cargo patch directive

* Formatting

* Support bitvec type

* Use root namespace

* Fix root module name

* Fix tests and bump dependencies
  • Loading branch information
montekki authored Aug 24, 2021
1 parent ee5ab4a commit 947521b
Show file tree
Hide file tree
Showing 6 changed files with 2,600 additions and 1,715 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ members = [
exclude = [
"examples/",
]

[patch.crates-io]
scale-info = { git = "https://github.com/montekki/scale-info", branch = "fs-add-type-id" }
14 changes: 11 additions & 3 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,29 @@ authors = ["Andrew Jones <[email protected]>"]
edition = "2018"

[dependencies]
frame-metadata = { package = "frame-metadata", git = "https://github.com/paritytech/frame-metadata", branch = "aj-substrate", default-features = false, features = ["v13"] }
bitvec = { version = "0.20.1", default-features = false, features = ["alloc"], optional = true }
frame-metadata = { package = "frame-metadata", git = "https://github.com/paritytech/frame-metadata", default-features = false, features = ["v14"] }
heck = "0.3.1"
proc-macro2 = "1.0"
quote = "1"
syn = { version = "1.0", features = ["parsing", "full"] }
scale = { package = "parity-scale-codec", version = "2.0", default-features = false}
scale-info = { git = "https://github.com/paritytech/scale-info", branch = "aj-substrate", default-features = false, features = ["derive", "decode"] }
scale-info = { version = "0.10.0", default-features = false, features = ["derive", "decode"] }

thiserror = "1.0.22"

[features]
default = ["std"]
default = ["std", "bit-vec"]
std = [
"bitvec/std",
"frame-metadata/std",
"scale/std",
"scale-info/std",
"scale-info/serde",
]

# enables type information for bitvec types
bit-vec = [
"bitvec",
"scale-info/bit-vec"
]
Binary file modified core/node-runtime.scale
Binary file not shown.
71 changes: 46 additions & 25 deletions core/src/generate_runtime.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
use crate::{TokenStream2, TypeGenerator};
use frame_metadata::{v13::RuntimeMetadataV13, RuntimeMetadata, RuntimeMetadataPrefixed};
use frame_metadata::{v14::RuntimeMetadataV14, RuntimeMetadata, RuntimeMetadataPrefixed};
use heck::SnakeCase as _;
use quote::{format_ident, quote};
use scale_info::prelude::string::ToString;

pub struct RuntimeGenerator {
metadata: RuntimeMetadataV13,
metadata: RuntimeMetadataV14,
}

impl RuntimeGenerator {
pub fn new(metadata: RuntimeMetadataPrefixed) -> Self {
match metadata.1 {
RuntimeMetadata::V13(v13) => Self { metadata: v13 },
RuntimeMetadata::V14(v14) => Self { metadata: v14 },
_ => panic!("Unsupported metadata version {:?}", metadata.1),
}
}
Expand All @@ -22,29 +22,50 @@ impl RuntimeGenerator {
let types_mod_ident = types_mod.ident();
let modules = self.metadata.pallets.iter().map(|pallet| {
let mod_name = format_ident!("{}", pallet.name.to_string().to_snake_case());
let calls = pallet
.calls
.as_ref()
.map_or(&Vec::new(), |call_metadata| &call_metadata.calls)
.iter()
.map(|call| {
use heck::CamelCase as _;
// todo: add free functions to Call mod and doc strings
let name = format_ident!("{}", call.name.to_string().to_camel_case());
let args = call.arguments.iter().map(|arg| {
let name = format_ident!("{}", arg.name);
let ty = type_gen.resolve_type_path(arg.ty.id(), &[]);
// todo: add docs and #[compact] attr
quote! { #name: #ty }
});
quote! {
#[derive(Debug, ::codec::Encode, ::codec::Decode)]
pub struct #name {
#( #args ),*
}
let mut calls = Vec::new();
for call in &pallet.calls {
let ty = call.ty;
let name = type_gen.resolve_type_path(ty.id(), &[]);
use crate::generate_types::TypePath;
match name {
TypePath::Parameter(_) => unreachable!(),
TypePath::Type(ref ty) => {
let ty = ty.ty();

let type_def = ty.type_def();

let c = match type_def {
scale_info::TypeDef::Variant(var) => var
.variants()
.iter()
.map(|var| {
use heck::CamelCase;
let name =
format_ident!("{}", var.name().to_string().to_camel_case());
let args = var.fields().iter().filter_map(|field| {
field.name().map(|name| {
let name = format_ident!("{}", name);
let ty =
type_gen.resolve_type_path(field.ty().id(), &[]);
quote! { #name: #ty }
})
});

quote! {
#[derive(Debug, ::codec::Encode, ::codec::Decode)]
pub struct #name {
#( #args ),*
}
}
})
.collect::<Vec<_>>(),
_ => unreachable!(),
};
calls.extend(c);
}
})
.collect::<Vec<_>>();
}
}

let event = if let Some(ref event) = pallet.event {
let event_type = type_gen.resolve_type_path(event.ty.id(), &[]);
quote! {
Expand Down
135 changes: 94 additions & 41 deletions core/src/generate_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@

use proc_macro2::{Ident, Span, TokenStream as TokenStream2, TokenStream};
use quote::{format_ident, quote, ToTokens};
use scale_info::{
form::PortableForm, prelude::num::NonZeroU32, Field, PortableRegistry, Type, TypeDef,
TypeDefPrimitive,
};
use scale_info::{form::PortableForm, Field, PortableRegistry, Type, TypeDef, TypeDefPrimitive};
use std::collections::{BTreeMap, HashSet};

#[derive(Debug)]
Expand All @@ -40,15 +37,15 @@ impl<'a> TypeGenerator<'a> {
pub fn generate_types_mod(&'a self) -> Module<'a> {
let mut root_mod = Module::new(self.root_mod_ident.clone(), self.root_mod_ident.clone());

for (id, ty) in self.type_registry.enumerate() {
if ty.path().namespace().is_empty() {
for (id, ty) in self.type_registry.types().iter().enumerate() {
if ty.ty().path().namespace().is_empty() {
// prelude types e.g. Option/Result have no namespace, so we don't generate them
continue;
}
self.insert_type(
ty.clone(),
id,
ty.path().namespace().to_vec(),
ty.ty().clone(),
id as u32,
ty.ty().path().namespace().to_vec(),
&self.root_mod_ident,
&mut root_mod,
)
Expand All @@ -60,7 +57,7 @@ impl<'a> TypeGenerator<'a> {
fn insert_type(
&'a self,
ty: Type<PortableForm>,
id: NonZeroU32,
id: u32,
path: Vec<String>,
root_mod_ident: &Ident,
module: &mut Module<'a>,
Expand All @@ -85,11 +82,7 @@ impl<'a> TypeGenerator<'a> {
/// # Panics
///
/// If no type with the given id found in the type registry.
pub fn resolve_type_path(
&self,
id: NonZeroU32,
parent_type_params: &[TypeParameter],
) -> TypePath {
pub fn resolve_type_path(&self, id: u32, parent_type_params: &[TypeParameter]) -> TypePath {
if let Some(parent_type_param) = parent_type_params
.iter()
.find(|tp| tp.concrete_type_id == id)
Expand All @@ -106,16 +99,25 @@ impl<'a> TypeGenerator<'a> {

let mut ty = resolve_type(id);
if ty.path().ident() == Some("Cow".to_string()) {
ty = resolve_type(ty.type_params()[0].id())
ty = resolve_type(
ty.type_params()[0]
.ty()
.expect("type parameters to Cow are not expected to be skipped; qed")
.id(),
)
}

let params_type_ids = match ty.type_def() {
TypeDef::Array(arr) => vec![arr.type_param().id()],
TypeDef::Sequence(seq) => vec![seq.type_param().id()],
TypeDef::Tuple(tuple) => tuple.fields().iter().map(|f| f.id()).collect(),
TypeDef::Compact(compact) => vec![compact.type_param().id()],
TypeDef::Phantom(phantom) => vec![phantom.type_param().id()],
_ => ty.type_params().iter().map(|f| f.id()).collect(),
TypeDef::BitSequence(seq) => vec![seq.bit_order_type().id(), seq.bit_store_type().id()],
_ => ty
.type_params()
.iter()
.filter_map(|f| f.ty().map(|f| f.id()))
.collect(),
};

let params = params_type_ids
Expand Down Expand Up @@ -198,12 +200,15 @@ impl<'a> quote::ToTokens for ModuleType<'a> {
.type_params()
.iter()
.enumerate()
.map(|(i, tp)| {
let tp_name = format_ident!("_{}", i);
TypeParameter {
concrete_type_id: tp.id(),
name: tp_name,
.filter_map(|(i, tp)| match tp.ty() {
Some(ty) => {
let tp_name = format_ident!("_{}", i);
Some(TypeParameter {
concrete_type_id: ty.id(),
name: tp_name,
})
}
None => None,
})
.collect::<Vec<_>>();

Expand Down Expand Up @@ -327,11 +332,12 @@ impl<'a> ModuleType<'a> {

let mut fields_tokens = fields
.iter()
.map(|(name, ty, ty_name)| {
let ty = ty_toks(ty_name, ty);
if is_struct {
.map(|(name, ty, ty_name)| match ty_name {
Some(ty_name) if is_struct => {
let ty = ty_toks(ty_name, ty);
quote! { pub #name: #ty }
} else {
}
_ => {
quote! { #name: #ty }
}
})
Expand Down Expand Up @@ -363,11 +369,12 @@ impl<'a> ModuleType<'a> {
.collect::<Vec<_>>();
let mut fields_tokens = type_paths
.iter()
.map(|(ty, ty_name)| {
let ty = ty_toks(ty_name, ty);
if is_struct {
.map(|(ty, ty_name)| match ty_name {
Some(ty_name) if is_struct => {
let ty = ty_toks(ty_name, ty);
quote! { pub #ty }
} else {
}
_ => {
quote! { #ty }
}
})
Expand Down Expand Up @@ -410,7 +417,7 @@ impl quote::ToTokens for TypePath {
}

impl TypePath {
fn to_syn_type(&self) -> syn::Type {
pub(crate) fn to_syn_type(&self) -> syn::Type {
match self {
TypePath::Parameter(ty_param) => syn::Type::Path(syn::parse_quote! { #ty_param }),
TypePath::Type(ty) => ty.to_syn_type(),
Expand Down Expand Up @@ -444,6 +451,10 @@ pub struct TypePathType {
}

impl TypePathType {
pub(crate) fn ty(&self) -> &Type<PortableForm> {
&self.ty
}

fn to_syn_type(&self) -> syn::Type {
let params = &self.params;
match self.ty.type_def() {
Expand Down Expand Up @@ -505,20 +516,23 @@ impl TypePathType {
let path = syn::parse_quote! { #ident };
syn::Type::Path(path)
}
TypeDef::Phantom(_) => {
let type_param = params
.iter()
.next()
.expect("a phantom type should have a single type parameter");
let type_path = syn::parse_quote! { core::marker::PhantomData<#type_param> };
syn::Type::Path(type_path)
}
TypeDef::Compact(_) => {
// todo: change the return type of this method to include info that it is compact
// and should be annotated with #[compact] for fields
let compact_type = &self.params[0];
syn::Type::Path(syn::parse_quote! ( #compact_type ))
}
TypeDef::BitSequence(_) => {
let bit_order_type = &self.params[0];
let bit_store_type = &self.params[1];

let mut type_path: syn::punctuated::Punctuated<syn::PathSegment, syn::Token![::]> =
syn::parse_quote! { bitvec::vec::BitVec<#bit_order_type, #bit_store_type> };
type_path.insert(0, syn::PathSegment::from(self.root_mod_ident.clone()));
let type_path = syn::parse_quote! { #type_path };

syn::Type::Path(type_path)
}
}
}

Expand All @@ -540,7 +554,7 @@ impl TypePathType {

#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct TypeParameter {
concrete_type_id: NonZeroU32,
concrete_type_id: u32,
name: proc_macro2::Ident,
}

Expand Down Expand Up @@ -896,6 +910,45 @@ mod tests {
)
}

#[cfg(feature = "bit-vec")]
#[test]
fn generate_bitvec() {
use bitvec::{
order::{Lsb0, Msb0},
vec::BitVec,
};

#[allow(unused)]
#[derive(TypeInfo)]
struct S {
lsb: BitVec<Lsb0, u8>,
msb: BitVec<Msb0, u16>,
}

let mut registry = Registry::new();
registry.register_type(&meta_type::<S>());
let portable_types: PortableRegistry = registry.into();

let type_gen = TypeGenerator::new(&portable_types, "root");
let types = type_gen.generate_types_mod();
let tests_mod = types.get_mod(MOD_PATH).unwrap();

assert_eq!(
tests_mod.into_token_stream().to_string(),
quote! {
pub mod tests {
use super::root;
#[derive(Debug, ::codec::Encode, ::codec::Decode)]
pub struct S {
pub lsb: root::bitvec::vec::BitVec<root::bitvec::order::Lsb0, u8>,
pub msb: root::bitvec::vec::BitVec<root::bitvec::order::Msb0, u16>,
}
}
}
.to_string()
)
}

#[test]
fn generics_with_alias_adds_phantom_data_marker() {
trait Trait {
Expand Down
Loading

0 comments on commit 947521b

Please sign in to comment.