diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 73cbdd5b..511c0bec 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -19,7 +19,13 @@ extern crate proc_macro; mod impl_wrapper; -use alloc::vec::Vec; +use alloc::{ + string::{ + String, + ToString, + }, + vec::Vec, +}; use proc_macro::TokenStream; use proc_macro2::TokenStream as TokenStream2; use quote::quote; @@ -104,19 +110,38 @@ fn generate_fields(fields: &FieldsList) -> Vec { .iter() .map(|f| { let (ty, ident) = (&f.ty, &f.ident); + let type_name = clean_type_string("e!(#ty).to_string()); + if let Some(i) = ident { quote! { - .field_of::<#ty>(stringify!(#i)) + .field_of::<#ty>(stringify!(#i), #type_name) } } else { quote! { - .field_of::<#ty>() + .field_of::<#ty>(#type_name) } } }) .collect() } +fn clean_type_string(input: &str) -> String { + input + .replace(" ::", "::") + .replace(":: ", "::") + .replace(" ,", ",") + .replace(" ;", ";") + .replace(" [", "[") + .replace("[ ", "[") + .replace(" ]", "]") + .replace(" (", "(") + .replace("( ", "(") + .replace(" )", ")") + .replace(" <", "<") + .replace("< ", "<") + .replace(" >", ">") +} + fn generate_composite_type(data_struct: &DataStruct) -> TokenStream2 { let fields = match data_struct.fields { Fields::Named(ref fs) => { diff --git a/src/build.rs b/src/build.rs index ed150f12..4832b3e1 100644 --- a/src/build.rs +++ b/src/build.rs @@ -39,8 +39,8 @@ //! .path(Path::new("Foo", module_path!())) //! .type_params(vec![MetaType::new::()]) //! .composite(Fields::named() -//! .field_of::("bar") -//! .field_of::("data") +//! .field_of::("bar", "T") +//! .field_of::("data", "u64") //! ) //! } //! } @@ -57,8 +57,8 @@ //! Type::builder() //! .path(Path::new("Foo", module_path!())) //! .composite(Fields::unnamed() -//! .field_of::() -//! .field_of::() +//! .field_of::("u32") +//! .field_of::("bool") //! ) //! } //! } @@ -84,8 +84,8 @@ //! .type_params(vec![MetaType::new::()]) //! .variant( //! Variants::with_fields() -//! .variant("A", Fields::unnamed().field_of::()) -//! .variant("B", Fields::named().field_of::("f")) +//! .variant("A", Fields::unnamed().field_of::("T")) +//! .variant("B", Fields::named().field_of::("f", "u32")) //! .variant("C", Fields::unit()) //! ) //! } @@ -177,12 +177,12 @@ impl TypeBuilder { /// Construct a "variant" type i.e an `enum` pub fn variant(self, builder: VariantsBuilder) -> Type { - self.build(builder.done()) + self.build(builder.finalize()) } /// Construct a "composite" type i.e. a `struct` pub fn composite(self, fields: FieldsBuilder) -> Type { - self.build(TypeDefComposite::new(fields.done())) + self.build(TypeDefComposite::new(fields.finalize())) } } @@ -226,7 +226,7 @@ impl Fields { /// Build a set of either all named (e.g. for a struct) or all unnamed (e.g. for a tuple struct) pub struct FieldsBuilder { - fields: Vec>, + fields: Vec, marker: PhantomData T>, } @@ -241,41 +241,29 @@ impl Default for FieldsBuilder { impl FieldsBuilder { /// Complete building and return the set of fields - pub fn done(self) -> Vec> { + pub fn finalize(self) -> Vec> { self.fields } } impl FieldsBuilder { - /// Add a named field with the given [`MetaType`](`crate::MetaType`) instance - pub fn field(mut self, name: &'static str, ty: MetaType) -> Self { - self.fields.push(Field::named(name, ty)); - self - } - /// Add a named field with the type of the type parameter `T` - pub fn field_of(mut self, name: &'static str) -> Self + pub fn field_of(mut self, name: &'static str, type_name: &'static str) -> Self where T: TypeInfo + ?Sized + 'static, { - self.fields.push(Field::named_of::(name)); + self.fields.push(Field::named_of::(name, type_name)); self } } impl FieldsBuilder { - /// Add an unnamed field with the given [`MetaType`](`crate::MetaType`) instance - pub fn field(mut self, ty: MetaType) -> Self { - self.fields.push(Field::unnamed(ty)); - self - } - /// Add an unnamed field with the type of the type parameter `T` - pub fn field_of(mut self) -> Self + pub fn field_of(mut self, type_name: &'static str) -> Self where T: TypeInfo + ?Sized + 'static, { - self.fields.push(Field::unnamed_of::()); + self.fields.push(Field::unnamed_of::(type_name)); self } } @@ -341,7 +329,7 @@ impl VariantsBuilder { } } - fn done(self) -> TypeDefVariant { + fn finalize(self) -> TypeDefVariant { TypeDefVariant::new(self.variants) } } diff --git a/src/impls.rs b/src/impls.rs index 9554b589..25d4cc49 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -121,7 +121,7 @@ where .variant( Variants::with_fields() .variant_unit("None") - .variant("Some", Fields::unnamed().field_of::()), + .variant("Some", Fields::unnamed().field_of::("T")), ) } } @@ -139,8 +139,8 @@ where .type_params(tuple_meta_type!(T, E)) .variant( Variants::with_fields() - .variant("Ok", Fields::unnamed().field_of::()) - .variant("Err", Fields::unnamed().field_of::()), + .variant("Ok", Fields::unnamed().field_of::("T")) + .variant("Err", Fields::unnamed().field_of::("E")), ) } } @@ -156,7 +156,7 @@ where Type::builder() .path(Path::prelude("BTreeMap")) .type_params(tuple_meta_type![(K, V)]) - .composite(Fields::unnamed().field_of::<[(K, V)]>()) + .composite(Fields::unnamed().field_of::<[(K, V)]>("[(K, V)]")) } } diff --git a/src/registry.rs b/src/registry.rs index 609a1db3..fd539be4 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -266,10 +266,17 @@ mod tests { .path(Path::new("RecursiveRefs", module_path!())) .composite( Fields::named() - .field_of::>("boxed") - .field_of::<&'static RecursiveRefs<'static>>("reference") + .field_of::>( + "boxed", + "Box < RecursiveRefs >", + ) + .field_of::<&'static RecursiveRefs<'static>>( + "reference", + "&RecursiveRefs", + ) .field_of::<&'static mut RecursiveRefs<'static>>( "mutable_reference", + "&mut RecursiveRefs", ), ) .into() diff --git a/src/tests.rs b/src/tests.rs index ccb9b8af..1552490c 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -60,7 +60,7 @@ fn prelude_items() { .variant( Variants::with_fields() .variant_unit("None") - .variant("Some", Fields::unnamed().field_of::()) + .variant("Some", Fields::unnamed().field_of::("T")) ) ); assert_type!( @@ -70,8 +70,8 @@ fn prelude_items() { .type_params(tuple_meta_type!(bool, String)) .variant( Variants::with_fields() - .variant("Ok", Fields::unnamed().field_of::()) - .variant("Err", Fields::unnamed().field_of::()) + .variant("Ok", Fields::unnamed().field_of::("T")) + .variant("Err", Fields::unnamed().field_of::("E")) ) ); assert_type!( @@ -133,7 +133,7 @@ fn struct_with_generics() { Type::builder() .path(Path::new("MyStruct", module_path!())) .type_params(tuple_meta_type!(T)) - .composite(Fields::named().field_of::("data")) + .composite(Fields::named().field_of::("data", "T")) .into() } } @@ -142,7 +142,7 @@ fn struct_with_generics() { let struct_bool_type_info = Type::builder() .path(Path::from_segments(vec!["scale_info", "tests", "MyStruct"]).unwrap()) .type_params(tuple_meta_type!(bool)) - .composite(Fields::named().field_of::("data")); + .composite(Fields::named().field_of::("data", "T")); assert_type!(MyStruct, struct_bool_type_info); @@ -151,6 +151,6 @@ fn struct_with_generics() { let expected_type = Type::builder() .path(Path::new("MyStruct", "scale_info::tests")) .type_params(tuple_meta_type!(Box>)) - .composite(Fields::named().field_of::>>("data")); + .composite(Fields::named().field_of::>>("data", "T")); assert_type!(SelfTyped, expected_type); } diff --git a/src/ty/fields.rs b/src/ty/fields.rs index d4efcf66..687f55d0 100644 --- a/src/ty/fields.rs +++ b/src/ty/fields.rs @@ -39,7 +39,30 @@ use serde::{ /// /// Name is optional so it can represent both named and unnamed fields. /// -/// This can be a named field of a struct type or a struct variant. +/// This can be a named field of a struct type or an enum struct variant. +/// +/// # Type name +/// +/// The `type_name` field contains a string which is the name of the type of the +/// field as it appears in the source code. The exact contents and format of the +/// type name are not specified, but in practice will be the name of any valid +/// type for a field e.g. +/// +/// - Concrete types e.g `"u32"`, `"bool"`, `"Foo"` etc. +/// - Type parameters e.g `"T"`, `"U"` +/// - Generic types e.g `"Vec"`, `"Vec"` +/// - Associated types e.g. `"T::MyType"`, `"::MyType"` +/// - Type aliases e.g. `"MyTypeAlias"`, `"MyTypeAlias"` +/// - Other built in Rust types e.g. arrays, references etc. +/// +/// Note that the type name doesn't correspond to the underlying type of the +/// field, unless using a concrete type directly. Any given type may be referred +/// to by multiple field type names, when using generic type parameters and type +/// aliases. +/// +/// This is intended for informational and diagnostic purposes only. Although it +/// is possible to infer certain properties e.g. whether a type name is a type alias, +/// there are no guarantees provided, and the type name representation may change. #[derive( PartialEq, Eq, PartialOrd, Ord, Clone, Debug, Serialize, Deserialize, Encode, Decode, )] @@ -47,6 +70,7 @@ use serde::{ serialize = "T::Type: Serialize, T::String: Serialize", deserialize = "T::Type: DeserializeOwned, T::String: DeserializeOwned" ))] +#[serde(rename_all = "camelCase")] pub struct Field { /// The name of the field. None for unnamed fields. #[serde(skip_serializing_if = "Option::is_none", default)] @@ -54,6 +78,8 @@ pub struct Field { /// The type of the field. #[serde(rename = "type")] ty: T::Type, + /// The name of the type of the field as it appears in the source code. + type_name: T::String, } impl IntoCompact for Field { @@ -63,6 +89,7 @@ impl IntoCompact for Field { Field { name: self.name.map(|name| name.into_compact(registry)), ty: registry.register_type(&self.ty), + type_name: self.type_name.into_compact(registry), } } } @@ -71,43 +98,38 @@ impl Field { /// Creates a new field. /// /// Use this constructor if you want to instantiate from a given meta type. - pub fn new(name: Option<&'static str>, ty: MetaType) -> Self { - Self { name, ty } - } - - /// Creates a new named field - pub fn named(name: &'static str, ty: MetaType) -> Self { - Self::new(Some(name), ty) + pub fn new( + name: Option<&'static str>, + ty: MetaType, + type_name: &'static str, + ) -> Self { + Self { + name, + ty, + type_name, + } } /// Creates a new named field. /// /// Use this constructor if you want to instantiate from a given /// compile-time type. - pub fn named_of(name: &'static str) -> Self + pub fn named_of(name: &'static str, type_name: &'static str) -> Field where T: TypeInfo + ?Sized + 'static, { - Self::new(Some(name), MetaType::new::()) - } - - /// Creates a new unnamed field. - /// - /// Use this constructor if you want to instantiate an unnamed field from a - /// given meta type. - pub fn unnamed(meta_type: MetaType) -> Self { - Self::new(None, meta_type) + Self::new(Some(name), MetaType::new::(), type_name) } /// Creates a new unnamed field. /// /// Use this constructor if you want to instantiate an unnamed field from a /// given compile-time type. - pub fn unnamed_of() -> Self + pub fn unnamed_of(type_name: &'static str) -> Field where T: TypeInfo + ?Sized + 'static, { - Self::new(None, MetaType::new::()) + Self::new(None, MetaType::new::(), type_name) } } @@ -124,4 +146,13 @@ where pub fn ty(&self) -> &T::Type { &self.ty } + + /// Returns a string which is the name of the type of the field as it + /// appears in the source code. The exact contents and format of the type + /// name are not specified, but in practice will be the name of any valid + /// type for a field. This is intended for informational and diagnostic + /// purposes only. + pub fn type_name(&self) -> &T::String { + &self.type_name + } } diff --git a/src/ty/variant.rs b/src/ty/variant.rs index 90b3313c..4541b5e7 100644 --- a/src/ty/variant.rs +++ b/src/ty/variant.rs @@ -186,7 +186,7 @@ impl Variant { pub fn with_fields(name: &'static str, fields: FieldsBuilder) -> Self { Self { name, - fields: fields.done(), + fields: fields.finalize(), discriminant: None, } } diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index 49e4bf50..ba7deede 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -55,7 +55,11 @@ fn struct_derive() { let struct_type = Type::builder() .path(Path::new("S", "derive")) .type_params(tuple_meta_type!(bool, u8)) - .composite(Fields::named().field_of::("t").field_of::("u")); + .composite( + Fields::named() + .field_of::("t", "T") + .field_of::("u", "U"), + ); assert_type!(S, struct_type); @@ -68,8 +72,8 @@ fn struct_derive() { .type_params(tuple_meta_type!(Box>, bool)) .composite( Fields::named() - .field_of::>>("t") - .field_of::("u"), + .field_of::>>("t", "T") + .field_of::("u", "U"), ); assert_type!(SelfTyped, self_typed_type); } @@ -83,7 +87,7 @@ fn tuple_struct_derive() { let ty = Type::builder() .path(Path::new("S", "derive")) .type_params(tuple_meta_type!(bool)) - .composite(Fields::unnamed().field_of::()); + .composite(Fields::unnamed().field_of::("T")); assert_type!(S, ty); } @@ -132,8 +136,8 @@ fn enum_derive() { .type_params(tuple_meta_type!(bool)) .variant( Variants::with_fields() - .variant("A", Fields::unnamed().field_of::()) - .variant("B", Fields::named().field_of::("b")) + .variant("A", Fields::unnamed().field_of::("T")) + .variant("B", Fields::named().field_of::("b", "T")) .variant_unit("C"), ); @@ -151,14 +155,31 @@ fn recursive_type_derive() { let ty = Type::builder().path(Path::new("Tree", "derive")).variant( Variants::with_fields() - .variant("Leaf", Fields::named().field_of::("value")) + .variant("Leaf", Fields::named().field_of::("value", "i32")) .variant( "Node", Fields::named() - .field_of::>("right") - .field_of::>("left"), + .field_of::>("right", "Box") + .field_of::>("left", "Box"), ), ); assert_type!(Tree, ty); } + +#[test] +fn fields_with_type_alias() { + type BoolAlias = bool; + + #[allow(unused)] + #[derive(TypeInfo)] + struct S { + a: BoolAlias, + } + + let ty = Type::builder() + .path(Path::new("S", "derive")) + .composite(Fields::named().field_of::("a", "BoolAlias")); + + assert_type!(S, ty); +} diff --git a/test_suite/tests/json.rs b/test_suite/tests/json.rs index d472893e..7306d273 100644 --- a/test_suite/tests/json.rs +++ b/test_suite/tests/json.rs @@ -103,7 +103,7 @@ fn test_builtins() { }, { "name": "Some", - "fields": [ { "type": 1 } ] + "fields": [ { "type": 1, "typeName": "T" } ] }, ] } @@ -117,11 +117,11 @@ fn test_builtins() { "variants": [ { "name": "Ok", - "fields": [ { "type": 1 } ] + "fields": [ { "type": 1, "typeName": "T" } ] }, { "name": "Err", - "fields": [ { "type": 2 } ] + "fields": [ { "type": 2, "typeName": "E" } ] } ] } @@ -171,9 +171,9 @@ fn test_tuplestruct() { "def": { "composite": { "fields": [ - { "type": 1 }, - { "type": 2 }, - { "type": 4 }, + { "type": 1, "typeName": "i32" }, + { "type": 2, "typeName": "[u8; 32]" }, + { "type": 4, "typeName": "bool" }, ], }, } @@ -194,9 +194,9 @@ fn test_struct() { "def": { "composite": { "fields": [ - { "name": "a", "type": 1, }, - { "name": "b", "type": 2, }, - { "name": "c", "type": 4, }, + { "name": "a", "type": 1, "typeName": "i32" }, + { "name": "b", "type": 2, "typeName": "[u8; 32]" }, + { "name": "c", "type": 4, "typeName": "bool" }, ], }, } @@ -244,16 +244,16 @@ fn test_enum() { { "name": "TupleStructVariant", "fields": [ - { "type": 1 }, - { "type": 2 }, + { "type": 1, "typeName": "u32" }, + { "type": 2, "typeName": "bool" }, ], }, { "name": "StructVariant", "fields": [ - { "name": "a", "type": 1, }, - { "name": "b", "type": 3, }, - { "name": "c", "type": 5, }, + { "name": "a", "type": 1, "typeName": "u32" }, + { "name": "b", "type": 3, "typeName": "[u8; 32]" }, + { "name": "c", "type": 5, "typeName": "char" }, ], } ], @@ -283,14 +283,14 @@ fn test_recursive_type_with_box() { { "name": "Leaf", "fields": [ - { "name": "value", "type": 2 }, + { "name": "value", "type": 2, "typeName": "i32" }, ], }, { "name": "Node", "fields": [ - { "name": "right", "type": 1, }, - { "name": "left", "type": 1, }, + { "name": "right", "type": 1, "typeName": "Box" }, + { "name": "left", "type": 1, "typeName": "Box" }, ], } ], @@ -363,8 +363,8 @@ fn test_registry() { "def": { "composite": { "fields": [ - { "type": 3 }, - { "type": 4 }, + { "type": 3, "typeName": "u8" }, + { "type": 4, "typeName": "u32" }, ], }, } @@ -385,15 +385,18 @@ fn test_registry() { "fields": [ { "name": "a", - "type": 3, // u8 + "type": 3, + "typeName": "u8" }, { "name": "b", - "type": 4, // u32 + "type": 4, + "typeName": "u32" }, { "name": "c", - "type": 6, // [u8; 32] + "type": 6, + "typeName": "[u8; 32]" } ] }, @@ -417,7 +420,8 @@ fn test_registry() { "fields": [ { "name": "rec", - "type": 8, // Vec + "type": 8, + "typeName": "Vec" } ] }, @@ -468,8 +472,8 @@ fn test_registry() { { "name": "B", "fields": [ - { "type": 3 }, // u8 - { "type": 4 }, // u32 + { "type": 3, "typeName": "u8" }, // u8 + { "type": 4, "typeName": "u32" }, // u32 ] }, { @@ -478,14 +482,17 @@ fn test_registry() { { "name": "a", "type": 3, // u8 + "typeName": "u8" }, { "name": "b", "type": 4, // u32 + "typeName": "u32" }, { "name": "c", - "type": 6, // [u8; 32] + "type": 6, + "typeName": "[u8; 32]" } ] }