From 7390e7d033e06e4ce4826a8bd96886ff1a1e2447 Mon Sep 17 00:00:00 2001 From: ascjones Date: Mon, 12 Sep 2022 17:41:54 +0100 Subject: [PATCH 01/11] Add failing test for compact generic parameter --- codegen/src/types/tests.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/codegen/src/types/tests.rs b/codegen/src/types/tests.rs index c789bbab50..95b73d62ca 100644 --- a/codegen/src/types/tests.rs +++ b/codegen/src/types/tests.rs @@ -371,6 +371,44 @@ fn compact_fields() { ) } +#[test] +fn compact_generic_parameter() { + #[allow(unused)] + #[derive(TypeInfo)] + struct S { + a: Option<::Type>, + } + + let mut registry = Registry::new(); + registry.register_type(&meta_type::()); + let portable_types: PortableRegistry = registry.into(); + + let type_gen = TypeGenerator::new( + &portable_types, + "root", + Default::default(), + Default::default(), + ); + let types = type_gen.generate_types_mod(); + let tests_mod = get_mod(&types, MOD_PATH).unwrap(); + + assert_eq!( + tests_mod.into_token_stream().to_string(), + quote! { + pub mod tests { + use super::root; + + #[derive(::subxt::ext::codec::Decode, ::subxt::ext::codec::Encode, Debug)] + pub struct S { + pub a: ::core::Option<::subxt::ext::codec::Compact<::core::primitive::u128>>, + } + } + } + .to_string() + ) +} + + #[test] fn generate_array_field() { #[allow(unused)] From 42c6b36573fd5b80f1f90b3fdd129c1148c93ca5 Mon Sep 17 00:00:00 2001 From: ascjones Date: Tue, 13 Sep 2022 14:09:23 +0100 Subject: [PATCH 02/11] WIP refactor type generation --- codegen/src/types/mod.rs | 85 +++++++++------ codegen/src/types/type_path.rs | 189 +++++++++++++-------------------- 2 files changed, 128 insertions(+), 146 deletions(-) diff --git a/codegen/src/types/mod.rs b/codegen/src/types/mod.rs index 68c7d999db..3104b698fe 100644 --- a/codegen/src/types/mod.rs +++ b/codegen/src/types/mod.rs @@ -46,8 +46,8 @@ pub use self::{ type_path::{ TypeParameter, TypePath, - TypePathSubstitute, TypePathType, + TypePathTypeKind, }, }; @@ -171,40 +171,59 @@ impl<'a> TypeGenerator<'a> { ) } - 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::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 + let params = ty.type_params() .iter() - .map(|tp| self.resolve_type_path(*tp, parent_type_params)) - .collect::>(); + .filter_map(|f| f.ty().map(|f| self.resolve_type_path(f.id(), parent_type_params))) + .collect(); - let joined_path = ty.path().segments().join("::"); - if let Some(substitute_type_path) = self.type_substitutes.get(&joined_path) { - TypePath::Substitute(TypePathSubstitute { - path: substitute_type_path.clone(), - params, - }) - } else { - TypePath::Type(TypePathType { - ty, - params, - root_mod_ident: self.types_mod_ident.clone(), - }) - } + let kind = + match ty.type_def() { + TypeDef::Composite(_) | TypeDef::Variant(_) => { + let joined_path = ty.path().segments().join("::"); + if let Some(substitute_type_path) = self.type_substitutes.get(&joined_path) { + TypePathTypeKind::Path { + path: substitute_type_path.clone(), + params + } + } else { + TypePathTypeKind::from_type_def_path(ty.path(), self.types_mod_ident.clone(), params) + } + }, + TypeDef::Array(arr) => { + TypePathTypeKind::Array { + len: arr.len() as usize, + of: Box::new(self.resolve_type_path(arr.type_param().id(), parent_type_params)), + } + }, + TypeDef::Sequence(seq) => { + TypePathTypeKind::Vec { + of: Box::new(self.resolve_type_path(seq.type_param().id(), parent_type_params)), + } + }, + TypeDef::Tuple(tuple) => { + TypePathTypeKind::Tuple { + elements: tuple.fields().iter().map(|f| + self.resolve_type_path(f.id(), parent_type_params)).collect() + } + }, + TypeDef::Compact(compact) => { + TypePathTypeKind::Compact { + inner: Box::new(self.resolve_type_path(compact.type_param().id(), parent_type_params)), + is_field: false, // todo + } + }, + TypeDef::BitSequence(bitseq) => { + TypePathTypeKind::BitVec { + bit_order_type: Box::new(self.resolve_type_path(bitseq.bit_order_type().id(), parent_type_params)), + bit_store_type: Box::new(self.resolve_type_path(bitseq.bit_store_type().id(), parent_type_params)) + } + } + }; + + TypePath::Type(TypePathType { + kind, + root_mod_ident: self.types_mod_ident.clone(), + }) } /// Returns the derives to be applied to all generated types. diff --git a/codegen/src/types/type_path.rs b/codegen/src/types/type_path.rs index 646a18ad2c..47b81b9731 100644 --- a/codegen/src/types/type_path.rs +++ b/codegen/src/types/type_path.rs @@ -10,12 +10,7 @@ use quote::{ format_ident, quote, }; -use scale_info::{ - form::PortableForm, - Type, - TypeDef, - TypeDefPrimitive, -}; +use scale_info::{form::PortableForm, Path, Type, TypeDef, TypeDefPrimitive}; use std::collections::BTreeSet; use syn::parse_quote; @@ -23,7 +18,6 @@ use syn::parse_quote; pub enum TypePath { Parameter(TypeParameter), Type(TypePathType), - Substitute(TypePathSubstitute), } impl quote::ToTokens for TypePath { @@ -38,7 +32,6 @@ impl TypePath { match self { TypePath::Parameter(ty_param) => syn::Type::Path(parse_quote! { #ty_param }), TypePath::Type(ty) => ty.to_syn_type(), - TypePath::Substitute(sub) => sub.to_syn_type(), } } @@ -61,7 +54,6 @@ impl TypePath { acc.insert(type_parameter.clone()); } Self::Type(type_path) => type_path.parent_type_params(acc), - Self::Substitute(sub) => sub.parent_type_params(acc), } } @@ -74,8 +66,8 @@ impl TypePath { _ => return None, }; - match ty.ty.type_def() { - TypeDef::Sequence(_) => Some(&ty.params[0]), + match ty.kind { + TypePathTypeKind::Vec { ref of } => Some(of), _ => None, } } @@ -83,79 +75,39 @@ impl TypePath { #[derive(Clone, Debug)] pub struct TypePathType { - pub(super) ty: Type, - pub(super) params: Vec, + pub(super) kind: TypePathTypeKind, pub(super) root_mod_ident: Ident, } impl TypePathType { pub(crate) fn is_compact(&self) -> bool { - matches!(self.ty.type_def(), TypeDef::Compact(_)) + matches!(self.kind, TypePathTypeKind::Compact { .. }) } fn to_syn_type(&self) -> syn::Type { - let params = &self.params; - match self.ty.type_def() { - TypeDef::Composite(_) | TypeDef::Variant(_) => { - let path_segments = self.ty.path().segments(); - - let ty_path: syn::TypePath = match path_segments { - [] => panic!("Type has no ident"), - [ident] => { - // paths to prelude types - match ident.as_str() { - "Option" => parse_quote!(::core::option::Option), - "Result" => parse_quote!(::core::result::Result), - "Cow" => parse_quote!(::std::borrow::Cow), - "BTreeMap" => parse_quote!(::std::collections::BTreeMap), - "BTreeSet" => parse_quote!(::std::collections::BTreeSet), - "Range" => parse_quote!(::core::ops::Range), - "RangeInclusive" => parse_quote!(::core::ops::RangeInclusive), - ident => panic!("Unknown prelude type '{}'", ident), - } - } - _ => { - // paths to generated types in the root types module - let mut ty_path = path_segments - .iter() - .map(|s| syn::PathSegment::from(format_ident!("{}", s))) - .collect::>(); - ty_path.insert( - 0, - syn::PathSegment::from(self.root_mod_ident.clone()), - ); - parse_quote!( #ty_path ) - } - }; - - let params = &self.params; + match &self.kind { + TypePathTypeKind::Path { path, params } => { let path = if params.is_empty() { - parse_quote! { #ty_path } + parse_quote! { #path } } else { - parse_quote! { #ty_path< #( #params ),* > } + parse_quote! { #path< #( #params ),* > } }; syn::Type::Path(path) } - TypeDef::Sequence(_) => { - let type_param = &self.params[0]; - let type_path = parse_quote! { ::std::vec::Vec<#type_param> }; + TypePathTypeKind::Vec { of } => { + let type_path = parse_quote! { ::std::vec::Vec<#of> }; syn::Type::Path(type_path) } - TypeDef::Array(array) => { - let array_type = &self.params[0]; - let array_len = array.len() as usize; - let array = parse_quote! { [#array_type; #array_len] }; + TypePathTypeKind::Array { len, of } => { + let array = parse_quote! { [#of; #len] }; syn::Type::Array(array) } - TypeDef::Tuple(_) => { - let tuple = parse_quote! { (#( # params, )* ) }; + TypePathTypeKind::Tuple { elements } => { + let tuple = parse_quote! { (#( # elements, )* ) }; syn::Type::Tuple(tuple) } - TypeDef::Primitive(primitive) => { - let path = match primitive { + TypePathTypeKind::Primitive { def } => { + syn::Type::Path(match def { TypeDefPrimitive::Bool => parse_quote!(::core::primitive::bool), TypeDefPrimitive::Char => parse_quote!(::core::primitive::char), TypeDefPrimitive::Str => parse_quote!(::std::string::String), @@ -171,19 +123,18 @@ impl TypePathType { TypeDefPrimitive::I64 => parse_quote!(::core::primitive::i64), TypeDefPrimitive::I128 => parse_quote!(::core::primitive::i128), TypeDefPrimitive::I256 => unimplemented!("not a rust primitive"), + }) + } + TypePathTypeKind::Compact { inner, is_field } => { + let path = if *is_field { + parse_quote! ( #inner ) + } else { + parse_quote! ( ::subxt::ext::codec::Compact<#inner> ) }; syn::Type::Path(path) } - TypeDef::Compact(_) => { - let compact_type = &self.params[0]; - parse_quote! ( #compact_type ) - } - TypeDef::BitSequence(_) => { - let bit_order_type = &self.params[0]; - let bit_store_type = &self.params[1]; - + TypePathTypeKind::BitVec { bit_order_type, bit_store_type } => { let type_path = parse_quote! { ::subxt::ext::bitvec::vec::BitVec<#bit_store_type, #bit_order_type> }; - syn::Type::Path(type_path) } } @@ -205,11 +156,61 @@ impl TypePathType { } } +#[derive(Clone, Debug)] +pub enum TypePathTypeKind { + Path { path: syn::TypePath, params: Vec }, + Vec { of: Box }, + Array { len: usize, of: Box }, + Tuple { elements: Vec }, + Primitive { def: TypeDefPrimitive }, + Compact { inner: Box, is_field: bool }, + BitVec { bit_order_type: Box, bit_store_type: Box } +} + +impl TypePathTypeKind { + pub fn from_type_def_path(path: &Path, root_mod_ident: Ident, params: Vec) -> Self { + let path_segments = path.segments(); + + let path: syn::TypePath = match path_segments { + [] => panic!("Type has no ident"), + [ident] => { + // paths to prelude types + match ident.as_str() { + "Option" => parse_quote!(::core::option::Option), + "Result" => parse_quote!(::core::result::Result), + "Cow" => parse_quote!(::std::borrow::Cow), + "BTreeMap" => parse_quote!(::std::collections::BTreeMap), + "BTreeSet" => parse_quote!(::std::collections::BTreeSet), + "Range" => parse_quote!(::core::ops::Range), + "RangeInclusive" => parse_quote!(::core::ops::RangeInclusive), + ident => panic!("Unknown prelude type '{}'", ident), + } + } + _ => { + // paths to generated types in the root types module + let mut ty_path = path_segments + .iter() + .map(|s| syn::PathSegment::from(format_ident!("{}", s))) + .collect::>(); + ty_path.insert( + 0, + syn::PathSegment::from(root_mod_ident), + ); + parse_quote!( #ty_path ) + } + }; + Self::Path { path, params } + } +} + #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct TypeParameter { pub(super) concrete_type_id: u32, pub(super) original_name: String, - pub(super) name: proc_macro2::Ident, + pub(super) name: Ident, } impl quote::ToTokens for TypeParameter { @@ -217,41 +218,3 @@ impl quote::ToTokens for TypeParameter { self.name.to_tokens(tokens) } } - -#[derive(Clone, Debug)] -pub struct TypePathSubstitute { - pub(super) path: syn::TypePath, - pub(super) params: Vec, -} - -impl quote::ToTokens for TypePathSubstitute { - fn to_tokens(&self, tokens: &mut TokenStream) { - if self.params.is_empty() { - self.path.to_tokens(tokens) - } else { - let substitute_path = &self.path; - let params = &self.params; - tokens.extend(quote! { - #substitute_path< #( #params ),* > - }) - } - } -} - -impl TypePathSubstitute { - fn parent_type_params(&self, acc: &mut BTreeSet) { - for p in &self.params { - p.parent_type_params(acc); - } - } - - fn to_syn_type(&self) -> syn::Type { - if self.params.is_empty() { - syn::Type::Path(self.path.clone()) - } else { - let substitute_path = &self.path; - let params = &self.params; - parse_quote! ( #substitute_path< #( #params ),* > ) - } - } -} From c5e3032e30826fa61e772b06a81251103302348d Mon Sep 17 00:00:00 2001 From: ascjones Date: Tue, 13 Sep 2022 14:10:17 +0100 Subject: [PATCH 03/11] Fmt --- codegen/src/types/mod.rs | 111 ++++++++++++++++++++------------- codegen/src/types/tests.rs | 1 - codegen/src/types/type_path.rs | 56 ++++++++++++----- 3 files changed, 110 insertions(+), 58 deletions(-) diff --git a/codegen/src/types/mod.rs b/codegen/src/types/mod.rs index 3104b698fe..67fe1c9322 100644 --- a/codegen/src/types/mod.rs +++ b/codegen/src/types/mod.rs @@ -171,54 +171,79 @@ impl<'a> TypeGenerator<'a> { ) } - let params = ty.type_params() + let params = ty + .type_params() .iter() - .filter_map(|f| f.ty().map(|f| self.resolve_type_path(f.id(), parent_type_params))) + .filter_map(|f| { + f.ty() + .map(|f| self.resolve_type_path(f.id(), parent_type_params)) + }) .collect(); - let kind = - match ty.type_def() { - TypeDef::Composite(_) | TypeDef::Variant(_) => { - let joined_path = ty.path().segments().join("::"); - if let Some(substitute_type_path) = self.type_substitutes.get(&joined_path) { - TypePathTypeKind::Path { - path: substitute_type_path.clone(), - params - } - } else { - TypePathTypeKind::from_type_def_path(ty.path(), self.types_mod_ident.clone(), params) - } - }, - TypeDef::Array(arr) => { - TypePathTypeKind::Array { - len: arr.len() as usize, - of: Box::new(self.resolve_type_path(arr.type_param().id(), parent_type_params)), - } - }, - TypeDef::Sequence(seq) => { - TypePathTypeKind::Vec { - of: Box::new(self.resolve_type_path(seq.type_param().id(), parent_type_params)), - } - }, - TypeDef::Tuple(tuple) => { - TypePathTypeKind::Tuple { - elements: tuple.fields().iter().map(|f| - self.resolve_type_path(f.id(), parent_type_params)).collect() - } - }, - TypeDef::Compact(compact) => { - TypePathTypeKind::Compact { - inner: Box::new(self.resolve_type_path(compact.type_param().id(), parent_type_params)), - is_field: false, // todo - } - }, - TypeDef::BitSequence(bitseq) => { - TypePathTypeKind::BitVec { - bit_order_type: Box::new(self.resolve_type_path(bitseq.bit_order_type().id(), parent_type_params)), - bit_store_type: Box::new(self.resolve_type_path(bitseq.bit_store_type().id(), parent_type_params)) + let kind = match ty.type_def() { + TypeDef::Composite(_) | TypeDef::Variant(_) => { + let joined_path = ty.path().segments().join("::"); + if let Some(substitute_type_path) = + self.type_substitutes.get(&joined_path) + { + TypePathTypeKind::Path { + path: substitute_type_path.clone(), + params, } + } else { + TypePathTypeKind::from_type_def_path( + ty.path(), + self.types_mod_ident.clone(), + params, + ) + } + } + TypeDef::Array(arr) => { + TypePathTypeKind::Array { + len: arr.len() as usize, + of: Box::new( + self.resolve_type_path(arr.type_param().id(), parent_type_params), + ), + } + } + TypeDef::Sequence(seq) => { + TypePathTypeKind::Vec { + of: Box::new( + self.resolve_type_path(seq.type_param().id(), parent_type_params), + ), + } + } + TypeDef::Tuple(tuple) => { + TypePathTypeKind::Tuple { + elements: tuple + .fields() + .iter() + .map(|f| self.resolve_type_path(f.id(), parent_type_params)) + .collect(), + } + } + TypeDef::Compact(compact) => { + TypePathTypeKind::Compact { + inner: Box::new(self.resolve_type_path( + compact.type_param().id(), + parent_type_params, + )), + is_field: false, // todo + } + } + TypeDef::BitSequence(bitseq) => { + TypePathTypeKind::BitVec { + bit_order_type: Box::new(self.resolve_type_path( + bitseq.bit_order_type().id(), + parent_type_params, + )), + bit_store_type: Box::new(self.resolve_type_path( + bitseq.bit_store_type().id(), + parent_type_params, + )), } - }; + } + }; TypePath::Type(TypePathType { kind, diff --git a/codegen/src/types/tests.rs b/codegen/src/types/tests.rs index 95b73d62ca..7b22fdb8cf 100644 --- a/codegen/src/types/tests.rs +++ b/codegen/src/types/tests.rs @@ -408,7 +408,6 @@ fn compact_generic_parameter() { ) } - #[test] fn generate_array_field() { #[allow(unused)] diff --git a/codegen/src/types/type_path.rs b/codegen/src/types/type_path.rs index 47b81b9731..2f558fa8d2 100644 --- a/codegen/src/types/type_path.rs +++ b/codegen/src/types/type_path.rs @@ -10,7 +10,13 @@ use quote::{ format_ident, quote, }; -use scale_info::{form::PortableForm, Path, Type, TypeDef, TypeDefPrimitive}; +use scale_info::{ + form::PortableForm, + Path, + Type, + TypeDef, + TypeDefPrimitive, +}; use std::collections::BTreeSet; use syn::parse_quote; @@ -133,7 +139,10 @@ impl TypePathType { }; syn::Type::Path(path) } - TypePathTypeKind::BitVec { bit_order_type, bit_store_type } => { + TypePathTypeKind::BitVec { + bit_order_type, + bit_store_type, + } => { let type_path = parse_quote! { ::subxt::ext::bitvec::vec::BitVec<#bit_store_type, #bit_order_type> }; syn::Type::Path(type_path) } @@ -158,17 +167,39 @@ impl TypePathType { #[derive(Clone, Debug)] pub enum TypePathTypeKind { - Path { path: syn::TypePath, params: Vec }, - Vec { of: Box }, - Array { len: usize, of: Box }, - Tuple { elements: Vec }, - Primitive { def: TypeDefPrimitive }, - Compact { inner: Box, is_field: bool }, - BitVec { bit_order_type: Box, bit_store_type: Box } + Path { + path: syn::TypePath, + params: Vec, + }, + Vec { + of: Box, + }, + Array { + len: usize, + of: Box, + }, + Tuple { + elements: Vec, + }, + Primitive { + def: TypeDefPrimitive, + }, + Compact { + inner: Box, + is_field: bool, + }, + BitVec { + bit_order_type: Box, + bit_store_type: Box, + }, } impl TypePathTypeKind { - pub fn from_type_def_path(path: &Path, root_mod_ident: Ident, params: Vec) -> Self { + pub fn from_type_def_path( + path: &Path, + root_mod_ident: Ident, + params: Vec, + ) -> Self { let path_segments = path.segments(); let path: syn::TypePath = match path_segments { @@ -195,10 +226,7 @@ impl TypePathTypeKind { syn::PathSegment, syn::Token![::], >>(); - ty_path.insert( - 0, - syn::PathSegment::from(root_mod_ident), - ); + ty_path.insert(0, syn::PathSegment::from(root_mod_ident)); parse_quote!( #ty_path ) } }; From 1dade4e1560987f0803e6801b36a8487afc4d586 Mon Sep 17 00:00:00 2001 From: ascjones Date: Tue, 13 Sep 2022 14:11:01 +0100 Subject: [PATCH 04/11] Remove deprecated rustfmt optionns --- .rustfmt.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.rustfmt.toml b/.rustfmt.toml index 82af150637..a370fc8b5c 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -57,8 +57,6 @@ skip_children = false hide_parse_errors = false error_on_line_overflow = false error_on_unformatted = false -report_todo = "Always" -report_fixme = "Always" ignore = [] # Below are `rustfmt` internal settings From ee3747d2db1bcc2ca34aa0ceaa35a78d6bc60f1f Mon Sep 17 00:00:00 2001 From: ascjones Date: Wed, 14 Sep 2022 09:59:34 +0100 Subject: [PATCH 05/11] Remove license template path --- .rustfmt.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/.rustfmt.toml b/.rustfmt.toml index a370fc8b5c..536703e6b3 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -9,7 +9,6 @@ format_code_in_doc_comments = false comment_width = 80 normalize_comments = true # changed normalize_doc_attributes = false -license_template_path = "FILE_TEMPLATE" # changed format_strings = false format_macro_matchers = false format_macro_bodies = true From 766e5d92b9e7a7215174147174d22a75029606b8 Mon Sep 17 00:00:00 2001 From: ascjones Date: Wed, 14 Sep 2022 10:05:26 +0100 Subject: [PATCH 06/11] Update parent type parameter visitor --- codegen/src/types/mod.rs | 27 ++--- codegen/src/types/tests.rs | 2 +- codegen/src/types/type_path.rs | 199 +++++++++++++++++---------------- 3 files changed, 118 insertions(+), 110 deletions(-) diff --git a/codegen/src/types/mod.rs b/codegen/src/types/mod.rs index 67fe1c9322..c93bde9faf 100644 --- a/codegen/src/types/mod.rs +++ b/codegen/src/types/mod.rs @@ -47,7 +47,6 @@ pub use self::{ TypeParameter, TypePath, TypePathType, - TypePathTypeKind, }, }; @@ -180,26 +179,31 @@ impl<'a> TypeGenerator<'a> { }) .collect(); - let kind = match ty.type_def() { + let ty = match ty.type_def() { TypeDef::Composite(_) | TypeDef::Variant(_) => { let joined_path = ty.path().segments().join("::"); if let Some(substitute_type_path) = self.type_substitutes.get(&joined_path) { - TypePathTypeKind::Path { + TypePathType::Path { path: substitute_type_path.clone(), params, } } else { - TypePathTypeKind::from_type_def_path( + TypePathType::from_type_def_path( ty.path(), self.types_mod_ident.clone(), params, ) } } + TypeDef::Primitive(primitive) => { + TypePathType::Primitive { + def: primitive.clone(), + } + } TypeDef::Array(arr) => { - TypePathTypeKind::Array { + TypePathType::Array { len: arr.len() as usize, of: Box::new( self.resolve_type_path(arr.type_param().id(), parent_type_params), @@ -207,14 +211,14 @@ impl<'a> TypeGenerator<'a> { } } TypeDef::Sequence(seq) => { - TypePathTypeKind::Vec { + TypePathType::Vec { of: Box::new( self.resolve_type_path(seq.type_param().id(), parent_type_params), ), } } TypeDef::Tuple(tuple) => { - TypePathTypeKind::Tuple { + TypePathType::Tuple { elements: tuple .fields() .iter() @@ -223,7 +227,7 @@ impl<'a> TypeGenerator<'a> { } } TypeDef::Compact(compact) => { - TypePathTypeKind::Compact { + TypePathType::Compact { inner: Box::new(self.resolve_type_path( compact.type_param().id(), parent_type_params, @@ -232,7 +236,7 @@ impl<'a> TypeGenerator<'a> { } } TypeDef::BitSequence(bitseq) => { - TypePathTypeKind::BitVec { + TypePathType::BitVec { bit_order_type: Box::new(self.resolve_type_path( bitseq.bit_order_type().id(), parent_type_params, @@ -245,10 +249,7 @@ impl<'a> TypeGenerator<'a> { } }; - TypePath::Type(TypePathType { - kind, - root_mod_ident: self.types_mod_ident.clone(), - }) + TypePath::Type(ty) } /// Returns the derives to be applied to all generated types. diff --git a/codegen/src/types/tests.rs b/codegen/src/types/tests.rs index 7b22fdb8cf..d17a356d29 100644 --- a/codegen/src/types/tests.rs +++ b/codegen/src/types/tests.rs @@ -400,7 +400,7 @@ fn compact_generic_parameter() { #[derive(::subxt::ext::codec::Decode, ::subxt::ext::codec::Encode, Debug)] pub struct S { - pub a: ::core::Option<::subxt::ext::codec::Compact<::core::primitive::u128>>, + pub a: ::core::option::Option<::subxt::ext::codec::Compact<::core::primitive::u128> >, } } } diff --git a/codegen/src/types/type_path.rs b/codegen/src/types/type_path.rs index 2f558fa8d2..1326f6b5bc 100644 --- a/codegen/src/types/type_path.rs +++ b/codegen/src/types/type_path.rs @@ -6,15 +6,10 @@ use proc_macro2::{ Ident, TokenStream, }; -use quote::{ - format_ident, - quote, -}; +use quote::format_ident; use scale_info::{ form::PortableForm, Path, - Type, - TypeDef, TypeDefPrimitive, }; use std::collections::BTreeSet; @@ -72,101 +67,15 @@ impl TypePath { _ => return None, }; - match ty.kind { - TypePathTypeKind::Vec { ref of } => Some(of), + match ty { + TypePathType::Vec { ref of } => Some(of), _ => None, } } } #[derive(Clone, Debug)] -pub struct TypePathType { - pub(super) kind: TypePathTypeKind, - pub(super) root_mod_ident: Ident, -} - -impl TypePathType { - pub(crate) fn is_compact(&self) -> bool { - matches!(self.kind, TypePathTypeKind::Compact { .. }) - } - - fn to_syn_type(&self) -> syn::Type { - match &self.kind { - TypePathTypeKind::Path { path, params } => { - let path = if params.is_empty() { - parse_quote! { #path } - } else { - parse_quote! { #path< #( #params ),* > } - }; - syn::Type::Path(path) - } - TypePathTypeKind::Vec { of } => { - let type_path = parse_quote! { ::std::vec::Vec<#of> }; - syn::Type::Path(type_path) - } - TypePathTypeKind::Array { len, of } => { - let array = parse_quote! { [#of; #len] }; - syn::Type::Array(array) - } - TypePathTypeKind::Tuple { elements } => { - let tuple = parse_quote! { (#( # elements, )* ) }; - syn::Type::Tuple(tuple) - } - TypePathTypeKind::Primitive { def } => { - syn::Type::Path(match def { - TypeDefPrimitive::Bool => parse_quote!(::core::primitive::bool), - TypeDefPrimitive::Char => parse_quote!(::core::primitive::char), - TypeDefPrimitive::Str => parse_quote!(::std::string::String), - TypeDefPrimitive::U8 => parse_quote!(::core::primitive::u8), - TypeDefPrimitive::U16 => parse_quote!(::core::primitive::u16), - TypeDefPrimitive::U32 => parse_quote!(::core::primitive::u32), - TypeDefPrimitive::U64 => parse_quote!(::core::primitive::u64), - TypeDefPrimitive::U128 => parse_quote!(::core::primitive::u128), - TypeDefPrimitive::U256 => unimplemented!("not a rust primitive"), - TypeDefPrimitive::I8 => parse_quote!(::core::primitive::i8), - TypeDefPrimitive::I16 => parse_quote!(::core::primitive::i16), - TypeDefPrimitive::I32 => parse_quote!(::core::primitive::i32), - TypeDefPrimitive::I64 => parse_quote!(::core::primitive::i64), - TypeDefPrimitive::I128 => parse_quote!(::core::primitive::i128), - TypeDefPrimitive::I256 => unimplemented!("not a rust primitive"), - }) - } - TypePathTypeKind::Compact { inner, is_field } => { - let path = if *is_field { - parse_quote! ( #inner ) - } else { - parse_quote! ( ::subxt::ext::codec::Compact<#inner> ) - }; - syn::Type::Path(path) - } - TypePathTypeKind::BitVec { - bit_order_type, - bit_store_type, - } => { - let type_path = parse_quote! { ::subxt::ext::bitvec::vec::BitVec<#bit_store_type, #bit_order_type> }; - syn::Type::Path(type_path) - } - } - } - - /// Returns the type parameters in a path which are inherited from the containing type. - /// - /// # Example - /// - /// ```rust - /// struct S { - /// a: Vec>, // the parent type param here is `T` - /// } - /// ``` - fn parent_type_params(&self, acc: &mut BTreeSet) { - for p in &self.params { - p.parent_type_params(acc); - } - } -} - -#[derive(Clone, Debug)] -pub enum TypePathTypeKind { +pub enum TypePathType { Path { path: syn::TypePath, params: Vec, @@ -194,7 +103,7 @@ pub enum TypePathTypeKind { }, } -impl TypePathTypeKind { +impl TypePathType { pub fn from_type_def_path( path: &Path, root_mod_ident: Ident, @@ -232,6 +141,104 @@ impl TypePathTypeKind { }; Self::Path { path, params } } + + /// Visits a type path, collecting all the generic type parameters from the containing type. + /// + /// # Example + /// + /// ```rust + /// struct S { + /// a: Vec>, // the parent type param here is `T` + /// } + /// ``` + fn parent_type_params(&self, acc: &mut BTreeSet) { + match self { + TypePathType::Path { params, .. } => { + for p in params { + p.parent_type_params(acc) + } + } + TypePathType::Vec { of } => of.parent_type_params(acc), + TypePathType::Array { of, .. } => of.parent_type_params(acc), + TypePathType::Tuple { elements } => { + for e in elements { + e.parent_type_params(acc) + } + } + TypePathType::Primitive { .. } => (), + TypePathType::Compact { inner, .. } => inner.parent_type_params(acc), + TypePathType::BitVec { + bit_order_type, + bit_store_type, + } => { + bit_order_type.parent_type_params(acc); + bit_store_type.parent_type_params(acc); + } + } + } + + pub(crate) fn is_compact(&self) -> bool { + matches!(self, TypePathType::Compact { .. }) + } + + fn to_syn_type(&self) -> syn::Type { + match &self { + TypePathType::Path { path, params } => { + let path = if params.is_empty() { + parse_quote! { #path } + } else { + parse_quote! { #path< #( #params ),* > } + }; + syn::Type::Path(path) + } + TypePathType::Vec { of } => { + let type_path = parse_quote! { ::std::vec::Vec<#of> }; + syn::Type::Path(type_path) + } + TypePathType::Array { len, of } => { + let array = parse_quote! { [#of; #len] }; + syn::Type::Array(array) + } + TypePathType::Tuple { elements } => { + let tuple = parse_quote! { (#( # elements, )* ) }; + syn::Type::Tuple(tuple) + } + TypePathType::Primitive { def } => { + syn::Type::Path(match def { + TypeDefPrimitive::Bool => parse_quote!(::core::primitive::bool), + TypeDefPrimitive::Char => parse_quote!(::core::primitive::char), + TypeDefPrimitive::Str => parse_quote!(::std::string::String), + TypeDefPrimitive::U8 => parse_quote!(::core::primitive::u8), + TypeDefPrimitive::U16 => parse_quote!(::core::primitive::u16), + TypeDefPrimitive::U32 => parse_quote!(::core::primitive::u32), + TypeDefPrimitive::U64 => parse_quote!(::core::primitive::u64), + TypeDefPrimitive::U128 => parse_quote!(::core::primitive::u128), + TypeDefPrimitive::U256 => unimplemented!("not a rust primitive"), + TypeDefPrimitive::I8 => parse_quote!(::core::primitive::i8), + TypeDefPrimitive::I16 => parse_quote!(::core::primitive::i16), + TypeDefPrimitive::I32 => parse_quote!(::core::primitive::i32), + TypeDefPrimitive::I64 => parse_quote!(::core::primitive::i64), + TypeDefPrimitive::I128 => parse_quote!(::core::primitive::i128), + TypeDefPrimitive::I256 => unimplemented!("not a rust primitive"), + }) + } + TypePathType::Compact { inner, is_field } => { + let path = if *is_field { + parse_quote! ( #inner ) + } else { + parse_quote! ( ::subxt::ext::codec::Compact<#inner> ) + }; + syn::Type::Path(path) + } + TypePathType::BitVec { + bit_order_type, + bit_store_type, + } => { + let type_path = parse_quote! { ::subxt::ext::bitvec::vec::BitVec<#bit_store_type, #bit_order_type> }; + syn::Type::Path(type_path) + } + } + } } #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] From e9dadf3de7dafc920602e11b84d921d7b47888c3 Mon Sep 17 00:00:00 2001 From: ascjones Date: Wed, 14 Sep 2022 10:51:36 +0100 Subject: [PATCH 07/11] Introduce different methods for generating a type path for a field --- codegen/src/api/constants.rs | 2 +- codegen/src/api/events.rs | 2 +- codegen/src/api/storage.rs | 6 +-- codegen/src/types/composite_def.rs | 2 +- codegen/src/types/mod.rs | 78 ++++++++++++++++++++++++------ 5 files changed, 69 insertions(+), 21 deletions(-) diff --git a/codegen/src/api/constants.rs b/codegen/src/api/constants.rs index 6925570ec9..529da75059 100644 --- a/codegen/src/api/constants.rs +++ b/codegen/src/api/constants.rs @@ -58,7 +58,7 @@ pub fn generate_constants( let constant_hash = subxt_metadata::get_constant_hash(metadata, pallet_name, constant_name) .unwrap_or_else(|_| abort_call_site!("Metadata information for the constant {}_{} could not be found", pallet_name, constant_name)); - let return_ty = type_gen.resolve_type_path(constant.ty.id(), &[]); + let return_ty = type_gen.resolve_type_path(constant.ty.id()); let docs = &constant.docs; quote! { diff --git a/codegen/src/api/events.rs b/codegen/src/api/events.rs index 5e16964265..24f0e38059 100644 --- a/codegen/src/api/events.rs +++ b/codegen/src/api/events.rs @@ -69,7 +69,7 @@ pub fn generate_events( } } }); - let event_type = type_gen.resolve_type_path(event.ty.id(), &[]); + let event_type = type_gen.resolve_type_path(event.ty.id()); let event_ty = type_gen.resolve_type(event.ty.id()); let docs = event_ty.docs(); diff --git a/codegen/src/api/storage.rs b/codegen/src/api/storage.rs index 5d0e0b1674..273cdb22b2 100644 --- a/codegen/src/api/storage.rs +++ b/codegen/src/api/storage.rs @@ -101,7 +101,7 @@ fn generate_storage_entry_fns( .enumerate() .map(|(i, f)| { let field_name = format_ident!("_{}", syn::Index::from(i)); - let field_type = type_gen.resolve_type_path(f.id(), &[]); + let field_type = type_gen.resolve_type_path(f.id()); (field_name, field_type) }) .collect::>(); @@ -142,7 +142,7 @@ fn generate_storage_entry_fns( (fields, key_impl) } _ => { - let ty_path = type_gen.resolve_type_path(key.id(), &[]); + let ty_path = type_gen.resolve_type_path(key.id()); let fields = vec![(format_ident!("_0"), ty_path)]; let hasher = hashers.get(0).unwrap_or_else(|| { abort_call_site!("No hasher found for single key") @@ -173,7 +173,7 @@ fn generate_storage_entry_fns( StorageEntryType::Plain(ref ty) => ty, StorageEntryType::Map { ref value, .. } => value, }; - let storage_entry_value_ty = type_gen.resolve_type_path(storage_entry_ty.id(), &[]); + let storage_entry_value_ty = type_gen.resolve_type_path(storage_entry_ty.id()); let docs = &storage_entry.docs; let docs_token = quote! { #( #[doc = #docs ] )* }; diff --git a/codegen/src/types/composite_def.rs b/codegen/src/types/composite_def.rs index 9cd10a5cd0..7d4dec5fc6 100644 --- a/codegen/src/types/composite_def.rs +++ b/codegen/src/types/composite_def.rs @@ -190,7 +190,7 @@ impl CompositeDefFields { for field in fields { let type_path = - type_gen.resolve_type_path(field.ty().id(), parent_type_params); + type_gen.resolve_field_type_path(field.ty().id(), parent_type_params); let field_type = CompositeDefFieldType::new( field.ty().id(), type_path, diff --git a/codegen/src/types/mod.rs b/codegen/src/types/mod.rs index c93bde9faf..8e8a2b6fb1 100644 --- a/codegen/src/types/mod.rs +++ b/codegen/src/types/mod.rs @@ -144,12 +144,46 @@ impl<'a> TypeGenerator<'a> { .clone() } + /// Get the type path for a field of a struct or an enum variant, providing any generic + /// type parameters from the containing type. This is for identifying where a generic type + /// parameter is used in a field type e.g. + /// + /// ```rust + /// struct S { + /// a: T, // `T` is the "parent" type param from the containing type. + /// b: Vec>, // nested use of generic type param `T`. + /// } + /// ``` + /// + /// This allows generating the correct generic field type paths. + /// + /// # Panics + /// + /// If no type with the given id found in the type registry. + pub fn resolve_field_type_path( + &self, + id: u32, + parent_type_params: &[TypeParameter], + ) -> TypePath { + self.resolve_type_path_recurse(id, true, parent_type_params) + } + + /// Get the type path for the given type identifier. + /// /// # Panics /// /// If no type with the given id found in the type registry. - pub fn resolve_type_path( + pub fn resolve_type_path(&self, id: u32) -> TypePath { + self.resolve_type_path_recurse(id, false, &[]) + } + + /// Visit each node in a possibly nested type definition to produce a type path. + /// + /// e.g `Result>, String>` + fn resolve_type_path_recurse( &self, id: u32, + is_field: bool, parent_type_params: &[TypeParameter], ) -> TypePath { if let Some(parent_type_param) = parent_type_params @@ -174,8 +208,9 @@ impl<'a> TypeGenerator<'a> { .type_params() .iter() .filter_map(|f| { - f.ty() - .map(|f| self.resolve_type_path(f.id(), parent_type_params)) + f.ty().map(|f| { + self.resolve_type_path_recurse(f.id(), false, parent_type_params) + }) }) .collect(); @@ -205,16 +240,20 @@ impl<'a> TypeGenerator<'a> { TypeDef::Array(arr) => { TypePathType::Array { len: arr.len() as usize, - of: Box::new( - self.resolve_type_path(arr.type_param().id(), parent_type_params), - ), + of: Box::new(self.resolve_type_path_recurse( + arr.type_param().id(), + false, + parent_type_params, + )), } } TypeDef::Sequence(seq) => { TypePathType::Vec { - of: Box::new( - self.resolve_type_path(seq.type_param().id(), parent_type_params), - ), + of: Box::new(self.resolve_type_path_recurse( + seq.type_param().id(), + false, + parent_type_params, + )), } } TypeDef::Tuple(tuple) => { @@ -222,27 +261,36 @@ impl<'a> TypeGenerator<'a> { elements: tuple .fields() .iter() - .map(|f| self.resolve_type_path(f.id(), parent_type_params)) + .map(|f| { + self.resolve_type_path_recurse( + f.id(), + false, + parent_type_params, + ) + }) .collect(), } } TypeDef::Compact(compact) => { TypePathType::Compact { - inner: Box::new(self.resolve_type_path( + inner: Box::new(self.resolve_type_path_recurse( compact.type_param().id(), + false, parent_type_params, )), - is_field: false, // todo + is_field, } } TypeDef::BitSequence(bitseq) => { TypePathType::BitVec { - bit_order_type: Box::new(self.resolve_type_path( + bit_order_type: Box::new(self.resolve_type_path_recurse( bitseq.bit_order_type().id(), + false, parent_type_params, )), - bit_store_type: Box::new(self.resolve_type_path( + bit_store_type: Box::new(self.resolve_type_path_recurse( bitseq.bit_store_type().id(), + false, parent_type_params, )), } @@ -273,7 +321,7 @@ pub struct Module { name: Ident, root_mod: Ident, children: BTreeMap, - types: BTreeMap, TypeDefGen>, + types: BTreeMap, TypeDefGen>, } impl ToTokens for Module { From a31b7408712168c5225b1e73d8308c249c7f0a33 Mon Sep 17 00:00:00 2001 From: ascjones Date: Wed, 14 Sep 2022 11:20:39 +0100 Subject: [PATCH 08/11] Add comment --- codegen/src/types/type_path.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/codegen/src/types/type_path.rs b/codegen/src/types/type_path.rs index 1326f6b5bc..74c31b3e1c 100644 --- a/codegen/src/types/type_path.rs +++ b/codegen/src/types/type_path.rs @@ -224,6 +224,8 @@ impl TypePathType { } TypePathType::Compact { inner, is_field } => { let path = if *is_field { + // compact fields can use the inner compact type directly and be annotated with + // the `compact` attribute e.g. `#[codec(compact)] my_compact_field: u128` parse_quote! ( #inner ) } else { parse_quote! ( ::subxt::ext::codec::Compact<#inner> ) From 3fb055a2274376090af4366d86a8730a2dc81af3 Mon Sep 17 00:00:00 2001 From: ascjones Date: Wed, 14 Sep 2022 13:07:18 +0100 Subject: [PATCH 09/11] Fix weights refs --- testing/integration-tests/src/frame/contracts.rs | 2 +- testing/integration-tests/src/frame/sudo.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/integration-tests/src/frame/contracts.rs b/testing/integration-tests/src/frame/contracts.rs index 31cc84c0e3..8340bc220e 100644 --- a/testing/integration-tests/src/frame/contracts.rs +++ b/testing/integration-tests/src/frame/contracts.rs @@ -8,7 +8,7 @@ use crate::{ node_runtime::{ self, contracts::events, - runtime_types::frame_support::weights::weight_v2::Weight, + runtime_types::sp_weights::weight_v2::Weight, system, }, test_context, diff --git a/testing/integration-tests/src/frame/sudo.rs b/testing/integration-tests/src/frame/sudo.rs index fd5c91a50e..e43bcf9941 100644 --- a/testing/integration-tests/src/frame/sudo.rs +++ b/testing/integration-tests/src/frame/sudo.rs @@ -7,7 +7,7 @@ use crate::{ self, runtime_types::{ self, - frame_support::weights::weight_v2::Weight, + sp_weights::weight_v2::Weight, }, sudo, }, From 907f936e598f3a12bef91aa2d18fc30a7fd2f9ba Mon Sep 17 00:00:00 2001 From: ascjones Date: Tue, 20 Sep 2022 10:40:28 +0100 Subject: [PATCH 10/11] Add extra compact test cases --- codegen/src/types/tests.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/codegen/src/types/tests.rs b/codegen/src/types/tests.rs index d17a356d29..386037690b 100644 --- a/codegen/src/types/tests.rs +++ b/codegen/src/types/tests.rs @@ -4,11 +4,7 @@ use super::*; use pretty_assertions::assert_eq; -use scale_info::{ - meta_type, - Registry, - TypeInfo, -}; +use scale_info::{meta_type, Registry, scale, TypeInfo}; use syn::parse_quote; const MOD_PATH: &[&str] = &["subxt_codegen", "types", "tests"]; @@ -373,10 +369,16 @@ fn compact_fields() { #[test] fn compact_generic_parameter() { + use scale::Compact; + #[allow(unused)] #[derive(TypeInfo)] struct S { a: Option<::Type>, + nested: Option, u8>>, + vector: Vec>, + array: [Compact; 32], + tuple: (Compact, Compact), } let mut registry = Registry::new(); @@ -401,6 +403,10 @@ fn compact_generic_parameter() { #[derive(::subxt::ext::codec::Decode, ::subxt::ext::codec::Encode, Debug)] pub struct S { pub a: ::core::option::Option<::subxt::ext::codec::Compact<::core::primitive::u128> >, + pub nested: ::core::option::Option<::core::result::Result<::subxt::ext::codec::Compact<::core::primitive::u128>, ::core::primitive::u8 > >, + pub vector: ::std::vec::Vec<::subxt::ext::codec::Compact<::core::primitive::u16> >, + pub array: [::subxt::ext::codec::Compact<::core::primitive::u8>; 32usize], + pub tuple: (::subxt::ext::codec::Compact<::core::primitive::u8>, ::subxt::ext::codec::Compact<::core::primitive::u16>,), } } } From 2143ec7bba8385f27dddf47afe70cd68cc543124 Mon Sep 17 00:00:00 2001 From: ascjones Date: Tue, 20 Sep 2022 10:43:02 +0100 Subject: [PATCH 11/11] Fmt --- codegen/src/types/tests.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/codegen/src/types/tests.rs b/codegen/src/types/tests.rs index 386037690b..8dbfac0b3a 100644 --- a/codegen/src/types/tests.rs +++ b/codegen/src/types/tests.rs @@ -4,7 +4,12 @@ use super::*; use pretty_assertions::assert_eq; -use scale_info::{meta_type, Registry, scale, TypeInfo}; +use scale_info::{ + meta_type, + scale, + Registry, + TypeInfo, +}; use syn::parse_quote; const MOD_PATH: &[&str] = &["subxt_codegen", "types", "tests"];