Skip to content

Commit

Permalink
Add TypeParameter struct and optional type
Browse files Browse the repository at this point in the history
  • Loading branch information
ascjones committed Jun 24, 2021
1 parent a7e1e6b commit 411e50c
Show file tree
Hide file tree
Showing 9 changed files with 155 additions and 63 deletions.
26 changes: 9 additions & 17 deletions derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,34 +69,26 @@ fn generate_type(input: TokenStream2) -> Result<TokenStream2> {

let ident = &ast.ident;

let type_params: Vec<_> = ast
.generics
.type_params()
.filter(|tp| {
attrs
.skip_type_params()
.map(|skip| !skip.skip(tp))
.unwrap_or(true)
})
.cloned()
.collect();

let where_clause = trait_bounds::make_where_clause(
&attrs,
ident,
&ast.generics,
&type_params,
&ast.data,
&scale_info,
&parity_scale_codec,
)?;

let (impl_generics, ty_generics, _) = ast.generics.split_for_impl();

let type_params_meta_types = type_params.iter().map(|ty| {
let ty_ident = &ty.ident;
let type_params = ast.generics.type_params().map(|tp| {
let ty_ident = &tp.ident;
let ty = if attrs.skip_type_params().map_or(true, |skip| !skip.skip(tp)) {
quote! { Some(:: #scale_info ::meta_type::<#ty_ident>()) }
} else {
quote! { None }
};
quote! {
:: #scale_info ::meta_type::<#ty_ident>()
:: #scale_info ::TypeParameter::new(::core::stringify!(#ty_ident), #ty)
}
});

Expand All @@ -113,7 +105,7 @@ fn generate_type(input: TokenStream2) -> Result<TokenStream2> {
fn type_info() -> :: #scale_info ::Type {
:: #scale_info ::Type::builder()
.path(:: #scale_info ::Path::new(::core::stringify!(#ident), ::core::module_path!()))
.type_params(:: #scale_info ::prelude::vec![ #( #type_params_meta_types ),* ])
.type_params(:: #scale_info ::prelude::vec![ #( #type_params ),* ])
#docs
.#build_type
}
Expand Down
17 changes: 13 additions & 4 deletions derive/src/trait_bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ use syn::{
Generics,
Result,
Type,
TypeParam,
TypePath,
WhereClause,
};
Expand All @@ -39,12 +38,19 @@ use crate::{
/// relevant generic types including associated types (e.g. `T::A: TypeInfo`), correctly dealing
/// with self-referential types.
///
/// Ignores any type parameters not included in `type_params`.
/// # Effect of attributes
///
/// `#[scale_info(skip_type_params(..))]`
///
/// Will not add `TypeInfo` bounds for any type parameters skipped via this attribute.
///
/// `#[scale_info(bounds(..))]`
///
/// Replaces *all* auto-generated trait bounds with the user-defined ones.
pub fn make_where_clause<'a>(
attrs: &'a Attributes,
input_ident: &'a Ident,
generics: &'a Generics,
type_params: &[TypeParam],
data: &'a syn::Data,
scale_info: &Ident,
parity_scale_codec: &Ident,
Expand Down Expand Up @@ -102,7 +108,10 @@ pub fn make_where_clause<'a>(
generics.type_params().into_iter().for_each(|type_param| {
let ident = type_param.ident.clone();
let mut bounds = type_param.bounds.clone();
if type_params.iter().any(|tp| *tp == *type_param) {
if attrs
.skip_type_params()
.map_or(true, |skip| !skip.skip(type_param))
{
bounds.push(parse_quote!(:: #scale_info ::TypeInfo));
}
bounds.push(parse_quote!('static));
Expand Down
13 changes: 7 additions & 6 deletions src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
//!
//! ## Generic struct
//! ```
//! # use scale_info::{build::Fields, MetaType, Path, Type, TypeInfo};
//! # use scale_info::{build::Fields, type_params, MetaType, Path, Type, TypeInfo};
//! struct Foo<T> {
//! bar: T,
//! data: u64,
Expand All @@ -37,7 +37,7 @@
//! fn type_info() -> Type {
//! Type::builder()
//! .path(Path::new("Foo", module_path!()))
//! .type_params(vec![MetaType::new::<T>()])
//! .type_params(type_params!(T))
//! .composite(Fields::named()
//! .field(|f| f.ty::<T>().name("bar").type_name("T"))
//! .field(|f| f.ty::<u64>().name("data").type_name("u64"))
Expand Down Expand Up @@ -65,7 +65,7 @@
//! ```
//! ## Enum with fields
//! ```
//! # use scale_info::{build::{Fields, Variants}, MetaType, Path, Type, TypeInfo, Variant};
//! # use scale_info::{build::{Fields, Variants}, type_params, MetaType, Path, Type, TypeInfo, Variant};
//! enum Foo<T>{
//! A(T),
//! B { f: u32 },
Expand All @@ -81,7 +81,7 @@
//! fn type_info() -> Type {
//! Type::builder()
//! .path(Path::new("Foo", module_path!()))
//! .type_params(vec![MetaType::new::<T>()])
//! .type_params(type_params!(T))
//! .variant(
//! Variants::new()
//! .variant("A", |v| v.fields(Fields::unnamed().field(|f| f.ty::<T>().type_name("T"))))
Expand Down Expand Up @@ -131,6 +131,7 @@ use crate::{
TypeDefComposite,
TypeDefVariant,
TypeInfo,
TypeParameter,
Variant,
};

Expand All @@ -145,7 +146,7 @@ pub mod state {
/// Builds a [`Type`](`crate::Type`)
pub struct TypeBuilder<S = state::PathNotAssigned> {
path: Option<Path>,
type_params: Vec<MetaType>,
type_params: Vec<TypeParameter>,
docs: Vec<&'static str>,
marker: PhantomData<fn() -> S>,
}
Expand Down Expand Up @@ -197,7 +198,7 @@ impl<S> TypeBuilder<S> {
/// Set the type parameters if it's a generic type
pub fn type_params<I>(mut self, type_params: I) -> Self
where
I: IntoIterator<Item = MetaType>,
I: IntoIterator<Item = TypeParameter>,
{
self.type_params = type_params.into_iter().collect();
self
Expand Down
10 changes: 5 additions & 5 deletions src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ where
fn type_info() -> Type {
Type::builder()
.path(Path::prelude("Option"))
.type_params(tuple_meta_type![T])
.type_params(type_params![T])
.variant(Variants::new().variant("None", |v| v).variant("Some", |v| {
v.fields(Fields::unnamed().field(|f| f.ty::<T>()))
}))
Expand All @@ -164,7 +164,7 @@ where
fn type_info() -> Type {
Type::builder()
.path(Path::prelude("Result"))
.type_params(tuple_meta_type!(T, E))
.type_params(type_params!(T, E))
.variant(
Variants::new()
.variant("Ok", |v| v.fields(Fields::unnamed().field(|f| f.ty::<T>())))
Expand All @@ -184,7 +184,7 @@ where
fn type_info() -> Type {
Type::builder()
.path(Path::prelude("Cow"))
.type_params(tuple_meta_type!(T))
.type_params(type_params!(T))
.composite(Fields::unnamed().field(|f| f.ty::<T>()))
}
}
Expand All @@ -199,7 +199,7 @@ where
fn type_info() -> Type {
Type::builder()
.path(Path::prelude("BTreeMap"))
.type_params(tuple_meta_type![(K, V)])
.type_params(type_params![K, V])
.composite(Fields::unnamed().field(|f| f.ty::<[(K, V)]>()))
}
}
Expand All @@ -213,7 +213,7 @@ where
fn type_info() -> Type {
Type::builder()
.path(Path::prelude("BTreeSet"))
.type_params(tuple_meta_type![T])
.type_params(type_params![T])
.composite(Fields::unnamed().field(|f| f.ty::<[T]>()))
}
}
Expand Down
28 changes: 27 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
/// [`MetaType`](`crate::MetaType`) instances.
///
/// This is useful for places that require inputs of iterators over [`MetaType`](`crate::MetaType`)
/// instances and provide a way out of code bloat in these scenarious.
/// instances and provide a way out of code bloat in these scenarios.
///
/// # Example
///
Expand Down Expand Up @@ -101,6 +101,32 @@ macro_rules! tuple_meta_type {
}
}

/// Construct a vector of `TypeParameter`s from pairs of the name and the concrete type.
#[macro_export]
macro_rules! named_type_params {
( $(($tp:ty, $ty:ty)),* ) => {
{
$crate::prelude::vec![
$(
$crate::TypeParameter::new(
::core::stringify!($tp),
Some($crate::MetaType::new::<$ty>())
),
)*
]
}
}
}

/// Construct a vector of [`TypeParameter`] instances with the name of the type parameter,
/// together with its concrete [`MetaType`].
#[macro_export]
macro_rules! type_params {
( $($ty:ty),* ) => {
$crate::named_type_params!{ $( ($ty, $ty) ),* }
}
}

pub mod prelude;

pub mod build;
Expand Down
20 changes: 10 additions & 10 deletions src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ fn prelude_items() {
Option<u128>,
Type::builder()
.path(Path::prelude("Option"))
.type_params(tuple_meta_type!(u128))
.type_params(named_type_params![(T, u128)])
.variant(Variants::new().variant("None", |v| v).variant("Some", |v| {
v.fields(Fields::unnamed().field(|f| f.ty::<u128>()))
}))
Expand All @@ -69,7 +69,7 @@ fn prelude_items() {
Result<bool, String>,
Type::builder()
.path(Path::prelude("Result"))
.type_params(tuple_meta_type!(bool, String))
.type_params(named_type_params![(T, bool), (E, String)])
.variant(
Variants::new()
.variant(
Expand All @@ -87,7 +87,7 @@ fn prelude_items() {
Cow<u128>,
Type::builder()
.path(Path::prelude("Cow"))
.type_params(tuple_meta_type!(u128))
.type_params(named_type_params![(T, u128)])
.composite(Fields::unnamed().field(|f| f.ty::<u128>()))
);
}
Expand All @@ -98,15 +98,15 @@ fn collections() {
BTreeMap<String, u32>,
Type::builder()
.path(Path::prelude("BTreeMap"))
.type_params(tuple_meta_type![(String, u32)])
.type_params(named_type_params![(K, String), (V, u32)])
.composite(Fields::unnamed().field(|f| f.ty::<[(String, u32)]>()))
);

assert_type!(
BTreeSet<String>,
Type::builder()
.path(Path::prelude("BTreeSet"))
.type_params(tuple_meta_type![String])
.type_params(named_type_params![(T, String)])
.composite(Fields::unnamed().field(|f| f.ty::<[String]>()))
);

Expand Down Expand Up @@ -197,7 +197,7 @@ fn struct_with_generics() {
fn type_info() -> Type {
Type::builder()
.path(Path::new("MyStruct", module_path!()))
.type_params(tuple_meta_type!(T))
.type_params(type_params!(T))
.composite(
Fields::named().field(|f| f.ty::<T>().name("data").type_name("T")),
)
Expand All @@ -207,7 +207,7 @@ fn struct_with_generics() {
// Normal struct
let struct_bool_type_info = Type::builder()
.path(Path::from_segments(vec!["scale_info", "tests", "MyStruct"]).unwrap())
.type_params(tuple_meta_type!(bool))
.type_params(named_type_params![(T, bool)])
.composite(Fields::named().field(|f| f.ty::<bool>().name("data").type_name("T")));

assert_type!(MyStruct<bool>, struct_bool_type_info);
Expand All @@ -216,7 +216,7 @@ fn struct_with_generics() {
type SelfTyped = MyStruct<Box<MyStruct<bool>>>;
let expected_type = Type::builder()
.path(Path::new("MyStruct", "scale_info::tests"))
.type_params(tuple_meta_type!(Box<MyStruct<bool>>))
.type_params(named_type_params![(T, Box<MyStruct<bool>>)])
.composite(
Fields::named()
.field(|f| f.ty::<Box<MyStruct<bool>>>().name("data").type_name("T")),
Expand All @@ -241,7 +241,7 @@ fn basic_struct_with_phantoms() {
fn type_info() -> Type {
Type::builder()
.path(Path::new("SomeStruct", module_path!()))
.type_params(tuple_meta_type!(T))
.type_params(type_params!(T))
.composite(
Fields::named().field(|f| f.ty::<u8>().name("a").type_name("u8")),
)
Expand All @@ -250,7 +250,7 @@ fn basic_struct_with_phantoms() {

let struct_bool_type_info = Type::builder()
.path(Path::from_segments(vec!["scale_info", "tests", "SomeStruct"]).unwrap())
.type_params(tuple_meta_type!(bool))
.type_params(named_type_params![(T, bool)])
.composite(Fields::named().field(|f| f.ty::<u8>().name("a").type_name("u8")));

assert_type!(SomeStruct<bool>, struct_bool_type_info);
Expand Down
Loading

0 comments on commit 411e50c

Please sign in to comment.