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

Update to latest changes in scale-info #5

Merged
merged 7 commits into from
Aug 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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