From 37c0a577ccd9973ee246b37a558f1b3b2c225391 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 7 Dec 2020 11:48:59 +0000 Subject: [PATCH 01/72] Parameterize CompactForm String for optional SCALE impl By default, parity-scale-codec does not provide Encode/Decode impls for an owned String. This is only provided under the "full" feature which is not used by the substrate runtime, because it should not be used for consensus critical code. So in order for the CompactForm to be integrated into the substrate runtime, or wherever the "full" feature cannot be used, then we must parameterize the `String` type so that it can be both an `&'static str` on the runtime side where it is encoded, and a `String` in client/consuming code where it is decoded. --- src/form.rs | 13 ++++++++----- src/registry.rs | 22 +++++++++++++++------- test_suite/tests/codec.rs | 5 +++-- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/form.rs b/src/form.rs index f2a56ac4..f323123f 100644 --- a/src/form.rs +++ b/src/form.rs @@ -33,7 +33,7 @@ use crate::prelude::{ any::TypeId, fmt::Debug, - string::String, + marker::PhantomData, }; use crate::{ @@ -51,7 +51,7 @@ pub trait Form { /// The type representing the type. type Type: PartialEq + Eq + PartialOrd + Ord + Clone + Debug; /// The string type. - type String: Serialize + PartialEq + Eq + PartialOrd + Ord + Clone + Debug; + type String: PartialEq + Eq + PartialOrd + Ord + Clone + Debug; } /// A meta meta-type. @@ -76,9 +76,12 @@ impl Form for MetaForm { /// /// `type String` is owned in order to enable decoding #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Serialize, Debug)] -pub enum CompactForm {} +pub struct CompactForm(PhantomData); -impl Form for CompactForm { +impl Form for CompactForm +where + S: PartialEq + Eq + PartialOrd + Ord + Clone + Debug, +{ type Type = UntrackedSymbol; - type String = String; + type String = S; } diff --git a/src/registry.rs b/src/registry.rs index 30cc9d24..425df457 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -27,9 +27,9 @@ use crate::prelude::{ any::TypeId, collections::BTreeMap, + fmt::Debug, mem, num::NonZeroU32, - string::ToString, vec::Vec, }; @@ -50,6 +50,7 @@ use scale::{ Encode, }; use serde::{ + de::DeserializeOwned, Deserialize, Serialize, }; @@ -67,7 +68,7 @@ impl IntoCompact for &'static str { type Output = ::String; fn into_compact(self, _registry: &mut Registry) -> Self::Output { - self.to_string() + self } } @@ -201,8 +202,12 @@ impl Registry { /// A read-only registry, to be used for decoding/deserializing #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Decode)] -pub struct RegistryReadOnly { - types: Vec>, +#[serde(bound(serialize = "S: Serialize", deserialize = "S: DeserializeOwned",))] +pub struct RegistryReadOnly +where + S: PartialEq + Eq + PartialOrd + Ord + Clone + Debug, +{ + types: Vec>>, } impl From for RegistryReadOnly { @@ -213,14 +218,17 @@ impl From for RegistryReadOnly { } } -impl RegistryReadOnly { +impl RegistryReadOnly +where + S: PartialEq + Eq + PartialOrd + Ord + Clone + Debug, +{ /// Returns the type definition for the given identifier, `None` if no type found for that ID. - pub fn resolve(&self, id: NonZeroU32) -> Option<&Type> { + pub fn resolve(&self, id: NonZeroU32) -> Option<&Type>> { self.types.get((id.get() - 1) as usize) } /// Returns an iterator for all types paired with their associated NonZeroU32 identifier. - pub fn enumerate(&self) -> impl Iterator)> { + pub fn enumerate(&self) -> impl Iterator>)> { self.types.iter().enumerate().map(|(i, ty)| { let id = NonZeroU32::new(i as u32 + 1).expect("i + 1 > 0; qed"); (id, ty) diff --git a/test_suite/tests/codec.rs b/test_suite/tests/codec.rs index c6ef0461..6d2f398e 100644 --- a/test_suite/tests/codec.rs +++ b/test_suite/tests/codec.rs @@ -28,6 +28,7 @@ use scale_info::{ form::CompactForm, prelude::{ num::NonZeroU32, + string::String, vec, vec::Vec, }, @@ -60,7 +61,7 @@ fn scale_encode_then_decode_to_readonly() { let mut encoded = registry.encode(); let original_serialized = serde_json::to_value(registry).unwrap(); - let readonly_decoded = RegistryReadOnly::decode(&mut &encoded[..]).unwrap(); + let readonly_decoded = RegistryReadOnly::::decode(&mut &encoded[..]).unwrap(); assert!(readonly_decoded .resolve(NonZeroU32::new(1).unwrap()) .is_some()); @@ -76,7 +77,7 @@ fn json_serialize_then_deserialize_to_readonly() { let original_serialized = serde_json::to_value(registry).unwrap(); // assert_eq!(original_serialized, serde_json::Value::Null); - let readonly_deserialized: RegistryReadOnly = + let readonly_deserialized: RegistryReadOnly = serde_json::from_value(original_serialized.clone()).unwrap(); assert!(readonly_deserialized .resolve(NonZeroU32::new(1).unwrap()) From 9a7ccbf5dec5abc6d85244ea7eb1adeec0a8e1f6 Mon Sep 17 00:00:00 2001 From: David Palm Date: Mon, 14 Dec 2020 12:44:07 +0100 Subject: [PATCH 02/72] Fix no-std compilation --- src/form.rs | 3 ++- src/registry.rs | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/form.rs b/src/form.rs index 30537ba2..ae8a0db2 100644 --- a/src/form.rs +++ b/src/form.rs @@ -78,7 +78,8 @@ impl Form for MetaForm { /// underlying data. /// /// `type String` is owned in order to enable decoding -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Serialize, Debug)] +#[cfg_attr(feature = "serde", derive(Serialize))] +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)] pub struct CompactForm(PhantomData); impl Form for CompactForm diff --git a/src/registry.rs b/src/registry.rs index 4945e0dc..7fc0b42a 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -204,8 +204,9 @@ impl Registry { } /// A read-only registry, to be used for decoding/deserializing -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Decode)] -#[serde(bound(serialize = "S: Serialize", deserialize = "S: DeserializeOwned",))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, PartialEq, Eq, Decode)] +#[cfg_attr(feature = "serde", serde(bound(serialize = "S: Serialize", deserialize = "S: DeserializeOwned")))] pub struct RegistryReadOnly where S: PartialEq + Eq + PartialOrd + Ord + Clone + Debug, From 254fee129b5a66b7a61998654b5f04ece22c4ec7 Mon Sep 17 00:00:00 2001 From: David Palm Date: Mon, 14 Dec 2020 12:47:33 +0100 Subject: [PATCH 03/72] Obey the fmt --- src/registry.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/registry.rs b/src/registry.rs index 7fc0b42a..446c199c 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -206,7 +206,10 @@ impl Registry { /// A read-only registry, to be used for decoding/deserializing #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, PartialEq, Eq, Decode)] -#[cfg_attr(feature = "serde", serde(bound(serialize = "S: Serialize", deserialize = "S: DeserializeOwned")))] +#[cfg_attr( + feature = "serde", + serde(bound(serialize = "S: Serialize", deserialize = "S: DeserializeOwned")) +)] pub struct RegistryReadOnly where S: PartialEq + Eq + PartialOrd + Ord + Clone + Debug, From e74e4f9eb3e11b3895bec5d17327f1eed84de546 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 16 Dec 2020 09:50:25 +0000 Subject: [PATCH 04/72] Introduce String trait for Form --- src/form.rs | 14 ++++++++++++-- src/registry.rs | 5 +++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/form.rs b/src/form.rs index ae8a0db2..2e21cd37 100644 --- a/src/form.rs +++ b/src/form.rs @@ -34,6 +34,7 @@ use crate::prelude::{ any::TypeId, fmt::Debug, marker::PhantomData, + string::String, }; use crate::{ @@ -53,9 +54,18 @@ pub trait Form { /// The type representing the type. type Type: PartialEq + Eq + PartialOrd + Ord + Clone + Debug; /// The string type. - type String: PartialEq + Eq + PartialOrd + Ord + Clone + Debug; + type String: FormString; } +/// Trait for types which can be used to represent strings in type definitions. +pub trait FormString: + AsRef + PartialEq + Eq + PartialOrd + Ord + Clone + Debug +{ +} + +impl FormString for &'static str {} +impl FormString for String {} + /// A meta meta-type. /// /// Allows to be converted into other forms such as compact form @@ -84,7 +94,7 @@ pub struct CompactForm(PhantomData); impl Form for CompactForm where - S: PartialEq + Eq + PartialOrd + Ord + Clone + Debug, + S: FormString, { type Type = UntrackedSymbol; type String = S; diff --git a/src/registry.rs b/src/registry.rs index 446c199c..016f8719 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -37,6 +37,7 @@ use crate::{ form::{ CompactForm, Form, + FormString, }, interner::{ Interner, @@ -212,7 +213,7 @@ impl Registry { )] pub struct RegistryReadOnly where - S: PartialEq + Eq + PartialOrd + Ord + Clone + Debug, + S: FormString, { types: Vec>>, } @@ -227,7 +228,7 @@ impl From for RegistryReadOnly { impl RegistryReadOnly where - S: PartialEq + Eq + PartialOrd + Ord + Clone + Debug, + S: FormString, { /// Returns the type definition for the given identifier, `None` if no type found for that ID. pub fn resolve(&self, id: NonZeroU32) -> Option<&Type>> { From 7860c791ea2befb79a451216b2cdf12fa148711c Mon Sep 17 00:00:00 2001 From: David Palm Date: Wed, 16 Dec 2020 11:22:20 +0100 Subject: [PATCH 05/72] Rename "Compact" to "Frozen" (and associated fallout) Add a `compact` member to `Field` to indicate it is `scale_codec::Compact` --- src/form.rs | 6 +- src/lib.rs | 45 ++++++----- src/registry.rs | 38 ++++----- src/tests.rs | 25 ++++++ src/ty/composite.rs | 12 +-- src/ty/fields.rs | 39 +++++++--- src/ty/mod.rs | 49 ++++++------ src/ty/path.rs | 16 ++-- src/ty/variant.rs | 22 +++--- test_suite/tests/codec.rs | 4 +- test_suite/tests/derive.rs | 156 ++++++++++++++++++++++++++++++++++++- test_suite/tests/json.rs | 6 +- 12 files changed, 309 insertions(+), 109 deletions(-) diff --git a/src/form.rs b/src/form.rs index ae8a0db2..c9302f99 100644 --- a/src/form.rs +++ b/src/form.rs @@ -22,7 +22,7 @@ //! It uses `MetaType` for communicating type identifiers and thus acts as //! a bridge from runtime to compile time type information. //! -//! The compact form is `CompactForm` and represents a compact form +//! The compact form is `FrozenForm` and represents a compact form //! that no longer has any connections to the interning registry and thus //! can no longer be used in order to retrieve information from the //! original registry easily. Its sole purpose is for compact serialization. @@ -80,9 +80,9 @@ impl Form for MetaForm { /// `type String` is owned in order to enable decoding #[cfg_attr(feature = "serde", derive(Serialize))] #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)] -pub struct CompactForm(PhantomData); +pub struct FrozenForm(PhantomData); -impl Form for CompactForm +impl Form for FrozenForm where S: PartialEq + Eq + PartialOrd + Ord + Clone + Debug, { diff --git a/src/lib.rs b/src/lib.rs index 4446005c..fb86ed29 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,49 +15,52 @@ #![cfg_attr(not(feature = "std"), no_std)] #![deny(missing_docs)] -//! Efficient and compact serialization of Rust types. +//! Efficient and space-efficient serialization of Rust types. //! //! This library provides structures to easily retrieve compile-time type -//! information at runtime and also to serialize this information in a compact -//! form. +//! information at runtime and also to serialize this information in a +//! space-efficient form, aka `FrozenForm`. //! //! # Registry //! -//! At the heart of its functionality is the [`Registry`](`crate::Registry`) that acts as cache for -//! known types in order to efficiently deduplicate them and thus compactify the overall -//! serialization. +//! At the heart of its functionality is the [`Registry`](`crate::Registry`) +//! that acts as a cache for known types in order to efficiently deduplicate +//! types and ensure a space-efficient serialization. //! //! # Type Information //! //! Information about types is provided via the [`TypeInfo`](`crate::TypeInfo`) trait. //! //! This trait should be implemented for all types that are serializable. -//! For this the library provides implementations for all commonly used Rust -//! standard types and provides derive macros for simpler implementation of user -//! provided custom types. +//! `scale-info` provides implementations for all commonly used Rust standard +//! types and a derive macro for implementing of custom types. //! //! # Compaction Forms //! -//! There is an uncompact form, called [`MetaForm`](`crate::form::MetaForm`) that acts as a bridge -//! from compile-time type information at runtime in order to easily retrieve all information needed +//! There is an expanded form, called [`MetaForm`](`crate::form::MetaForm`) that acts as a bridge +//! between compile-time type information and runtime, in order to easily retrieve all information needed //! to uniquely identify types. //! -//! The compact form is retrieved by the [`IntoCompact`](`crate::IntoCompact`) trait and internally -//! used by the [`Registry`](`crate::Registry`) in order to convert the uncompact types -//! into their compact form. +//! The `MetaForm` and its associated `Registry` can be transformed into the +//! space-efficient and universal form by the +//! [`IntoFrozen`](`crate::IntoFrozen`) trait and internally used by the +//! [`Registry`](`crate::Registry`) in order to convert the expanded types into +//! their space-efficient form. //! //! # Symbols and Namespaces //! -//! To differentiate two types sharing the same name namespaces are used. +//! To differentiate two types sharing the same name, namespaces are used. //! Commonly the namespace is equal to the one where the type has been defined in. For Rust prelude //! types such as [`Option`](`std::option::Option`) and [`Result`](`std::result::Result`) the root //! namespace (empty namespace) is used. //! -//! To use this library simply use the [`MetaForm`](`crate::form::MetaForm`) initially with your own data -//! structures and at best make them generic over the [`Form`](`crate::form::Form`) trait just as has -//! been done in this crate with [`TypeInfo`](`crate::TypeInfo`) in order to go for a simple -//! implementation of [`IntoCompact`](`crate::IntoCompact`). Use a single instance of the [`Registry`](`crate::Registry`) for -//! compaction and provide this registry instance upon serialization. Done. +//! To use this library simply use the [`MetaForm`](`crate::form::MetaForm`) +//! initially with your own data structures; make them generic over the +//! [`Form`](`crate::form::Form`) trait just as has been done in this crate with +//! [`TypeInfo`](`crate::TypeInfo`) in order to get a simple implementation of +//! [`IntoFrozen`](`crate::IntoFrozen`). +//! Use a single instance of the [`Registry`](`crate::Registry`) for compaction +//! and provide this registry instance upon serialization. Done. //! //! A usage example can be found in ink! here: //! https://github.com/paritytech/ink/blob/master/abi/src/specs.rs @@ -115,7 +118,7 @@ mod tests; pub use self::{ meta_type::MetaType, registry::{ - IntoCompact, + IntoFrozen, Registry, RegistryReadOnly, }, diff --git a/src/registry.rs b/src/registry.rs index 446c199c..82e63c5f 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -35,7 +35,7 @@ use crate::prelude::{ use crate::{ form::{ - CompactForm, + FrozenForm, Form, }, interner::{ @@ -56,19 +56,19 @@ use serde::{ Serialize, }; -/// Compacts the implementor using a registry. -pub trait IntoCompact { - /// The compact version of `Self`. +/// Freezes the type definition using a registry. +pub trait IntoFrozen { + /// The frozen version of `Self`. type Output; - /// Compacts `self` by using the registry for caching and compaction. - fn into_compact(self, registry: &mut Registry) -> Self::Output; + /// "Freezes" `self` by using the registry for caching and compaction. + fn into_frozen(self, registry: &mut Registry) -> Self::Output; } -impl IntoCompact for &'static str { - type Output = ::String; +impl IntoFrozen for &'static str { + type Output = ::String; - fn into_compact(self, _registry: &mut Registry) -> Self::Output { + fn into_frozen(self, _registry: &mut Registry) -> Self::Output { self } } @@ -98,14 +98,14 @@ pub struct Registry { /// /// This is going to be serialized upon serlialization. #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_registry_types"))] - types: BTreeMap, Type>, + types: BTreeMap, Type>, } /// Serializes the types of the registry by removing their unique IDs /// and instead serialize them in order of their removed unique ID. #[cfg(feature = "serde")] fn serialize_registry_types( - types: &BTreeMap, Type>, + types: &BTreeMap, Type>, serializer: S, ) -> Result where @@ -123,7 +123,7 @@ impl Default for Registry { impl Encode for Registry { fn size_hint(&self) -> usize { - mem::size_of::() + mem::size_of::>() * self.types.len() + mem::size_of::() + mem::size_of::>() * self.types.len() } fn encode_to(&self, dest: &mut W) { @@ -174,7 +174,7 @@ impl Registry { pub fn register_type(&mut self, ty: &MetaType) -> UntrackedSymbol { let (inserted, symbol) = self.intern_type_id(ty.type_id()); if inserted { - let compact_id = ty.type_info().into_compact(self); + let compact_id = ty.type_info().into_frozen(self); self.types.insert(symbol, compact_id); } symbol @@ -192,13 +192,13 @@ impl Registry { /// Converts an iterator into a Vec of the equivalent compact /// representations - pub fn map_into_compact(&mut self, iter: I) -> Vec + pub fn map_into_frozen(&mut self, iter: I) -> Vec where I: IntoIterator, - T: IntoCompact, + T: IntoFrozen, { iter.into_iter() - .map(|i| i.into_compact(self)) + .map(|i| i.into_frozen(self)) .collect::>() } } @@ -214,7 +214,7 @@ pub struct RegistryReadOnly where S: PartialEq + Eq + PartialOrd + Ord + Clone + Debug, { - types: Vec>>, + types: Vec>>, } impl From for RegistryReadOnly { @@ -230,12 +230,12 @@ where S: PartialEq + Eq + PartialOrd + Ord + Clone + Debug, { /// Returns the type definition for the given identifier, `None` if no type found for that ID. - pub fn resolve(&self, id: NonZeroU32) -> Option<&Type>> { + pub fn resolve(&self, id: NonZeroU32) -> Option<&Type>> { self.types.get((id.get() - 1) as usize) } /// Returns an iterator for all types paired with their associated NonZeroU32 identifier. - pub fn enumerate(&self) -> impl Iterator>)> { + pub fn enumerate(&self) -> impl Iterator>)> { self.types.iter().enumerate().map(|(i, ty)| { let id = NonZeroU32::new(i as u32 + 1).expect("i + 1 > 0; qed"); (id, ty) diff --git a/src/tests.rs b/src/tests.rs index 1552490c..73671ae2 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -154,3 +154,28 @@ fn struct_with_generics() { .composite(Fields::named().field_of::>>("data", "T")); assert_type!(SelfTyped, expected_type); } + +#[test] +fn struct_with_compact() { + use scale::Encode; + #[allow(unused)] + #[derive(Encode)] + struct Thicc { + #[codec(compact)] + stuff: u8 + } + + impl TypeInfo for Thicc { + type Identity = Self; + + fn type_info() -> Type { + Type::builder() + .path(Path::new("Thicc", module_path!())) + .composite(Fields::named().field_of::("stuff", "u8")) + .into() + } + } + + fn assert_type_info() {} + assert_type_info::(); +} diff --git a/src/ty/composite.rs b/src/ty/composite.rs index 6571bd38..2ec039d8 100644 --- a/src/ty/composite.rs +++ b/src/ty/composite.rs @@ -16,12 +16,12 @@ use crate::prelude::vec::Vec; use crate::{ form::{ - CompactForm, + FrozenForm, Form, MetaForm, }, Field, - IntoCompact, + IntoFrozen, Registry, }; use derive_more::From; @@ -81,12 +81,12 @@ pub struct TypeDefComposite { fields: Vec>, } -impl IntoCompact for TypeDefComposite { - type Output = TypeDefComposite; +impl IntoFrozen for TypeDefComposite { + type Output = TypeDefComposite; - fn into_compact(self, registry: &mut Registry) -> Self::Output { + fn into_frozen(self, registry: &mut Registry) -> Self::Output { TypeDefComposite { - fields: registry.map_into_compact(self.fields), + fields: registry.map_into_frozen(self.fields), } } } diff --git a/src/ty/fields.rs b/src/ty/fields.rs index 0b5755a3..e2bea876 100644 --- a/src/ty/fields.rs +++ b/src/ty/fields.rs @@ -14,11 +14,11 @@ use crate::{ form::{ - CompactForm, + FrozenForm, Form, MetaForm, }, - IntoCompact, + IntoFrozen, MetaType, Registry, TypeInfo, @@ -34,11 +34,12 @@ use serde::{ Serialize, }; -/// A field of a struct like data type. +/// A field of a struct-like data type. /// /// Name is optional so it can represent both named and unnamed fields. /// -/// This can be a named field of a struct type or an enum struct variant. +/// This can be a named field of a struct type or an enum struct variant, or an +/// unnamed field of a tuple struct. /// /// # Type name /// @@ -60,8 +61,9 @@ use serde::{ /// 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. +/// 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. #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde", @@ -84,16 +86,29 @@ pub struct Field { ty: T::Type, /// The name of the type of the field as it appears in the source code. type_name: T::String, + /// Should be encode/decoded as a [`Compact`](parity_scale_codec::Compact) field + #[cfg_attr( + feature = "serde", + serde(skip_serializing_if = "is_false", default) + )] + compact: bool, +} + +/// TODO: There must be a better way than this +#[allow(unused)] +fn is_false(v: &bool) -> bool { + !v } -impl IntoCompact for Field { - type Output = Field; +impl IntoFrozen for Field { + type Output = Field; - fn into_compact(self, registry: &mut Registry) -> Self::Output { + fn into_frozen(self, registry: &mut Registry) -> Self::Output { Field { - name: self.name.map(|name| name.into_compact(registry)), + name: self.name.map(|name| name.into_frozen(registry)), ty: registry.register_type(&self.ty), - type_name: self.type_name.into_compact(registry), + type_name: self.type_name.into_frozen(registry), + compact: false, } } } @@ -106,11 +121,13 @@ impl Field { name: Option<&'static str>, ty: MetaType, type_name: &'static str, + // TODO: dp add compact arg (and use it) ) -> Self { Self { name, ty, type_name, + compact: false, } } diff --git a/src/ty/mod.rs b/src/ty/mod.rs index 81ff9805..3dbb29ff 100644 --- a/src/ty/mod.rs +++ b/src/ty/mod.rs @@ -20,11 +20,11 @@ use crate::prelude::{ use crate::{ build::TypeBuilder, form::{ - CompactForm, + FrozenForm, Form, MetaForm, }, - IntoCompact, + IntoFrozen, MetaType, Registry, TypeInfo, @@ -80,16 +80,17 @@ pub struct Type { /// The actual type definition #[cfg_attr(feature = "serde", serde(rename = "def"))] type_def: TypeDef, + // TODO: dp Should we have a `compact` flag here too? Or only here? } -impl IntoCompact for Type { - type Output = Type; +impl IntoFrozen for Type { + type Output = Type; - fn into_compact(self, registry: &mut Registry) -> Self::Output { + fn into_frozen(self, registry: &mut Registry) -> Self::Output { Type { - path: self.path.into_compact(registry), + path: self.path.into_frozen(registry), type_params: registry.register_types(self.type_params), - type_def: self.type_def.into_compact(registry), + type_def: self.type_def.into_frozen(registry), } } } @@ -183,16 +184,16 @@ pub enum TypeDef { Primitive(TypeDefPrimitive), } -impl IntoCompact for TypeDef { - type Output = TypeDef; +impl IntoFrozen for TypeDef { + type Output = TypeDef; - fn into_compact(self, registry: &mut Registry) -> Self::Output { + fn into_frozen(self, registry: &mut Registry) -> Self::Output { match self { - TypeDef::Composite(composite) => composite.into_compact(registry).into(), - TypeDef::Variant(variant) => variant.into_compact(registry).into(), - TypeDef::Sequence(sequence) => sequence.into_compact(registry).into(), - TypeDef::Array(array) => array.into_compact(registry).into(), - TypeDef::Tuple(tuple) => tuple.into_compact(registry).into(), + TypeDef::Composite(composite) => composite.into_frozen(registry).into(), + TypeDef::Variant(variant) => variant.into_frozen(registry).into(), + TypeDef::Sequence(sequence) => sequence.into_frozen(registry).into(), + TypeDef::Array(array) => array.into_frozen(registry).into(), + TypeDef::Tuple(tuple) => tuple.into_frozen(registry).into(), TypeDef::Primitive(primitive) => primitive.into(), } } @@ -253,10 +254,10 @@ pub struct TypeDefArray { type_param: T::Type, } -impl IntoCompact for TypeDefArray { - type Output = TypeDefArray; +impl IntoFrozen for TypeDefArray { + type Output = TypeDefArray; - fn into_compact(self, registry: &mut Registry) -> Self::Output { + fn into_frozen(self, registry: &mut Registry) -> Self::Output { TypeDefArray { len: self.len, type_param: registry.register_type(&self.type_param), @@ -303,10 +304,10 @@ pub struct TypeDefTuple { fields: Vec, } -impl IntoCompact for TypeDefTuple { - type Output = TypeDefTuple; +impl IntoFrozen for TypeDefTuple { + type Output = TypeDefTuple; - fn into_compact(self, registry: &mut Registry) -> Self::Output { + fn into_frozen(self, registry: &mut Registry) -> Self::Output { TypeDefTuple { fields: registry.register_types(self.fields), } @@ -356,10 +357,10 @@ pub struct TypeDefSequence { type_param: T::Type, } -impl IntoCompact for TypeDefSequence { - type Output = TypeDefSequence; +impl IntoFrozen for TypeDefSequence { + type Output = TypeDefSequence; - fn into_compact(self, registry: &mut Registry) -> Self::Output { + fn into_frozen(self, registry: &mut Registry) -> Self::Output { TypeDefSequence { type_param: registry.register_type(&self.type_param), } diff --git a/src/ty/path.rs b/src/ty/path.rs index 3a60df0b..c8f6fa32 100644 --- a/src/ty/path.rs +++ b/src/ty/path.rs @@ -24,12 +24,12 @@ use crate::prelude::{ use crate::{ form::{ - CompactForm, + FrozenForm, Form, MetaForm, }, utils::is_rust_identifier, - IntoCompact, + IntoFrozen, Registry, }; use scale::{ @@ -76,17 +76,17 @@ where } } -impl IntoCompact for Path { - type Output = Path; +impl IntoFrozen for Path { + type Output = Path; - fn into_compact(self, registry: &mut Registry) -> Self::Output { + fn into_frozen(self, registry: &mut Registry) -> Self::Output { Path { - segments: registry.map_into_compact(self.segments), + segments: registry.map_into_frozen(self.segments), } } } -impl Display for Path { +impl Display for Path { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { write!(f, "{}", self.segments.join("::")) } @@ -254,7 +254,7 @@ mod tests { #[test] fn path_display() { let path = - Path::new("Planet", "hello::world").into_compact(&mut Default::default()); + Path::new("Planet", "hello::world").into_frozen(&mut Default::default()); assert_eq!("hello::world::Planet", format!("{}", path)) } } diff --git a/src/ty/variant.rs b/src/ty/variant.rs index f3aa6c64..4f31af47 100644 --- a/src/ty/variant.rs +++ b/src/ty/variant.rs @@ -17,12 +17,12 @@ use crate::prelude::vec::Vec; use crate::{ build::FieldsBuilder, form::{ - CompactForm, + FrozenForm, Form, MetaForm, }, Field, - IntoCompact, + IntoFrozen, Registry, }; use derive_more::From; @@ -94,12 +94,12 @@ pub struct TypeDefVariant { variants: Vec>, } -impl IntoCompact for TypeDefVariant { - type Output = TypeDefVariant; +impl IntoFrozen for TypeDefVariant { + type Output = TypeDefVariant; - fn into_compact(self, registry: &mut Registry) -> Self::Output { + fn into_frozen(self, registry: &mut Registry) -> Self::Output { TypeDefVariant { - variants: registry.map_into_compact(self.variants), + variants: registry.map_into_frozen(self.variants), } } } @@ -173,13 +173,13 @@ pub struct Variant { discriminant: Option, } -impl IntoCompact for Variant { - type Output = Variant; +impl IntoFrozen for Variant { + type Output = Variant; - fn into_compact(self, registry: &mut Registry) -> Self::Output { + fn into_frozen(self, registry: &mut Registry) -> Self::Output { Variant { - name: self.name.into_compact(registry), - fields: registry.map_into_compact(self.fields), + name: self.name.into_frozen(registry), + fields: registry.map_into_frozen(self.fields), discriminant: self.discriminant, } } diff --git a/test_suite/tests/codec.rs b/test_suite/tests/codec.rs index 6d2f398e..0c4bd0e0 100644 --- a/test_suite/tests/codec.rs +++ b/test_suite/tests/codec.rs @@ -25,14 +25,14 @@ use scale::{ Encode, }; use scale_info::{ - form::CompactForm, + form::FrozenForm, prelude::{ num::NonZeroU32, string::String, vec, vec::Vec, }, - IntoCompact as _, + IntoFrozen as _, MetaType, Registry, RegistryReadOnly, diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index a3f7b59b..fdb29533 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -11,7 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. - +// #![feature(box_syntax)] #![cfg_attr(not(feature = "std"), no_std)] use scale_info::prelude::boxed::Box; @@ -216,3 +216,157 @@ fn ui_tests() { t.pass("tests/ui/pass_basic_generic_type.rs"); t.pass("tests/ui/pass_complex_generic_self_referential_type.rs"); } + +#[test] +fn substrate_example() { + use scale::{ + // Decode, + Encode, Compact, + }; + use scale_info::prelude::vec::Vec; + // #[allow(unused)] + // type AccountIndex = u32; + /// A multi-format address wrapper for on-chain accounts. + #[allow(unused)] + // #[derive(Encode, Decode, PartialEq, Eq, Clone, TypeInfo)] + #[derive(Encode, TypeInfo)] + #[cfg_attr(feature = "std", derive(Hash))] + pub enum MultiAddress { + /// It's an account ID (pubkey). + Id(AccountId), + /// It's an account index. + // Index(#[codec(compact)] AccountIndex), + Index(Compact), + /// It's some arbitrary raw bytes. + Raw(Vec), + /// It's a 32 byte representation. + Address32([u8; 32]), + /// Its a 20 byte representation. + Address20([u8; 20]), + } + + let _ma = MultiAddress::::Id(32); +} + +// #[ignore] +// fn substrate_example_expanded() { +// use scale::{Decode, Encode, Compact}; +// use scale_info::prelude::vec::Vec; +// /// A multi-format address wrapper for on-chain accounts. +// #[allow(unused)] +// pub enum MultiAddress { +// /// It's an account ID (pubkey). +// Id(AccountId), +// /// It's an account index. +// // Index(#[codec(compact)] AccountIndex), +// Index(Compact), +// /// It's some arbitrary raw bytes. +// Raw(Vec), +// /// It's a 32 byte representation. +// Address32([u8; 32]), +// /// Its a 20 byte representation. +// Address20([u8; 20]), +// } + +// const _IMPL_TYPE_INFO_FOR_MultiAddress: () = { +// impl< +// AccountId: ::scale_info::TypeInfo + 'static, +// AccountIndex: ::scale_info::TypeInfo + 'static, +// > ::scale_info::TypeInfo for MultiAddress +// where +// AccountId: ::scale_info::TypeInfo + 'static, +// AccountIndex: ::scale_info::TypeInfo + 'static, +// { +// type Identity = Self; +// fn type_info() -> ::scale_info::Type { +// ::scale_info::Type::builder() +// .path(::scale_info::Path::new("MultiAddress", "derive")) +// .type_params(<[_]>::into_vec(box [ +// ::scale_info::meta_type::(), +// ::scale_info::meta_type::(), +// ])) +// .variant( +// ::scale_info::build::Variants::with_fields() +// .variant( +// "Id", +// ::scale_info::build::Fields::unnamed() +// .field_of::("AccountId"), +// ) +// .variant( +// "Index", +// ::scale_info::build::Fields::unnamed() +// .field_of::("AccountIndex"), +// ) +// .variant( +// "Raw", +// ::scale_info::build::Fields::unnamed() +// .field_of::>("Vec"), +// ) +// .variant( +// "Address32", +// ::scale_info::build::Fields::unnamed() +// .field_of::<[u8; 32]>("[u8; 32]"), +// ) +// .variant( +// "Address20", +// ::scale_info::build::Fields::unnamed() +// .field_of::<[u8; 20]>("[u8; 20]"), +// ), +// ) +// .into() +// } +// }; +// }; + +// const _: () = { +// #[allow(unknown_lints)] +// #[allow(rust_2018_idioms)] +// extern crate scale as _parity_scale_codec; +// impl _parity_scale_codec::Encode for MultiAddress +// where +// AccountId: _parity_scale_codec::Encode, +// AccountId: _parity_scale_codec::Encode, +// AccountIndex: _parity_scale_codec::HasCompact, +// { +// fn encode_to<__CodecOutputEdqy: _parity_scale_codec::Output>( +// &self, +// __codec_dest_edqy: &mut __CodecOutputEdqy, +// ) { +// match *self { +// MultiAddress::Id(ref aa) => { +// __codec_dest_edqy.push_byte(0usize as u8); +// __codec_dest_edqy.push(aa); +// } +// MultiAddress::Index(ref aa) => { +// __codec_dest_edqy.push_byte(1usize as u8); +// { +// __codec_dest_edqy.push (&<::Type as _parity_scale_codec::EncodeAsRef< '_ , AccountIndex >>::RefType::from(aa)); +// } +// } +// MultiAddress::Raw(ref aa) => { +// __codec_dest_edqy.push_byte(2usize as u8); +// __codec_dest_edqy.push(aa); +// } +// MultiAddress::Address32(ref aa) => { +// __codec_dest_edqy.push_byte(3usize as u8); +// __codec_dest_edqy.push(aa); +// } +// MultiAddress::Address20(ref aa) => { +// __codec_dest_edqy.push_byte(4usize as u8); +// __codec_dest_edqy.push(aa); +// } +// _ => (), +// } +// } +// } +// impl _parity_scale_codec::EncodeLike +// for MultiAddress +// where +// AccountId: _parity_scale_codec::Encode, +// AccountId: _parity_scale_codec::Encode, +// AccountIndex: _parity_scale_codec::HasCompact, +// { +// } +// }; +// let _ma = MultiAddress::::Id(32); +// } diff --git a/test_suite/tests/json.rs b/test_suite/tests/json.rs index 5fd84585..5c3e3d7c 100644 --- a/test_suite/tests/json.rs +++ b/test_suite/tests/json.rs @@ -28,9 +28,9 @@ use pretty_assertions::{ assert_ne, }; use scale_info::{ - form::CompactForm, + form::FrozenForm, meta_type, - IntoCompact as _, + IntoFrozen as _, Registry, TypeInfo, }; @@ -42,7 +42,7 @@ where { let mut registry = Registry::new(); - let ty = T::type_info().into_compact(&mut registry); + let ty = T::type_info().into_frozen(&mut registry); assert_eq!(serde_json::to_value(ty).unwrap(), expected_json,); } From 579f95893e0a73cd06bb555f79922d41bda47e95 Mon Sep 17 00:00:00 2001 From: David Palm Date: Thu, 17 Dec 2020 16:15:59 +0100 Subject: [PATCH 06/72] Docs cleanup and more renames --- src/build.rs | 12 +++++++++++ src/form.rs | 23 ++++++++++---------- src/interner.rs | 9 ++++---- src/lib.rs | 31 ++++++++++++++------------- src/registry.rs | 44 +++++++++++++++++++------------------- src/tests.rs | 12 ++++++++--- src/ty/fields.rs | 14 ++++++++---- src/ty/mod.rs | 1 - test_suite/tests/derive.rs | 1 + test_suite/tests/json.rs | 43 +++++++++++++++++++++++++++++++++++++ 10 files changed, 129 insertions(+), 61 deletions(-) diff --git a/src/build.rs b/src/build.rs index c55cbfad..9667290c 100644 --- a/src/build.rs +++ b/src/build.rs @@ -248,6 +248,18 @@ impl FieldsBuilder { pub fn finalize(self) -> Vec> { self.fields } + + /// Mark last field as compact, meaning that encoding/decoding should be in the [`scale_codec::Compact`] format. + pub fn compact(mut self) -> Self { + self.fields + .iter_mut() + .last() + .and_then(|f| { + f.compact(); + Some(f) + }); + self + } } impl FieldsBuilder { diff --git a/src/form.rs b/src/form.rs index c9302f99..dd6e1f0d 100644 --- a/src/form.rs +++ b/src/form.rs @@ -12,22 +12,21 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Provides some form definitions. +//! Provides form definitions. //! -//! The forms provided here are used to generically communicate the -//! compaction mode a type identifier, type definition or structures -//! that are using these. +//! The forms provided here are used to generically communicate the mode a type +//! identifier, type definition or structure is using. //! //! The default form is the `MetaForm`. //! It uses `MetaType` for communicating type identifiers and thus acts as //! a bridge from runtime to compile time type information. //! -//! The compact form is `FrozenForm` and represents a compact form +//! The `FrozenForm` is a space-efficient representation //! that no longer has any connections to the interning registry and thus -//! can no longer be used in order to retrieve information from the -//! original registry easily. Its sole purpose is for compact serialization. +//! can no longer be used to retrieve information from the +//! original registry. Its sole purpose is for space-efficient serialization. //! -//! Other forms, such as a compact form that is still bound to the registry +//! Other forms, such as a frozen form that is still bound to the registry //! (also via lifetime tracking) are possible but current not needed. use crate::prelude::{ @@ -47,7 +46,7 @@ use serde::Serialize; /// Trait to control the internal structures of type definitions. /// /// This allows for type-level separation between free forms that can be -/// instantiated out of the flux and compact forms that require some sort of +/// instantiated out of the flux and frozen forms that require some sort of /// interning data structures. pub trait Form { /// The type representing the type. @@ -58,8 +57,8 @@ pub trait Form { /// A meta meta-type. /// -/// Allows to be converted into other forms such as compact form -/// through the registry and `IntoCompact`. +/// Allows to be converted into other forms such as frozen form +/// through the registry and `IntoFrozen`. #[cfg_attr(feature = "serde", derive(Serialize))] #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)] pub enum MetaForm {} @@ -69,7 +68,7 @@ impl Form for MetaForm { type String = &'static str; } -/// Compact form that has its lifetime untracked in association to its interner. +/// Frozen form that has its lifetime untracked in association to its interner. /// /// # Note /// diff --git a/src/interner.rs b/src/interner.rs index 61845735..44f2db51 100644 --- a/src/interner.rs +++ b/src/interner.rs @@ -14,12 +14,13 @@ //! Interning data structure and associated symbol definitions. //! -//! The interner is used by the registry in order to compact strings and type +//! The interner is used by the registry in order to deduplicate strings and type //! definitions. Strings are uniquely identified by their contents while types //! are uniquely identified by their respective type identifiers. //! -//! The interners provide a strict ordered sequence of cached (aka interned) -//! elements and is later used for compact serialization within the registry. +//! The interners provide a strict ordered sequence of cached (interned) +//! elements and is later used for space-efficient serialization within the +//! registry. use crate::prelude::{ collections::btree_map::{ @@ -127,7 +128,7 @@ impl Symbol<'_, T> { #[cfg_attr(feature = "serde", derive(Serialize))] #[cfg_attr(feature = "serde", serde(transparent))] pub struct Interner { - /// A mapping from the interned elements to their respective compact + /// A mapping from the interned elements to their respective space-efficient /// identifiers. /// /// The idenfitiers can be used to retrieve information about the original diff --git a/src/lib.rs b/src/lib.rs index fb86ed29..ae35d85d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,38 +29,39 @@ //! //! # Type Information //! -//! Information about types is provided via the [`TypeInfo`](`crate::TypeInfo`) trait. +//! Information about types is provided via the [`TypeInfo`](`crate::TypeInfo`) +//! trait. //! //! This trait should be implemented for all types that are serializable. //! `scale-info` provides implementations for all commonly used Rust standard //! types and a derive macro for implementing of custom types. //! -//! # Compaction Forms +//! # Forms //! -//! There is an expanded form, called [`MetaForm`](`crate::form::MetaForm`) that acts as a bridge -//! between compile-time type information and runtime, in order to easily retrieve all information needed -//! to uniquely identify types. +//! There is an expanded form, called [`MetaForm`](`crate::form::MetaForm`) that +//! acts as a bridge between compile-time type information and runtime, in order +//! to easily retrieve all information needed to uniquely identify types. //! //! The `MetaForm` and its associated `Registry` can be transformed into the -//! space-efficient and universal form by the -//! [`IntoFrozen`](`crate::IntoFrozen`) trait and internally used by the -//! [`Registry`](`crate::Registry`) in order to convert the expanded types into -//! their space-efficient form. +//! space-efficient form by the [`IntoFrozen`](`crate::IntoFrozen`) trait; it is +//! used internally by the [`Registry`](`crate::Registry`) in order to convert +//! the expanded types into their space-efficient form. //! //! # Symbols and Namespaces //! //! To differentiate two types sharing the same name, namespaces are used. -//! Commonly the namespace is equal to the one where the type has been defined in. For Rust prelude -//! types such as [`Option`](`std::option::Option`) and [`Result`](`std::result::Result`) the root -//! namespace (empty namespace) is used. +//! Commonly the namespace is equal to the one where the type has been defined +//! in. For Rust prelude types such as [`Option`](`std::option::Option`) and +//! [`Result`](`std::result::Result`) the root namespace (empty namespace) is +//! used. //! //! To use this library simply use the [`MetaForm`](`crate::form::MetaForm`) //! initially with your own data structures; make them generic over the //! [`Form`](`crate::form::Form`) trait just as has been done in this crate with //! [`TypeInfo`](`crate::TypeInfo`) in order to get a simple implementation of -//! [`IntoFrozen`](`crate::IntoFrozen`). -//! Use a single instance of the [`Registry`](`crate::Registry`) for compaction -//! and provide this registry instance upon serialization. Done. +//! [`IntoFrozen`](`crate::IntoFrozen`). Use a single instance of the +//! [`Registry`](`crate::Registry`) for compaction and provide this registry +//! instance upon serialization. //! //! A usage example can be found in ink! here: //! https://github.com/paritytech/ink/blob/master/abi/src/specs.rs diff --git a/src/registry.rs b/src/registry.rs index 82e63c5f..393c526b 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -12,17 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! The registry has the purpose to compactify types found in type definitions. +//! The registry stores type definitions in a space-efficient manner. //! -//! This is done by deduplicating common types in order to reuse -//! their definitions which can grow arbitrarily large. A type is uniquely +//! This is done by deduplicating common types in order to reuse their +//! definitions which otherwise can grow arbitrarily large. A type is uniquely //! identified by its type identifier that is therefore used to refer to types //! and their definitions. //! //! Types with the same name are uniquely identifiable by introducing -//! namespaces. For this the normal Rust namespace of a type is used where it -//! has been defined. Rust prelude types live within the so-called root -//! namespace that is just empty. +//! namespaces. The normal Rust namespace of a type is used, except for the Rust +//! prelude types that live in the so-called root namespace which is empty. use crate::prelude::{ any::TypeId, @@ -61,7 +60,7 @@ pub trait IntoFrozen { /// The frozen version of `Self`. type Output; - /// "Freezes" `self` by using the registry for caching and compaction. + /// "Freezes" `self` by using the registry for caching. fn into_frozen(self, registry: &mut Registry) -> Self::Output; } @@ -73,18 +72,19 @@ impl IntoFrozen for &'static str { } } -/// The registry for compaction of type identifiers and definitions. +/// The registry for space-efficient storage of type identifiers and +/// definitions. /// -/// The registry consists of a cache for already compactified type identifiers and definitions. +/// The registry consists of a cache for type identifiers and definitions. /// -/// Whenever using the registry to compact a type all of its sub-types -/// are going to be registered recursively as well. A type is a sub-type -/// of another type if it is used by its identifier or structure. +/// When adding a type to the registry, all of its sub-types are registered +/// recursively as well. A type is considered a sub-type of another type if it +/// is used by its identifier or structure. /// /// # Note /// /// A type can be a sub-type of itself. In this case the registry has a builtin -/// mechanism to stop recursion before going into an infinite loop. +/// mechanism to stop recursion and avoid going into an infinite loop. #[derive(Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize))] pub struct Registry { @@ -94,15 +94,15 @@ pub struct Registry { /// for all types found in the `types` field. #[cfg_attr(feature = "serde", serde(skip))] type_table: Interner, - /// The database where registered types actually reside. + /// The database where registered types reside. /// - /// This is going to be serialized upon serlialization. + /// The contents herein is used for serlialization. #[cfg_attr(feature = "serde", serde(serialize_with = "serialize_registry_types"))] types: BTreeMap, Type>, } -/// Serializes the types of the registry by removing their unique IDs -/// and instead serialize them in order of their removed unique ID. +/// Serializes the types of the registry by removing their unique IDs and +/// serializes them in order of their removed unique ID. #[cfg(feature = "serde")] fn serialize_registry_types( types: &BTreeMap, Type>, @@ -174,13 +174,13 @@ impl Registry { pub fn register_type(&mut self, ty: &MetaType) -> UntrackedSymbol { let (inserted, symbol) = self.intern_type_id(ty.type_id()); if inserted { - let compact_id = ty.type_info().into_frozen(self); - self.types.insert(symbol, compact_id); + let frozen_id = ty.type_info().into_frozen(self); + self.types.insert(symbol, frozen_id); } symbol } - /// Calls `register_type` for each `MetaType` in the given `iter` + /// Calls `register_type` for each `MetaType` in the given `iter`. pub fn register_types(&mut self, iter: I) -> Vec> where I: IntoIterator, @@ -190,8 +190,8 @@ impl Registry { .collect::>() } - /// Converts an iterator into a Vec of the equivalent compact - /// representations + /// Converts an iterator into a Vec of the equivalent frozen + /// representations. pub fn map_into_frozen(&mut self, iter: I) -> Vec where I: IntoIterator, diff --git a/src/tests.rs b/src/tests.rs index 73671ae2..92223978 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -155,14 +155,17 @@ fn struct_with_generics() { assert_type!(SelfTyped, expected_type); } +// TODO: dp remove this or make it actually test something #[test] fn struct_with_compact() { use scale::Encode; + // use scale::Compact; #[allow(unused)] #[derive(Encode)] struct Thicc { #[codec(compact)] - stuff: u8 + stuff: u8, + moar: u16, } impl TypeInfo for Thicc { @@ -171,8 +174,11 @@ fn struct_with_compact() { fn type_info() -> Type { Type::builder() .path(Path::new("Thicc", module_path!())) - .composite(Fields::named().field_of::("stuff", "u8")) - .into() + .composite( + Fields::named() + .field_of::("stuff", "u8").compact() + .field_of::("moar", "u16") + ) } } diff --git a/src/ty/fields.rs b/src/ty/fields.rs index e2bea876..8cdb7798 100644 --- a/src/ty/fields.rs +++ b/src/ty/fields.rs @@ -86,7 +86,8 @@ pub struct Field { ty: T::Type, /// The name of the type of the field as it appears in the source code. type_name: T::String, - /// Should be encode/decoded as a [`Compact`](parity_scale_codec::Compact) field + /// This field should be encode/decoded as a + /// [`Compact`](parity_scale_codec::Compact) field #[cfg_attr( feature = "serde", serde(skip_serializing_if = "is_false", default) @@ -95,9 +96,8 @@ pub struct Field { } /// TODO: There must be a better way than this -#[allow(unused)] fn is_false(v: &bool) -> bool { - !v + !(*v) } impl IntoFrozen for Field { @@ -108,7 +108,7 @@ impl IntoFrozen for Field { name: self.name.map(|name| name.into_frozen(registry)), ty: registry.register_type(&self.ty), type_name: self.type_name.into_frozen(registry), - compact: false, + compact: self.compact, } } } @@ -152,6 +152,12 @@ impl Field { { Self::new(None, MetaType::new::(), type_name) } + + /// Set the `compact` property to true, signalling that this type is to be + /// encoded/decoded as [`Compact`](parity_scale_codec::Compact). + pub fn compact(&mut self) { + self.compact = true; + } } impl Field diff --git a/src/ty/mod.rs b/src/ty/mod.rs index 3dbb29ff..fc510506 100644 --- a/src/ty/mod.rs +++ b/src/ty/mod.rs @@ -80,7 +80,6 @@ pub struct Type { /// The actual type definition #[cfg_attr(feature = "serde", serde(rename = "def"))] type_def: TypeDef, - // TODO: dp Should we have a `compact` flag here too? Or only here? } impl IntoFrozen for Type { diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index fdb29533..9c16db05 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -217,6 +217,7 @@ fn ui_tests() { t.pass("tests/ui/pass_complex_generic_self_referential_type.rs"); } +// TODO: dp Make useful or remove #[test] fn substrate_example() { use scale::{ diff --git a/test_suite/tests/json.rs b/test_suite/tests/json.rs index 5c3e3d7c..88ab6762 100644 --- a/test_suite/tests/json.rs +++ b/test_suite/tests/json.rs @@ -196,6 +196,49 @@ fn test_struct() { })); } +#[test] +fn test_struct_with_some_fields_marked_as_compact() { + use scale::Encode; + + // #[derive(TypeInfo, Encode)] + #[derive(Encode)] + struct Dense { + #[codec(compact)] + a: u128, + b: [u8; 32], + #[codec(compact)] + c: u64, + } + use scale_info::{Type, Path, build::Fields}; + impl TypeInfo for Dense { + type Identity = Self; + fn type_info() -> Type { + Type::builder() + .path(Path::new("Dense", module_path!())) + .composite( + Fields::named() + .field_of::("a", "i32").compact() + .field_of::<[u8; 32]>("b", "[u8; 32]") + .field_of::("c", "u64").compact() + ) + // .into() // <–– TODO: dp I don't think we need these `.into()`s anymore. + } + } + + assert_json_for_type::(json![{ + "path": ["json", "Dense"], + "def": { + "composite": { + "fields": [ + { "name": "a", "type": 1, "typeName": "i32", "compact": true }, + { "name": "b", "type": 2, "typeName": "[u8; 32]" }, + { "name": "c", "type": 3, "typeName": "u64", "compact": true }, + ], + }, + } + }]); +} + #[test] fn test_clike_enum() { #[derive(TypeInfo)] From 8333e5a30df57797d104d56603165cb14ae0801c Mon Sep 17 00:00:00 2001 From: David Palm Date: Thu, 17 Dec 2020 16:33:23 +0100 Subject: [PATCH 07/72] Cleanup --- src/build.rs | 12 --- src/tests.rs | 31 -------- src/ty/fields.rs | 21 ----- test_suite/tests/derive.rs | 155 ------------------------------------- test_suite/tests/json.rs | 43 ---------- 5 files changed, 262 deletions(-) diff --git a/src/build.rs b/src/build.rs index 9667290c..c55cbfad 100644 --- a/src/build.rs +++ b/src/build.rs @@ -248,18 +248,6 @@ impl FieldsBuilder { pub fn finalize(self) -> Vec> { self.fields } - - /// Mark last field as compact, meaning that encoding/decoding should be in the [`scale_codec::Compact`] format. - pub fn compact(mut self) -> Self { - self.fields - .iter_mut() - .last() - .and_then(|f| { - f.compact(); - Some(f) - }); - self - } } impl FieldsBuilder { diff --git a/src/tests.rs b/src/tests.rs index 92223978..1552490c 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -154,34 +154,3 @@ fn struct_with_generics() { .composite(Fields::named().field_of::>>("data", "T")); assert_type!(SelfTyped, expected_type); } - -// TODO: dp remove this or make it actually test something -#[test] -fn struct_with_compact() { - use scale::Encode; - // use scale::Compact; - #[allow(unused)] - #[derive(Encode)] - struct Thicc { - #[codec(compact)] - stuff: u8, - moar: u16, - } - - impl TypeInfo for Thicc { - type Identity = Self; - - fn type_info() -> Type { - Type::builder() - .path(Path::new("Thicc", module_path!())) - .composite( - Fields::named() - .field_of::("stuff", "u8").compact() - .field_of::("moar", "u16") - ) - } - } - - fn assert_type_info() {} - assert_type_info::(); -} diff --git a/src/ty/fields.rs b/src/ty/fields.rs index 8cdb7798..d718f2b1 100644 --- a/src/ty/fields.rs +++ b/src/ty/fields.rs @@ -86,18 +86,6 @@ pub struct Field { ty: T::Type, /// The name of the type of the field as it appears in the source code. type_name: T::String, - /// This field should be encode/decoded as a - /// [`Compact`](parity_scale_codec::Compact) field - #[cfg_attr( - feature = "serde", - serde(skip_serializing_if = "is_false", default) - )] - compact: bool, -} - -/// TODO: There must be a better way than this -fn is_false(v: &bool) -> bool { - !(*v) } impl IntoFrozen for Field { @@ -108,7 +96,6 @@ impl IntoFrozen for Field { name: self.name.map(|name| name.into_frozen(registry)), ty: registry.register_type(&self.ty), type_name: self.type_name.into_frozen(registry), - compact: self.compact, } } } @@ -121,13 +108,11 @@ impl Field { name: Option<&'static str>, ty: MetaType, type_name: &'static str, - // TODO: dp add compact arg (and use it) ) -> Self { Self { name, ty, type_name, - compact: false, } } @@ -152,12 +137,6 @@ impl Field { { Self::new(None, MetaType::new::(), type_name) } - - /// Set the `compact` property to true, signalling that this type is to be - /// encoded/decoded as [`Compact`](parity_scale_codec::Compact). - pub fn compact(&mut self) { - self.compact = true; - } } impl Field diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index 9c16db05..48fe56a8 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -216,158 +216,3 @@ fn ui_tests() { t.pass("tests/ui/pass_basic_generic_type.rs"); t.pass("tests/ui/pass_complex_generic_self_referential_type.rs"); } - -// TODO: dp Make useful or remove -#[test] -fn substrate_example() { - use scale::{ - // Decode, - Encode, Compact, - }; - use scale_info::prelude::vec::Vec; - // #[allow(unused)] - // type AccountIndex = u32; - /// A multi-format address wrapper for on-chain accounts. - #[allow(unused)] - // #[derive(Encode, Decode, PartialEq, Eq, Clone, TypeInfo)] - #[derive(Encode, TypeInfo)] - #[cfg_attr(feature = "std", derive(Hash))] - pub enum MultiAddress { - /// It's an account ID (pubkey). - Id(AccountId), - /// It's an account index. - // Index(#[codec(compact)] AccountIndex), - Index(Compact), - /// It's some arbitrary raw bytes. - Raw(Vec), - /// It's a 32 byte representation. - Address32([u8; 32]), - /// Its a 20 byte representation. - Address20([u8; 20]), - } - - let _ma = MultiAddress::::Id(32); -} - -// #[ignore] -// fn substrate_example_expanded() { -// use scale::{Decode, Encode, Compact}; -// use scale_info::prelude::vec::Vec; -// /// A multi-format address wrapper for on-chain accounts. -// #[allow(unused)] -// pub enum MultiAddress { -// /// It's an account ID (pubkey). -// Id(AccountId), -// /// It's an account index. -// // Index(#[codec(compact)] AccountIndex), -// Index(Compact), -// /// It's some arbitrary raw bytes. -// Raw(Vec), -// /// It's a 32 byte representation. -// Address32([u8; 32]), -// /// Its a 20 byte representation. -// Address20([u8; 20]), -// } - -// const _IMPL_TYPE_INFO_FOR_MultiAddress: () = { -// impl< -// AccountId: ::scale_info::TypeInfo + 'static, -// AccountIndex: ::scale_info::TypeInfo + 'static, -// > ::scale_info::TypeInfo for MultiAddress -// where -// AccountId: ::scale_info::TypeInfo + 'static, -// AccountIndex: ::scale_info::TypeInfo + 'static, -// { -// type Identity = Self; -// fn type_info() -> ::scale_info::Type { -// ::scale_info::Type::builder() -// .path(::scale_info::Path::new("MultiAddress", "derive")) -// .type_params(<[_]>::into_vec(box [ -// ::scale_info::meta_type::(), -// ::scale_info::meta_type::(), -// ])) -// .variant( -// ::scale_info::build::Variants::with_fields() -// .variant( -// "Id", -// ::scale_info::build::Fields::unnamed() -// .field_of::("AccountId"), -// ) -// .variant( -// "Index", -// ::scale_info::build::Fields::unnamed() -// .field_of::("AccountIndex"), -// ) -// .variant( -// "Raw", -// ::scale_info::build::Fields::unnamed() -// .field_of::>("Vec"), -// ) -// .variant( -// "Address32", -// ::scale_info::build::Fields::unnamed() -// .field_of::<[u8; 32]>("[u8; 32]"), -// ) -// .variant( -// "Address20", -// ::scale_info::build::Fields::unnamed() -// .field_of::<[u8; 20]>("[u8; 20]"), -// ), -// ) -// .into() -// } -// }; -// }; - -// const _: () = { -// #[allow(unknown_lints)] -// #[allow(rust_2018_idioms)] -// extern crate scale as _parity_scale_codec; -// impl _parity_scale_codec::Encode for MultiAddress -// where -// AccountId: _parity_scale_codec::Encode, -// AccountId: _parity_scale_codec::Encode, -// AccountIndex: _parity_scale_codec::HasCompact, -// { -// fn encode_to<__CodecOutputEdqy: _parity_scale_codec::Output>( -// &self, -// __codec_dest_edqy: &mut __CodecOutputEdqy, -// ) { -// match *self { -// MultiAddress::Id(ref aa) => { -// __codec_dest_edqy.push_byte(0usize as u8); -// __codec_dest_edqy.push(aa); -// } -// MultiAddress::Index(ref aa) => { -// __codec_dest_edqy.push_byte(1usize as u8); -// { -// __codec_dest_edqy.push (&<::Type as _parity_scale_codec::EncodeAsRef< '_ , AccountIndex >>::RefType::from(aa)); -// } -// } -// MultiAddress::Raw(ref aa) => { -// __codec_dest_edqy.push_byte(2usize as u8); -// __codec_dest_edqy.push(aa); -// } -// MultiAddress::Address32(ref aa) => { -// __codec_dest_edqy.push_byte(3usize as u8); -// __codec_dest_edqy.push(aa); -// } -// MultiAddress::Address20(ref aa) => { -// __codec_dest_edqy.push_byte(4usize as u8); -// __codec_dest_edqy.push(aa); -// } -// _ => (), -// } -// } -// } -// impl _parity_scale_codec::EncodeLike -// for MultiAddress -// where -// AccountId: _parity_scale_codec::Encode, -// AccountId: _parity_scale_codec::Encode, -// AccountIndex: _parity_scale_codec::HasCompact, -// { -// } -// }; -// let _ma = MultiAddress::::Id(32); -// } diff --git a/test_suite/tests/json.rs b/test_suite/tests/json.rs index 88ab6762..5c3e3d7c 100644 --- a/test_suite/tests/json.rs +++ b/test_suite/tests/json.rs @@ -196,49 +196,6 @@ fn test_struct() { })); } -#[test] -fn test_struct_with_some_fields_marked_as_compact() { - use scale::Encode; - - // #[derive(TypeInfo, Encode)] - #[derive(Encode)] - struct Dense { - #[codec(compact)] - a: u128, - b: [u8; 32], - #[codec(compact)] - c: u64, - } - use scale_info::{Type, Path, build::Fields}; - impl TypeInfo for Dense { - type Identity = Self; - fn type_info() -> Type { - Type::builder() - .path(Path::new("Dense", module_path!())) - .composite( - Fields::named() - .field_of::("a", "i32").compact() - .field_of::<[u8; 32]>("b", "[u8; 32]") - .field_of::("c", "u64").compact() - ) - // .into() // <–– TODO: dp I don't think we need these `.into()`s anymore. - } - } - - assert_json_for_type::(json![{ - "path": ["json", "Dense"], - "def": { - "composite": { - "fields": [ - { "name": "a", "type": 1, "typeName": "i32", "compact": true }, - { "name": "b", "type": 2, "typeName": "[u8; 32]" }, - { "name": "c", "type": 3, "typeName": "u64", "compact": true }, - ], - }, - } - }]); -} - #[test] fn test_clike_enum() { #[derive(TypeInfo)] From 2818f7bc398fdf44318ca679cbb7141891a17f34 Mon Sep 17 00:00:00 2001 From: David Palm Date: Thu, 17 Dec 2020 16:37:13 +0100 Subject: [PATCH 08/72] More cleanup --- README.md | 8 ++++---- test_suite/tests/derive.rs | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c700249c..f9ff3e8a 100644 --- a/README.md +++ b/README.md @@ -200,12 +200,12 @@ identifiers. All concrete `TypeInfo` structures have two forms: - One meta form (`MetaType`) that acts as a bridge to other forms -- A compact form that is later to be serialized. +- A frozen form suitable for serialization. -The `IntoCompact` trait must also be implemented in order to compact a type -definition using an instance of a type registry. +The `IntoFrozen` trait must also be implemented in order prepare a type +definition for serialization using an instance of the type registry. -After compactification all type definitions are stored in the type registry. +After transformation all type definitions are stored in the type registry. Note that the type registry should be serialized as part of the metadata structure where the registered types are utilized to allow consumers to resolve the types. diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index 48fe56a8..83eb3749 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -11,7 +11,6 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -// #![feature(box_syntax)] #![cfg_attr(not(feature = "std"), no_std)] use scale_info::prelude::boxed::Box; From e03a2cd38fb7643cb00fcc766e94e8b044c4b16f Mon Sep 17 00:00:00 2001 From: David Palm Date: Thu, 17 Dec 2020 19:25:50 +0100 Subject: [PATCH 09/72] obey the fmt --- src/registry.rs | 2 +- src/ty/composite.rs | 2 +- src/ty/fields.rs | 2 +- src/ty/mod.rs | 2 +- src/ty/path.rs | 2 +- src/ty/variant.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/registry.rs b/src/registry.rs index 8e8a16cc..9dc5ee99 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -34,9 +34,9 @@ use crate::prelude::{ use crate::{ form::{ - FrozenForm, Form, FormString, + FrozenForm, }, interner::{ Interner, diff --git a/src/ty/composite.rs b/src/ty/composite.rs index 2ec039d8..4d3923da 100644 --- a/src/ty/composite.rs +++ b/src/ty/composite.rs @@ -16,8 +16,8 @@ use crate::prelude::vec::Vec; use crate::{ form::{ - FrozenForm, Form, + FrozenForm, MetaForm, }, Field, diff --git a/src/ty/fields.rs b/src/ty/fields.rs index d718f2b1..803699ed 100644 --- a/src/ty/fields.rs +++ b/src/ty/fields.rs @@ -14,8 +14,8 @@ use crate::{ form::{ - FrozenForm, Form, + FrozenForm, MetaForm, }, IntoFrozen, diff --git a/src/ty/mod.rs b/src/ty/mod.rs index fc510506..313d2289 100644 --- a/src/ty/mod.rs +++ b/src/ty/mod.rs @@ -20,8 +20,8 @@ use crate::prelude::{ use crate::{ build::TypeBuilder, form::{ - FrozenForm, Form, + FrozenForm, MetaForm, }, IntoFrozen, diff --git a/src/ty/path.rs b/src/ty/path.rs index c8f6fa32..c3116881 100644 --- a/src/ty/path.rs +++ b/src/ty/path.rs @@ -24,8 +24,8 @@ use crate::prelude::{ use crate::{ form::{ - FrozenForm, Form, + FrozenForm, MetaForm, }, utils::is_rust_identifier, diff --git a/src/ty/variant.rs b/src/ty/variant.rs index 4f31af47..6dbdb90a 100644 --- a/src/ty/variant.rs +++ b/src/ty/variant.rs @@ -17,8 +17,8 @@ use crate::prelude::vec::Vec; use crate::{ build::FieldsBuilder, form::{ - FrozenForm, Form, + FrozenForm, MetaForm, }, Field, From 3a95663438b63b721e37d62f89c00fd4b3cf90d4 Mon Sep 17 00:00:00 2001 From: David Palm Date: Thu, 17 Dec 2020 20:48:01 +0100 Subject: [PATCH 10/72] Add a `compact` flag to `Field` to indicate that this type is to be encoded/decoded as a SCALE Compact type --- derive/src/lib.rs | 1 - src/build.rs | 9 ++++++++ src/registry.rs | 1 - src/tests.rs | 1 - src/ty/fields.rs | 21 ++++++++++++++++-- test_suite/tests/json.rs | 48 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 76 insertions(+), 5 deletions(-) diff --git a/derive/src/lib.rs b/derive/src/lib.rs index c12d8c2d..89aeed8e 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -92,7 +92,6 @@ fn generate_type(input: TokenStream2) -> Result { .path(::scale_info::Path::new(stringify!(#ident), module_path!())) .type_params(::scale_info::prelude::vec![ #( #generic_type_ids ),* ]) .#build_type - .into() } } }; diff --git a/src/build.rs b/src/build.rs index c55cbfad..39065785 100644 --- a/src/build.rs +++ b/src/build.rs @@ -248,6 +248,15 @@ impl FieldsBuilder { pub fn finalize(self) -> Vec> { self.fields } + + /// Mark last field as compact, meaning that encoding/decoding should be in the [`scale_codec::Compact`] format. + pub fn compact(mut self) -> Self { + self.fields.iter_mut().last().and_then(|f| { + f.compact(); + Some(f) + }); + self + } } impl FieldsBuilder { diff --git a/src/registry.rs b/src/registry.rs index 9dc5ee99..68abf220 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -303,7 +303,6 @@ mod tests { "&mut RecursiveRefs", ), ) - .into() } } diff --git a/src/tests.rs b/src/tests.rs index 1552490c..0f036073 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -134,7 +134,6 @@ fn struct_with_generics() { .path(Path::new("MyStruct", module_path!())) .type_params(tuple_meta_type!(T)) .composite(Fields::named().field_of::("data", "T")) - .into() } } diff --git a/src/ty/fields.rs b/src/ty/fields.rs index 803699ed..1cb1a853 100644 --- a/src/ty/fields.rs +++ b/src/ty/fields.rs @@ -86,6 +86,14 @@ pub struct Field { ty: T::Type, /// The name of the type of the field as it appears in the source code. type_name: T::String, + /// This field should be encode/decoded as a + /// [`Compact`](parity_scale_codec::Compact) field + #[cfg_attr(feature = "serde", serde(skip_serializing_if = "is_false", default))] + compact: bool, +} + +fn is_false(v: &bool) -> bool { + !v } impl IntoFrozen for Field { @@ -96,6 +104,7 @@ impl IntoFrozen for Field { name: self.name.map(|name| name.into_frozen(registry)), ty: registry.register_type(&self.ty), type_name: self.type_name.into_frozen(registry), + compact: self.compact, } } } @@ -108,11 +117,13 @@ impl Field { name: Option<&'static str>, ty: MetaType, type_name: &'static str, + compact: bool, ) -> Self { Self { name, ty, type_name, + compact, } } @@ -124,7 +135,7 @@ impl Field { where T: TypeInfo + ?Sized + 'static, { - Self::new(Some(name), MetaType::new::(), type_name) + Self::new(Some(name), MetaType::new::(), type_name, false) } /// Creates a new unnamed field. @@ -135,7 +146,7 @@ impl Field { where T: TypeInfo + ?Sized + 'static, { - Self::new(None, MetaType::new::(), type_name) + Self::new(None, MetaType::new::(), type_name, false) } } @@ -161,4 +172,10 @@ where pub fn type_name(&self) -> &T::String { &self.type_name } + + /// Set the `compact` property to true, signalling that this type is to be + /// encoded/decoded as a [`parity_scale_codec::Compact`]. + pub fn compact(&mut self) { + self.compact = true; + } } diff --git a/test_suite/tests/json.rs b/test_suite/tests/json.rs index 5c3e3d7c..b176eee6 100644 --- a/test_suite/tests/json.rs +++ b/test_suite/tests/json.rs @@ -196,6 +196,54 @@ fn test_struct() { })); } +#[test] +fn test_struct_with_some_fields_marked_as_compact() { + use scale::Encode; + + // #[derive(TypeInfo, Encode)] + #[derive(Encode)] + struct Dense { + #[codec(compact)] + a: u128, + b: [u8; 32], + #[codec(compact)] + c: u64, + } + use scale_info::{ + build::Fields, + Path, + Type, + }; + impl TypeInfo for Dense { + type Identity = Self; + fn type_info() -> Type { + Type::builder() + .path(Path::new("Dense", module_path!())) + .composite( + Fields::named() + .field_of::("a", "i32") + .compact() + .field_of::<[u8; 32]>("b", "[u8; 32]") + .field_of::("c", "u64") + .compact(), + ) + } + } + + assert_json_for_type::(json![{ + "path": ["json", "Dense"], + "def": { + "composite": { + "fields": [ + { "name": "a", "type": 1, "typeName": "i32", "compact": true }, + { "name": "b", "type": 2, "typeName": "[u8; 32]" }, + { "name": "c", "type": 3, "typeName": "u64", "compact": true }, + ], + }, + } + }]); +} + #[test] fn test_clike_enum() { #[derive(TypeInfo)] From 004e1076239d1e5506a2d7e61646d9b65e2b1f6e Mon Sep 17 00:00:00 2001 From: David Palm Date: Thu, 17 Dec 2020 21:28:53 +0100 Subject: [PATCH 11/72] Clippy warnings --- src/build.rs | 4 ++-- src/ty/fields.rs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/build.rs b/src/build.rs index 39065785..5778912e 100644 --- a/src/build.rs +++ b/src/build.rs @@ -251,9 +251,9 @@ impl FieldsBuilder { /// Mark last field as compact, meaning that encoding/decoding should be in the [`scale_codec::Compact`] format. pub fn compact(mut self) -> Self { - self.fields.iter_mut().last().and_then(|f| { + self.fields.iter_mut().last().map(|f| { f.compact(); - Some(f) + f }); self } diff --git a/src/ty/fields.rs b/src/ty/fields.rs index 1cb1a853..d68a943b 100644 --- a/src/ty/fields.rs +++ b/src/ty/fields.rs @@ -92,6 +92,7 @@ pub struct Field { compact: bool, } +#[allow(dead_code)] fn is_false(v: &bool) -> bool { !v } From 93a9aebfc235db66d19872b417f9d0d163a95ba5 Mon Sep 17 00:00:00 2001 From: David Palm Date: Thu, 17 Dec 2020 21:34:29 +0100 Subject: [PATCH 12/72] Acommodate older clippy --- src/ty/fields.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ty/fields.rs b/src/ty/fields.rs index d68a943b..404c5514 100644 --- a/src/ty/fields.rs +++ b/src/ty/fields.rs @@ -92,9 +92,11 @@ pub struct Field { compact: bool, } +// Need to obey the required serde signature here +#[allow(clippy::trivially_copy_pass_by_ref)] #[allow(dead_code)] -fn is_false(v: &bool) -> bool { - !v +const fn is_false(v: &bool) -> bool { + !(*v) } impl IntoFrozen for Field { From 6569e507ee8ab9087e0b464dd5477c31b0e13b7f Mon Sep 17 00:00:00 2001 From: David Palm Date: Mon, 28 Dec 2020 17:15:20 +0100 Subject: [PATCH 13/72] Derive (scale) compact fields --- derive/src/lib.rs | 33 ++++++++++++++++++++--- test_suite/tests/derive.rs | 55 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 83 insertions(+), 5 deletions(-) diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 89aeed8e..447bad83 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -37,6 +37,7 @@ use syn::{ }, punctuated::Punctuated, token::Comma, + AttrStyle, Data, DataEnum, DataStruct, @@ -46,6 +47,9 @@ use syn::{ Field, Fields, Lit, + Meta, + MetaList, + NestedMeta, Variant, }; @@ -107,20 +111,43 @@ fn generate_fields(fields: &FieldsList) -> Vec { .map(|f| { let (ty, ident) = (&f.ty, &f.ident); let type_name = clean_type_string("e!(#ty).to_string()); - + let compact = if is_compact(f) { + quote! { + .compact() + } + } else { + quote! {} + }; if let Some(i) = ident { quote! { - .field_of::<#ty>(stringify!(#i), #type_name) + .field_of::<#ty>(stringify!(#i), #type_name) #compact } } else { quote! { - .field_of::<#ty>(#type_name) + .field_of::<#ty>(#type_name) #compact } } }) .collect() } +/// Look for a `#[codec(compact)]` outer attribute. +fn is_compact(f: &Field) -> bool { + f.attrs.iter().any(|attr| { + let mut is_compact = false; + if attr.style == AttrStyle::Outer && attr.path.is_ident("codec") { + if let Ok(Meta::List(MetaList { nested, .. })) = attr.parse_meta() { + if let Some(NestedMeta::Meta(Meta::Path(path))) = nested.iter().next() { + if path.is_ident("compact") { + is_compact = true; + } + } + } + } + is_compact + }) +} + fn clean_type_string(input: &str) -> String { input .replace(" ::", "::") diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index 83eb3749..a6871e1b 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -13,11 +13,11 @@ // limitations under the License. #![cfg_attr(not(feature = "std"), no_std)] -use scale_info::prelude::boxed::Box; - use pretty_assertions::assert_eq; +use scale::Encode; use scale_info::{ build::*, + prelude::boxed::Box, tuple_meta_type, Path, Type, @@ -204,6 +204,57 @@ fn associated_types_derive_without_bounds() { assert_type!(Assoc, struct_type); } +#[test] +fn scale_compact_types_work_in_structs() { + #[allow(unused)] + #[derive(Encode, TypeInfo)] + struct Dense { + a: u8, + #[codec(compact)] + b: u16, + } + + let dense = Type::builder() + .path(Path::new("Dense", "derive")) + .composite( + Fields::named() + .field_of::("a", "u8") + .field_of::("b", "u16") + .compact(), + ); + + assert_type!(Dense, dense); +} + +#[test] +fn scale_compact_types_work_in_enums() { + #[allow(unused)] + #[derive(Encode, TypeInfo)] + enum MutilatedMultiAddress { + Id(AccountId), + Index(#[codec(compact)] AccountIndex), + Address32([u8; 32]), + } + + let ty = Type::builder() + .path(Path::new("MutilatedMultiAddress", "derive")) + .type_params(tuple_meta_type!(u8, u16)) + .variant( + Variants::with_fields() + .variant("Id", Fields::unnamed().field_of::("AccountId")) + .variant( + "Index", + Fields::unnamed().field_of::("AccountIndex").compact(), + ) + .variant( + "Address32", + Fields::unnamed().field_of::<[u8; 32]>("[u8; 32]"), + ), + ); + + assert_type!(MutilatedMultiAddress, ty); +} + #[rustversion::nightly] #[test] fn ui_tests() { From b43cdfc1d4276728af23f4150e3497924f3cefdf Mon Sep 17 00:00:00 2001 From: David Palm Date: Mon, 4 Jan 2021 22:59:57 +0100 Subject: [PATCH 14/72] Use utils from parity-scale-codec-derive Handle `codec(skip)` and `codec(index = $int)` attributes --- derive/src/lib.rs | 116 ++++++++++++++----------------------- derive/src/utils.rs | 105 +++++++++++++++++++++++++++++++++ test_suite/tests/derive.rs | 82 ++++++++++++++++++++++++++ 3 files changed, 231 insertions(+), 72 deletions(-) create mode 100644 derive/src/utils.rs diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 447bad83..80f93aa5 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -19,6 +19,7 @@ extern crate proc_macro; mod impl_wrapper; mod trait_bounds; +mod utils; use alloc::{ string::{ @@ -37,19 +38,12 @@ use syn::{ }, punctuated::Punctuated, token::Comma, - AttrStyle, Data, DataEnum, DataStruct, DeriveInput, - Expr, - ExprLit, Field, Fields, - Lit, - Meta, - MetaList, - NestedMeta, Variant, }; @@ -108,16 +102,18 @@ type FieldsList = Punctuated; fn generate_fields(fields: &FieldsList) -> Vec { fields .iter() + .filter(|f| !utils::should_skip(&f.attrs)) .map(|f| { let (ty, ident) = (&f.ty, &f.ident); let type_name = clean_type_string("e!(#ty).to_string()); - let compact = if is_compact(f) { + let compact = if utils::is_compact(f) { quote! { .compact() } } else { quote! {} }; + if let Some(i) = ident { quote! { .field_of::<#ty>(stringify!(#i), #type_name) #compact @@ -131,23 +127,6 @@ fn generate_fields(fields: &FieldsList) -> Vec { .collect() } -/// Look for a `#[codec(compact)]` outer attribute. -fn is_compact(f: &Field) -> bool { - f.attrs.iter().any(|attr| { - let mut is_compact = false; - if attr.style == AttrStyle::Outer && attr.path.is_ident("codec") { - if let Ok(Meta::List(MetaList { nested, .. })) = attr.parse_meta() { - if let Some(NestedMeta::Meta(Meta::Path(path))) = nested.iter().next() { - if path.is_ident("compact") { - is_compact = true; - } - } - } - } - is_compact - }) -} - fn clean_type_string(input: &str) -> String { input .replace(" ::", "::") @@ -189,27 +168,17 @@ fn generate_composite_type(data_struct: &DataStruct) -> TokenStream2 { type VariantList = Punctuated; fn generate_c_like_enum_def(variants: &VariantList) -> TokenStream2 { - let variants = variants.into_iter().enumerate().map(|(i, v)| { - let name = &v.ident; - let discriminant = if let Some(( - _, - Expr::Lit(ExprLit { - lit: Lit::Int(lit_int), - .. - }), - )) = &v.discriminant - { - match lit_int.base10_parse::() { - Ok(i) => i, - Err(err) => return err.to_compile_error(), + let variants = variants + .into_iter() + .enumerate() + .filter(|(_, v)| !utils::should_skip(&v.attrs)) + .map(|(i, v)| { + let name = &v.ident; + let discriminant = utils::variant_index(v, i); + quote! { + .variant(stringify!(#name), #discriminant as u64) } - } else { - i as u64 - }; - quote! { - .variant(stringify!(#name), #discriminant) - } - }); + }); quote! { variant( ::scale_info::build::Variants::fieldless() @@ -235,37 +204,40 @@ fn generate_variant_type(data_enum: &DataEnum) -> TokenStream2 { return generate_c_like_enum_def(variants) } - let variants = variants.into_iter().map(|v| { - let ident = &v.ident; - let v_name = quote! {stringify!(#ident) }; - match v.fields { - Fields::Named(ref fs) => { - let fields = generate_fields(&fs.named); - quote! { - .variant( - #v_name, - ::scale_info::build::Fields::named() - #( #fields)* - ) + let variants = variants + .into_iter() + .filter(|v| !utils::should_skip(&v.attrs)) + .map(|v| { + let ident = &v.ident; + let v_name = quote! {stringify!(#ident) }; + match v.fields { + Fields::Named(ref fs) => { + let fields = generate_fields(&fs.named); + quote! { + .variant( + #v_name, + ::scale_info::build::Fields::named() + #( #fields)* + ) + } } - } - Fields::Unnamed(ref fs) => { - let fields = generate_fields(&fs.unnamed); - quote! { - .variant( - #v_name, - ::scale_info::build::Fields::unnamed() - #( #fields)* - ) + Fields::Unnamed(ref fs) => { + let fields = generate_fields(&fs.unnamed); + quote! { + .variant( + #v_name, + ::scale_info::build::Fields::unnamed() + #( #fields)* + ) + } } - } - Fields::Unit => { - quote! { - .variant_unit(#v_name) + Fields::Unit => { + quote! { + .variant_unit(#v_name) + } } } - } - }); + }); quote! { variant( ::scale_info::build::Variants::with_fields() diff --git a/derive/src/utils.rs b/derive/src/utils.rs new file mode 100644 index 00000000..7f16a681 --- /dev/null +++ b/derive/src/utils.rs @@ -0,0 +1,105 @@ +// Copyright 2019-2020 Parity Technologies (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Utility methods to work with `SCALE` attributes relevant for the `TypeInfo` derive.. +//! +//! NOTE: The code here is copied verbatim from `parity-scale-codec-derive`. + +use proc_macro2::TokenStream; +use quote::quote; +use syn::{ + spanned::Spanned, + Attribute, + Field, + Lit, + Meta, + NestedMeta, + Variant, +}; + +/// Look for a `#[codec(index = $int)]` attribute on a variant. If no attribute +/// is found, fall back to the discriminant or just the variant index. +pub fn variant_index(v: &Variant, i: usize) -> TokenStream { + // first look for an attribute + let index = find_meta_item(v.attrs.iter(), |meta| { + if let NestedMeta::Meta(Meta::NameValue(ref nv)) = meta { + if nv.path.is_ident("index") { + if let Lit::Int(ref v) = nv.lit { + let byte = v + .base10_parse::() + .expect("Internal error, index attribute must have been checked"); + return Some(byte) + } + } + } + + None + }); + + // then fallback to discriminant or just index + index.map(|i| quote! { #i }).unwrap_or_else(|| { + v.discriminant + .as_ref() + .map(|&(_, ref expr)| quote! { #expr }) + .unwrap_or_else(|| quote! { #i }) + }) +} + +/// Look for a `#[codec(compact)]` outer attribute on the given `Field`. +pub fn is_compact(field: &Field) -> bool { + find_meta_item(field.attrs.iter(), |meta| { + if let NestedMeta::Meta(Meta::Path(ref path)) = meta { + if path.is_ident("compact") { + return Some(()) + } + } + + None + }) + .is_some() +} + +/// Look for a `#[codec(skip)]` in the given attributes. +pub fn should_skip(attrs: &[Attribute]) -> bool { + find_meta_item(attrs.iter(), |meta| { + if let NestedMeta::Meta(Meta::Path(ref path)) = meta { + if path.is_ident("skip") { + return Some(path.span()) + } + } + + None + }) + .is_some() +} + +fn find_meta_item<'a, F, R, I>(itr: I, pred: F) -> Option +where + F: FnMut(&NestedMeta) -> Option + Clone, + I: Iterator, +{ + itr.filter_map(|attr| { + if attr.path.is_ident("codec") { + if let Meta::List(ref meta_list) = attr + .parse_meta() + .expect("Internal error, parse_meta must have been checked") + { + return meta_list.nested.iter().filter_map(pred.clone()).next() + } + } + + None + }) + .next() +} diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index a6871e1b..c073e8af 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -116,6 +116,27 @@ fn c_like_enum_derive() { assert_type!(E, ty); } +#[test] +fn c_like_enum_derive_with_scale_index_set() { + #[allow(unused)] + #[derive(TypeInfo, Encode)] + enum E { + A, + B = 10, + #[codec(index = 13)] + C, + } + + let ty = Type::builder().path(Path::new("E", "derive")).variant( + Variants::fieldless() + .variant("A", 0u64) + .variant("B", 10u64) + .variant("C", 13u64), + ); + + assert_type!(E, ty); +} + #[test] fn enum_derive() { #[allow(unused)] @@ -255,6 +276,67 @@ fn scale_compact_types_work_in_enums() { assert_type!(MutilatedMultiAddress, ty); } +#[test] +fn struct_fields_marked_scale_skip_are_skipped() { + #[allow(unused)] + #[derive(TypeInfo, Encode)] + struct Skippy { + a: u8, + #[codec(skip)] + b: u16, + c: u32, + } + + let ty = Type::builder() + .path(Path::new("Skippy", "derive")) + .composite( + Fields::named() + .field_of::("a", "u8") + .field_of::("c", "u32"), + ); + assert_type!(Skippy, ty); +} + +#[test] +fn enum_variants_marked_scale_skip_are_skipped() { + #[allow(unused)] + #[derive(TypeInfo, Encode)] + enum Skippy { + A, + #[codec(skip)] + B, + C, + } + + let ty = Type::builder() + .path(Path::new("Skippy", "derive")) + .variant(Variants::fieldless().variant("A", 0).variant("C", 2)); + assert_type!(Skippy, ty); +} + +#[test] +fn enum_variants_with_fields_marked_scale_skip_are_skipped() { + #[allow(unused)] + #[derive(TypeInfo, Encode)] + enum Skippy { + #[codec(skip)] + Apa, + Bajs { + #[codec(skip)] + a: u8, + b: bool, + }, + Coo(bool), + } + + let ty = Type::builder().path(Path::new("Skippy", "derive")).variant( + Variants::with_fields() + .variant("Bajs", Fields::named().field_of::("b", "bool")) + .variant("Coo", Fields::unnamed().field_of::("bool")), + ); + assert_type!(Skippy, ty); +} + #[rustversion::nightly] #[test] fn ui_tests() { From d1700b206ad822df8090e8daeda8e198c92171f7 Mon Sep 17 00:00:00 2001 From: David Palm Date: Tue, 19 Jan 2021 16:12:35 +0100 Subject: [PATCH 15/72] fmt --- derive/src/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/derive/src/utils.rs b/derive/src/utils.rs index 7f16a681..9d7e41e3 100644 --- a/derive/src/utils.rs +++ b/derive/src/utils.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2020 Parity Technologies (UK) Ltd. +// Copyright 2019-2021 Parity Technologies (UK) Ltd. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. From d29c9be4c0c764ec4db17f2db5ab16d1ca2c0c9a Mon Sep 17 00:00:00 2001 From: David Palm Date: Thu, 18 Feb 2021 20:35:33 +0100 Subject: [PATCH 16/72] Attempt to fix CI --- .github/workflows/rust.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 0edea901..ab3d03e1 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -25,27 +25,30 @@ jobs: - name: fmt run: | + cargo generate-lockfile --verbose && cargo update -p funty --precise "1.1.0" --verbose cargo fmt --version cargo fmt --all -- --check - name: clippy run: | + cargo generate-lockfile --verbose && cargo update -p funty --precise "1.1.0" --verbose cargo clippy --version cargo clippy --all -- -D warnings - name: build run: | + cargo generate-lockfile --verbose && cargo update -p funty --precise "1.1.0" --verbose cargo --version --verbose cargo build --all cargo build --all --no-default-features - name: test run: | + cargo generate-lockfile --verbose && cargo update -p funty --precise "1.1.0" --verbose cargo test --all - name: test no-std run: | + cargo generate-lockfile --verbose && cargo update -p funty --precise "1.1.0" --verbose cd ./test_suite/derive_tests_no_std cargo build --no-default-features - - From 0426479f5db2fbf5f2bfb5a7404ca0b4eb5ae1a0 Mon Sep 17 00:00:00 2001 From: David Palm Date: Thu, 18 Feb 2021 20:44:10 +0100 Subject: [PATCH 17/72] FIx CI take 2 --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index ab3d03e1..d67c5774 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -49,6 +49,6 @@ jobs: - name: test no-std run: | - cargo generate-lockfile --verbose && cargo update -p funty --precise "1.1.0" --verbose cd ./test_suite/derive_tests_no_std + cargo generate-lockfile --verbose && cargo update -p funty --precise "1.1.0" --verbose cargo build --no-default-features From e8d2a749560df8b1f434e6c65e1234ff2b4fe6dc Mon Sep 17 00:00:00 2001 From: David Palm Date: Wed, 17 Mar 2021 10:37:06 +0100 Subject: [PATCH 18/72] Use is_compact from utils Ensure we're working with an outer attribute --- derive/src/lib.rs | 23 +---------------------- derive/src/trait_bounds.rs | 4 +++- derive/src/utils.rs | 27 ++++++++++++++++----------- 3 files changed, 20 insertions(+), 34 deletions(-) diff --git a/derive/src/lib.rs b/derive/src/lib.rs index af419ad4..d8fe3db0 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -42,7 +42,6 @@ use syn::{ punctuated::Punctuated, token::Comma, visit_mut::VisitMut, - AttrStyle, Data, DataEnum, DataStruct, @@ -51,9 +50,6 @@ use syn::{ Fields, Ident, Lifetime, - Meta, - MetaList, - NestedMeta, Variant, }; @@ -153,7 +149,7 @@ fn generate_fields(fields: &FieldsList) -> Vec { StaticLifetimesReplace.visit_type_mut(&mut ty); let type_name = clean_type_string("e!(#ty).to_string()); - let method_call = if is_compact(f) { + let method_call = if utils::is_compact(f) { quote!(.compact_of::<#ty>) } else { quote!(.field_of::<#ty>) @@ -167,23 +163,6 @@ fn generate_fields(fields: &FieldsList) -> Vec { .collect() } -/// Look for a `#[codec(compact)]` outer attribute. -fn is_compact(f: &Field) -> bool { - f.attrs.iter().any(|attr| { - let mut is_compact = false; - if attr.style == AttrStyle::Outer && attr.path.is_ident("codec") { - if let Ok(Meta::List(MetaList { nested, .. })) = attr.parse_meta() { - if let Some(NestedMeta::Meta(Meta::Path(path))) = nested.iter().next() { - if path.is_ident("compact") { - is_compact = true; - } - } - } - } - is_compact - }) -} - fn clean_type_string(input: &str) -> String { input .replace(" ::", "::") diff --git a/derive/src/trait_bounds.rs b/derive/src/trait_bounds.rs index 1e79e7d0..65da4257 100644 --- a/derive/src/trait_bounds.rs +++ b/derive/src/trait_bounds.rs @@ -29,6 +29,8 @@ use syn::{ WhereClause, }; +use crate::utils; + /// Generates a where clause for a `TypeInfo` impl, adding `TypeInfo + 'static` bounds to all /// relevant generic types including associated types (e.g. `T::A: TypeInfo`), correctly dealing /// with self-referential types. @@ -164,7 +166,7 @@ fn collect_types_to_bind( // to not have them in the where clause. !type_or_sub_type_path_starts_with_ident(&field.ty, &input_ident) }) - .map(|f| (f.ty.clone(), super::is_compact(f))) + .map(|f| (f.ty.clone(), utils::is_compact(f))) .collect() }; diff --git a/derive/src/utils.rs b/derive/src/utils.rs index b81f7221..2918d330 100644 --- a/derive/src/utils.rs +++ b/derive/src/utils.rs @@ -20,6 +20,7 @@ use proc_macro2::TokenStream; use quote::quote; use syn::{ spanned::Spanned, + AttrStyle, Attribute, Lit, Meta, @@ -56,18 +57,22 @@ pub fn variant_index(v: &Variant, i: usize) -> TokenStream { } // /// Look for a `#[codec(compact)]` outer attribute on the given `Field`. -// pub fn is_compact(field: &Field) -> bool { -// find_meta_item(field.attrs.iter(), |meta| { -// if let NestedMeta::Meta(Meta::Path(ref path)) = meta { -// if path.is_ident("compact") { -// return Some(()) -// } -// } +pub fn is_compact(field: &syn::Field) -> bool { + let outer_attrs = field + .attrs + .iter() + .filter(|attr| attr.style == AttrStyle::Outer); + find_meta_item(outer_attrs, |meta| { + if let NestedMeta::Meta(Meta::Path(ref path)) = meta { + if path.is_ident("compact") { + return Some(()) + } + } -// None -// }) -// .is_some() -// } + None + }) + .is_some() +} /// Look for a `#[codec(skip)]` in the given attributes. pub fn should_skip(attrs: &[Attribute]) -> bool { From d9239c54f8d40d934d8135ca4c743389899f957a Mon Sep 17 00:00:00 2001 From: David Palm Date: Wed, 17 Mar 2021 17:39:05 +0100 Subject: [PATCH 19/72] Fn is enough --- derive/src/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/derive/src/utils.rs b/derive/src/utils.rs index 2918d330..0dc5eb1f 100644 --- a/derive/src/utils.rs +++ b/derive/src/utils.rs @@ -90,7 +90,7 @@ pub fn should_skip(attrs: &[Attribute]) -> bool { fn find_meta_item<'a, F, R, I>(itr: I, pred: F) -> Option where - F: FnMut(&NestedMeta) -> Option + Clone, + F: Fn(&NestedMeta) -> Option + Clone, I: Iterator, { itr.filter_map(|attr| { From 98292c5f47beba7e8d4e5a2a4d287f647b8ede88 Mon Sep 17 00:00:00 2001 From: David Palm Date: Thu, 18 Mar 2021 10:52:20 +0100 Subject: [PATCH 20/72] Doc tweaks --- derive/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/derive/src/lib.rs b/derive/src/lib.rs index d8fe3db0..91a6e8d3 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -227,9 +227,9 @@ fn generate_c_like_enum_def(variants: &VariantList, scale_info: &Ident) -> Token } fn is_c_like_enum(variants: &VariantList) -> bool { - // any variant has an explicit discriminant + // One of the variants has an explicit discriminant, or… variants.iter().any(|v| v.discriminant.is_some()) || - // all variants are unit + // …all variants are unit variants.iter().all(|v| matches!(v.fields, Fields::Unit)) } From 71d7e11dc40d55b19d840adff92af57ad32abc8d Mon Sep 17 00:00:00 2001 From: David Palm Date: Thu, 18 Mar 2021 10:53:47 +0100 Subject: [PATCH 21/72] Add tests for enums --- src/tests.rs | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/src/tests.rs b/src/tests.rs index fbbf4bea..628fc70a 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -183,3 +183,103 @@ fn basic_struct_with_phantoms() { assert_type!(SomeStruct, struct_bool_type_info); } + +#[test] +fn basic_c_like_enum() { + #[allow(unused)] + enum BasicCStyleEnum { + A, + B, + } + + impl TypeInfo for BasicCStyleEnum { + type Identity = Self; + + fn type_info() -> Type { + Type::builder() + .path(Path::new("BasicCStyleEnum", module_path!())) + .variant(Variants::fieldless().variant("A", 0).variant("B", 1)) + } + } + + let ty = Type::builder() + .path( + Path::from_segments(vec!["scale_info", "tests", "BasicCStyleEnum"]).unwrap(), + ) + .variant(Variants::fieldless().variant("A", 0).variant("B", 1)); + + assert_type!(BasicCStyleEnum, ty); +} + +#[test] +fn c_like_enum_with_discriminant_override() { + #[allow(unused)] + enum CStyleEnum { + A = 3, + B = 0, + } + + impl TypeInfo for CStyleEnum { + type Identity = Self; + + fn type_info() -> Type { + Type::builder() + .path(Path::new("CStyleEnum", module_path!())) + .variant(Variants::fieldless().variant("A", 3).variant("B", 0)) + } + } + + let ty = Type::builder() + .path(Path::from_segments(vec!["scale_info", "tests", "CStyleEnum"]).unwrap()) + .variant(Variants::fieldless().variant("A", 3).variant("B", 0)); + + assert_type!(CStyleEnum, ty); +} + +#[test] +fn basic_enum() { + #[allow(unused)] + enum RustEnum { + A(bool), + B { b: u8 }, + C(u16, u32), + D, + } + impl TypeInfo for RustEnum { + type Identity = Self; + + fn type_info() -> Type { + Type::builder() + .path(Path::new("RustEnum", module_path!())) + .variant( + Variants::with_fields() + .variant("A", Fields::unnamed().field_of::("bool")) + .variant("B", Fields::named().field_of::("b", "bool")) + .variant( + "C", + Fields::unnamed() + .field_of::("u16") + .field_of::("u32"), + ) + .variant_unit("D"), + ) + } + } + + let ty = Type::builder() + .path(Path::new("RustEnum", module_path!())) + .variant( + Variants::with_fields() + .variant("A", Fields::unnamed().field_of::("bool")) + .variant("B", Fields::named().field_of::("b", "bool")) + .variant( + "C", + Fields::unnamed() + .field_of::("u16") + .field_of::("u32"), + ) + .variant_unit("D"), + ); + + assert_type!(RustEnum, ty); +} From 00aee2fe1582c63b226445b6b635e9f114daefc0 Mon Sep 17 00:00:00 2001 From: David Palm Date: Mon, 22 Mar 2021 13:49:34 +0100 Subject: [PATCH 22/72] Add test for indexed enum --- src/tests.rs | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/tests.rs b/src/tests.rs index 628fc70a..01fbb5eb 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -283,3 +283,58 @@ fn basic_enum() { assert_type!(RustEnum, ty); } + +#[test] +fn basic_enum_with_index() { + use scale::Encode; + + #[allow(unused)] + #[derive(Encode)] + enum IndexedRustEnum { + #[codec(index = 3)] + A(bool), + #[codec(index = 0)] + B { + b: u8, + }, + C(u16, u32), + D, + } + impl TypeInfo for IndexedRustEnum { + type Identity = Self; + + fn type_info() -> Type { + Type::builder() + .path(Path::new("IndexedRustEnum", module_path!())) + .variant( + Variants::with_fields() + .indexed("A", 3, Fields::unnamed().field_of::("bool")) + .indexed("B", 0, Fields::named().field_of::("b", "bool")) + .variant( + "C", + Fields::unnamed() + .field_of::("u16") + .field_of::("u32"), + ) + .variant_unit("D"), + ) + } + } + + let ty = Type::builder() + .path(Path::new("IndexedRustEnum", module_path!())) + .variant( + Variants::with_fields() + .indexed("A", 3, Fields::unnamed().field_of::("bool")) + .indexed("B", 0, Fields::named().field_of::("b", "bool")) + .variant( + "C", + Fields::unnamed() + .field_of::("u16") + .field_of::("u32"), + ) + .variant_unit("D"), + ); + + assert_type!(IndexedRustEnum, ty); +} From a31acc5c6757c6e365ed459a8804dd8407a9f1e4 Mon Sep 17 00:00:00 2001 From: David Palm Date: Mon, 22 Mar 2021 14:36:48 +0100 Subject: [PATCH 23/72] Oops --- src/tests.rs | 55 ---------------------------------------------------- 1 file changed, 55 deletions(-) diff --git a/src/tests.rs b/src/tests.rs index 01fbb5eb..628fc70a 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -283,58 +283,3 @@ fn basic_enum() { assert_type!(RustEnum, ty); } - -#[test] -fn basic_enum_with_index() { - use scale::Encode; - - #[allow(unused)] - #[derive(Encode)] - enum IndexedRustEnum { - #[codec(index = 3)] - A(bool), - #[codec(index = 0)] - B { - b: u8, - }, - C(u16, u32), - D, - } - impl TypeInfo for IndexedRustEnum { - type Identity = Self; - - fn type_info() -> Type { - Type::builder() - .path(Path::new("IndexedRustEnum", module_path!())) - .variant( - Variants::with_fields() - .indexed("A", 3, Fields::unnamed().field_of::("bool")) - .indexed("B", 0, Fields::named().field_of::("b", "bool")) - .variant( - "C", - Fields::unnamed() - .field_of::("u16") - .field_of::("u32"), - ) - .variant_unit("D"), - ) - } - } - - let ty = Type::builder() - .path(Path::new("IndexedRustEnum", module_path!())) - .variant( - Variants::with_fields() - .indexed("A", 3, Fields::unnamed().field_of::("bool")) - .indexed("B", 0, Fields::named().field_of::("b", "bool")) - .variant( - "C", - Fields::unnamed() - .field_of::("u16") - .field_of::("u32"), - ) - .variant_unit("D"), - ); - - assert_type!(IndexedRustEnum, ty); -} From e70425fb7803b849f25f6d596b99dd4d72f2c3ed Mon Sep 17 00:00:00 2001 From: David Date: Tue, 23 Mar 2021 11:17:57 +0100 Subject: [PATCH 24/72] Update derive/src/utils.rs Co-authored-by: Andrew Jones --- derive/src/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/derive/src/utils.rs b/derive/src/utils.rs index 0dc5eb1f..1b91a751 100644 --- a/derive/src/utils.rs +++ b/derive/src/utils.rs @@ -56,7 +56,7 @@ pub fn variant_index(v: &Variant, i: usize) -> TokenStream { }) } -// /// Look for a `#[codec(compact)]` outer attribute on the given `Field`. +/// Look for a `#[codec(compact)]` outer attribute on the given `Field`. pub fn is_compact(field: &syn::Field) -> bool { let outer_attrs = field .attrs From abdb0817f03d36b7f6a07646e49b3ddb432fe809 Mon Sep 17 00:00:00 2001 From: David Palm Date: Tue, 23 Mar 2021 11:49:27 +0100 Subject: [PATCH 25/72] Review feedback Better error message Remove redundant tests Test more enum cases to document index/discriminant interaction --- derive/src/utils.rs | 4 +- src/tests.rs | 100 ------------------ src/ty/variant.rs | 2 +- test_suite/tests/derive.rs | 11 +- .../ui/fail_with_invalid_codec_attrs.stderr | 2 +- 5 files changed, 12 insertions(+), 107 deletions(-) diff --git a/derive/src/utils.rs b/derive/src/utils.rs index 1b91a751..990b9ca1 100644 --- a/derive/src/utils.rs +++ b/derive/src/utils.rs @@ -38,7 +38,7 @@ pub fn variant_index(v: &Variant, i: usize) -> TokenStream { if let Lit::Int(ref v) = nv.lit { let byte = v .base10_parse::() - .expect("Internal error, index attribute must have been checked"); + .expect("Internal error. `#[codec(index = …)]` attribute syntax must be checked in `parity-scale-codec`. This is a bug."); return Some(byte) } } @@ -97,7 +97,7 @@ where if attr.path.is_ident("codec") { if let Meta::List(ref meta_list) = attr .parse_meta() - .expect("Internal error, parse_meta must have been checked") + .expect("Internal error. `#[codec(…)]` attributes must be checked in `parity-scale-codec`. This is a bug.") { return meta_list.nested.iter().filter_map(pred.clone()).next() } diff --git a/src/tests.rs b/src/tests.rs index 628fc70a..fbbf4bea 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -183,103 +183,3 @@ fn basic_struct_with_phantoms() { assert_type!(SomeStruct, struct_bool_type_info); } - -#[test] -fn basic_c_like_enum() { - #[allow(unused)] - enum BasicCStyleEnum { - A, - B, - } - - impl TypeInfo for BasicCStyleEnum { - type Identity = Self; - - fn type_info() -> Type { - Type::builder() - .path(Path::new("BasicCStyleEnum", module_path!())) - .variant(Variants::fieldless().variant("A", 0).variant("B", 1)) - } - } - - let ty = Type::builder() - .path( - Path::from_segments(vec!["scale_info", "tests", "BasicCStyleEnum"]).unwrap(), - ) - .variant(Variants::fieldless().variant("A", 0).variant("B", 1)); - - assert_type!(BasicCStyleEnum, ty); -} - -#[test] -fn c_like_enum_with_discriminant_override() { - #[allow(unused)] - enum CStyleEnum { - A = 3, - B = 0, - } - - impl TypeInfo for CStyleEnum { - type Identity = Self; - - fn type_info() -> Type { - Type::builder() - .path(Path::new("CStyleEnum", module_path!())) - .variant(Variants::fieldless().variant("A", 3).variant("B", 0)) - } - } - - let ty = Type::builder() - .path(Path::from_segments(vec!["scale_info", "tests", "CStyleEnum"]).unwrap()) - .variant(Variants::fieldless().variant("A", 3).variant("B", 0)); - - assert_type!(CStyleEnum, ty); -} - -#[test] -fn basic_enum() { - #[allow(unused)] - enum RustEnum { - A(bool), - B { b: u8 }, - C(u16, u32), - D, - } - impl TypeInfo for RustEnum { - type Identity = Self; - - fn type_info() -> Type { - Type::builder() - .path(Path::new("RustEnum", module_path!())) - .variant( - Variants::with_fields() - .variant("A", Fields::unnamed().field_of::("bool")) - .variant("B", Fields::named().field_of::("b", "bool")) - .variant( - "C", - Fields::unnamed() - .field_of::("u16") - .field_of::("u32"), - ) - .variant_unit("D"), - ) - } - } - - let ty = Type::builder() - .path(Path::new("RustEnum", module_path!())) - .variant( - Variants::with_fields() - .variant("A", Fields::unnamed().field_of::("bool")) - .variant("B", Fields::named().field_of::("b", "bool")) - .variant( - "C", - Fields::unnamed() - .field_of::("u16") - .field_of::("u32"), - ) - .variant_unit("D"), - ); - - assert_type!(RustEnum, ty); -} diff --git a/src/ty/variant.rs b/src/ty/variant.rs index b201fc66..dcf2db09 100644 --- a/src/ty/variant.rs +++ b/src/ty/variant.rs @@ -60,7 +60,7 @@ use serde::{ /// Monday, /// Tuesday, /// Wednesday, -/// Thursday = 42, // Also allows to manually set the discriminant! +/// Thursday = 42, // Allows setting the discriminant explicitly /// Friday, /// Saturday, /// Sunday, diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index 580dd5c3..882202be 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -151,13 +151,18 @@ fn c_like_enum_derive_with_scale_index_set() { B = 10, #[codec(index = 13)] C, + D, + #[codec(index = 14)] + E = 15, } let ty = Type::builder().path(Path::new("E", "derive")).variant( Variants::fieldless() - .variant("A", 0u64) - .variant("B", 10u64) - .variant("C", 13u64), + .variant("A", 0) + .variant("B", 10) + .variant("C", 13) + .variant("D", 3) + .variant("E", 14) ); assert_type!(E, ty); diff --git a/test_suite/tests/ui/fail_with_invalid_codec_attrs.stderr b/test_suite/tests/ui/fail_with_invalid_codec_attrs.stderr index 022af73a..e6f49de1 100644 --- a/test_suite/tests/ui/fail_with_invalid_codec_attrs.stderr +++ b/test_suite/tests/ui/fail_with_invalid_codec_attrs.stderr @@ -16,4 +16,4 @@ error: proc-macro derive panicked 11 | #[derive(TypeInfo, Encode)] | ^^^^^^^^ | - = help: message: Internal error, parse_meta must have been checked: Error("expected literal") + = help: message: Internal error. `#[codec(…)]` attributes must be checked in `parity-scale-codec`. This is a bug.: Error("expected literal") From c53eb38d4914b0880a80fa29ffbb8e6c745f1c9a Mon Sep 17 00:00:00 2001 From: David Palm Date: Tue, 23 Mar 2021 11:56:15 +0100 Subject: [PATCH 26/72] fmt --- test_suite/tests/derive.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index 882202be..febae6f3 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -162,7 +162,7 @@ fn c_like_enum_derive_with_scale_index_set() { .variant("B", 10) .variant("C", 13) .variant("D", 3) - .variant("E", 14) + .variant("E", 14), ); assert_type!(E, ty); From 7c0c6f895c1290c5b178095f1e936abd8575c0cb Mon Sep 17 00:00:00 2001 From: David Palm Date: Tue, 23 Mar 2021 14:07:26 +0100 Subject: [PATCH 27/72] wip --- derive/src/lib.rs | 38 ++++++++++++++++++++++---- derive/src/utils.rs | 40 ++++++++++++++------------- src/build.rs | 2 +- src/tests.rs | 56 ++++++++++++++++++++++++++++++++++++++ src/ty/variant.rs | 24 ++++++++++++++++ test_suite/tests/derive.rs | 32 ++++++++++++++++++++++ test_suite/tests/json.rs | 52 +++++++++++++++++++++++++++++++++++ 7 files changed, 219 insertions(+), 25 deletions(-) diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 91a6e8d3..8abf4726 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -245,9 +245,21 @@ fn generate_variant_type(data_enum: &DataEnum, scale_info: &Ident) -> TokenStrea .filter(|v| !utils::should_skip(&v.attrs)) .map(|v| { let ident = &v.ident; - let v_name = quote! {stringify!(#ident) }; - match v.fields { - Fields::Named(ref fs) => { + let v_name = quote! { stringify!(#ident) }; + let index = utils::maybe_index(v); + match (&v.fields, index) { + (Fields::Named(ref fs), Some(index)) => { + let fields = generate_fields(&fs.named); + quote! { + .indexed_variant( + #v_name, + #index, + :: #scale_info::build::Fields::named() + #( #fields)* + ) + } + } + (Fields::Named(ref fs), None) => { let fields = generate_fields(&fs.named); quote! { .variant( @@ -257,7 +269,18 @@ fn generate_variant_type(data_enum: &DataEnum, scale_info: &Ident) -> TokenStrea ) } } - Fields::Unnamed(ref fs) => { + (Fields::Unnamed(ref fs), Some(index)) => { + let fields = generate_fields(&fs.unnamed); + quote! { + .indexed_variant( + #v_name, + #index, + :: #scale_info::build::Fields::unnamed() + #( #fields)* + ) + } + } + (Fields::Unnamed(ref fs), None) => { let fields = generate_fields(&fs.unnamed); quote! { .variant( @@ -267,7 +290,12 @@ fn generate_variant_type(data_enum: &DataEnum, scale_info: &Ident) -> TokenStrea ) } } - Fields::Unit => { + (Fields::Unit, Some(index)) => { + quote! { + .indexed_variant_unit(#v_name, #index) + } + } + (Fields::Unit, None) => { quote! { .variant_unit(#v_name) } diff --git a/derive/src/utils.rs b/derive/src/utils.rs index 990b9ca1..58550f1d 100644 --- a/derive/src/utils.rs +++ b/derive/src/utils.rs @@ -18,21 +18,31 @@ use proc_macro2::TokenStream; use quote::quote; -use syn::{ - spanned::Spanned, - AttrStyle, - Attribute, - Lit, - Meta, - NestedMeta, - Variant, -}; +use syn::{AttrStyle, Attribute, Lit, Meta, NestedMeta, Variant, spanned::Spanned}; /// Look for a `#[codec(index = $int)]` attribute on a variant. If no attribute /// is found, fall back to the discriminant or just the variant index. pub fn variant_index(v: &Variant, i: usize) -> TokenStream { - // first look for an attribute - let index = find_meta_item(v.attrs.iter(), |meta| { + // first look for an `index` attribute… + let index = maybe_index(v); + // …then fallback to discriminant or just index + index.map(|i| quote! { #i }).unwrap_or_else(|| { + v.discriminant + .as_ref() + .map(|&(_, ref expr)| quote! { #expr }) + .unwrap_or_else(|| quote! { #i }) + }) +} + +/// Look for a `#[codec(index = $int)]` outer attribute on a variant. +/// If found, it is expected to be a parseable as a `u8` (panics otherwise). +pub fn maybe_index(variant: &Variant) -> Option { + let outer_attrs = variant + .attrs + .iter() + .filter(|attr| attr.style == AttrStyle::Outer); + + find_meta_item(outer_attrs, |meta| { if let NestedMeta::Meta(Meta::NameValue(ref nv)) = meta { if nv.path.is_ident("index") { if let Lit::Int(ref v) = nv.lit { @@ -45,14 +55,6 @@ pub fn variant_index(v: &Variant, i: usize) -> TokenStream { } None - }); - - // then fallback to discriminant or just index - index.map(|i| quote! { #i }).unwrap_or_else(|| { - v.discriminant - .as_ref() - .map(|&(_, ref expr)| quote! { #expr }) - .unwrap_or_else(|| quote! { #i }) }) } diff --git a/src/build.rs b/src/build.rs index 3bad9718..5a3ecaac 100644 --- a/src/build.rs +++ b/src/build.rs @@ -91,7 +91,7 @@ //! } //! } //! ``` -//! ## Enum without fields +//! ## Enum without fields, aka C-style enums. //! ``` //! # use scale_info::{build::{Fields, Variants}, MetaType, Path, Type, TypeInfo}; //! enum Foo { diff --git a/src/tests.rs b/src/tests.rs index fbbf4bea..02c99f77 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -183,3 +183,59 @@ fn basic_struct_with_phantoms() { assert_type!(SomeStruct, struct_bool_type_info); } + +#[test] +fn basic_enum_with_index() { + use scale::Encode; + + #[allow(unused)] + #[derive(Encode)] + enum IndexedRustEnum { + #[codec(index = 3)] + A(bool), + #[codec(index = 0)] + B { + b: u8, + }, + C(u16, u32), + D, + } + impl TypeInfo for IndexedRustEnum { + type Identity = Self; + + fn type_info() -> Type { + Type::builder() + .path(Path::new("IndexedRustEnum", module_path!())) + .variant( + Variants::with_fields() + .indexed_variant("A", 3, Fields::unnamed().field_of::("bool")) + .indexed_variant("B", 0, Fields::named().field_of::("b", "bool")) + .variant( + "C", + Fields::unnamed() + .field_of::("u16") + .field_of::("u32"), + ) + .variant_unit("D"), + ) + } + } + + let ty = Type::builder() + .path(Path::new("IndexedRustEnum", module_path!())) + .variant( + Variants::with_fields() + .indexed_variant("A", 3, Fields::unnamed().field_of::("bool")) + .indexed_variant("B", 0, Fields::named().field_of::("b", "bool")) + .variant( + "C", + Fields::unnamed() + .field_of::("u16") + .field_of::("u32"), + ) + .variant_unit("D"), + ); + + assert_type!(IndexedRustEnum, ty); + // TODO: assert on encoding too +} diff --git a/src/ty/variant.rs b/src/ty/variant.rs index dcf2db09..109b9325 100644 --- a/src/ty/variant.rs +++ b/src/ty/variant.rs @@ -158,6 +158,12 @@ pub struct Variant { serde(skip_serializing_if = "Vec::is_empty", default) )] fields: Vec>, + /// Index of the variant, used in `parity-scale-codec` + #[cfg_attr( + feature = "serde", + serde(skip_serializing_if = "Option::is_none", default) + )] + index: Option, /// The discriminant of the variant. /// /// # Note @@ -169,6 +175,7 @@ pub struct Variant { feature = "serde", serde(skip_serializing_if = "Option::is_none", default) )] + // TODO: why is this a `u64` and not a `usize`? To ensure it's consistent across platforms? discriminant: Option, } @@ -179,6 +186,7 @@ impl IntoPortable for Variant { Variant { name: self.name.into_portable(registry), fields: registry.map_into_portable(self.fields), + index: self.index, discriminant: self.discriminant, } } @@ -190,6 +198,21 @@ impl Variant { Self { name, fields: fields.finalize(), + index: None, + discriminant: None, + } + } + + /// Creates a new indexed variant with the given fields. + pub fn indexed_fields(name: &'static str, index: u8, fields: FieldsBuilder) -> Self { + Self { + name, + fields: fields.finalize(), + // TODO: this is where it gets yucky. Store the index but leaving + // the discriminant empty here, and vice versa below in + // `with_discriminant`. OTOH discriminants are (likely) `usize` + // whereas `index` is `u8`. So perhaps it's as good as it gets. + index: Some(index), discriminant: None, } } @@ -199,6 +222,7 @@ impl Variant { Self { name, fields: Vec::new(), + index: None, discriminant: Some(discriminant), } } diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index febae6f3..5e6a45f5 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -22,6 +22,7 @@ use scale_info::{ boxed::Box, marker::PhantomData, vec::Vec, + vec, }, tuple_meta_type, Path, @@ -166,6 +167,11 @@ fn c_like_enum_derive_with_scale_index_set() { ); assert_type!(E, ty); + // TODO: remove + assert_eq!( + vec![E::A.encode(), E::B.encode(), E::C.encode()], + vec![vec![0], vec![10], vec![13]], + ); } #[test] @@ -191,6 +197,32 @@ fn enum_derive() { assert_type!(E, ty); } +#[test] +fn enum_derive_with_codec_index() { + #[allow(unused)] + #[derive(TypeInfo, Encode)] + enum E { + #[codec(index = 5)] + A(T), + #[codec(index = 0)] + B { b: T }, + #[codec(index = 13)] + C, + } + + let ty = Type::builder() + .path(Path::new("E", "derive")) + .type_params(tuple_meta_type!(bool)) + .variant( + Variants::with_fields() + .indexed_variant("A", 5, Fields::unnamed().field_of::("T")) + .indexed_variant("B", 0, Fields::named().field_of::("b", "T")) + .indexed_variant_unit("C", 13), + ); + + assert_type!(E, ty); +} + #[test] fn recursive_type_derive() { #[allow(unused)] diff --git a/test_suite/tests/json.rs b/test_suite/tests/json.rs index 9ece5fc3..b22881d7 100644 --- a/test_suite/tests/json.rs +++ b/test_suite/tests/json.rs @@ -326,6 +326,58 @@ fn test_enum() { })); } +#[test] +fn enums_with_scale_indexed_variants() { + #[derive(TypeInfo, Encode)] + enum Animal { + #[codec(index = 123)] + Ape(u8), + #[codec(index = 12)] + Boar { a: u16, b: u32}, + #[codec(index = 1)] + Cat, + #[codec(index = 0)] + Dog(u64, u128), + } + + assert_json_for_type::(json!({ + "path": ["json", "Animal"], + "def": { + "variant": { + "variants": [ + { + "name": "Ape", + "index": 123, + "fields": [ + { "type": 1, "typeName": "u8" } + ] + }, + { + "name": "Boar", + "index": 12, + "fields": [ + { "name": "a", "type": 2, "typeName": "u16" }, + { "name": "b", "type": 3, "typeName": "u32" } + ] + }, + { + "name": "Cat", + "index": 1, + }, + { + "name": "Dog", + "index": 0, + "fields": [ + { "type": 4, "typeName": "u64" }, + { "type": 5, "typeName": "u128" } + ] + } + ] + } + } + })); +} + #[test] fn test_recursive_type_with_box() { #[derive(TypeInfo)] From 1a0a0304484a72a2f12b4190b98f0930c14c39f8 Mon Sep 17 00:00:00 2001 From: David Palm Date: Tue, 23 Mar 2021 14:08:59 +0100 Subject: [PATCH 28/72] Add indexed_* --- src/build.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/build.rs b/src/build.rs index 5a3ecaac..a9d016e3 100644 --- a/src/build.rs +++ b/src/build.rs @@ -331,10 +331,22 @@ impl VariantsBuilder { self } + /// Add an indexed variant with fields constructed by the supplied [`FieldsBuilder`](`crate::build::FieldsBuilder`) + pub fn indexed_variant(mut self, name: &'static str, index: u8, fields: FieldsBuilder) -> Self { + self.variants.push(Variant::indexed_fields(name, index, fields)); + self + } + /// Add a variant with no fields i.e. a unit variant pub fn variant_unit(self, name: &'static str) -> Self { self.variant::(name, Fields::unit()) } + + /// Add a variant with no fields i.e. a unit variant + // TODO: finish + pub fn indexed_variant_unit(self, name: &'static str, index: u8) -> Self { + self.indexed_variant::(name, index, Fields::unit()) + } } impl VariantsBuilder { From 2dd05cb991ce3ac5cacb4f822cf11713195819b8 Mon Sep 17 00:00:00 2001 From: David Palm Date: Tue, 23 Mar 2021 14:21:32 +0100 Subject: [PATCH 29/72] Renames, sort out todos --- src/build.rs | 3 +-- src/tests.rs | 1 - src/ty/variant.rs | 7 +------ test_suite/tests/derive.rs | 5 ----- 4 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/build.rs b/src/build.rs index a9d016e3..243b9d7e 100644 --- a/src/build.rs +++ b/src/build.rs @@ -333,7 +333,7 @@ impl VariantsBuilder { /// Add an indexed variant with fields constructed by the supplied [`FieldsBuilder`](`crate::build::FieldsBuilder`) pub fn indexed_variant(mut self, name: &'static str, index: u8, fields: FieldsBuilder) -> Self { - self.variants.push(Variant::indexed_fields(name, index, fields)); + self.variants.push(Variant::indexed_with_fields(name, index, fields)); self } @@ -343,7 +343,6 @@ impl VariantsBuilder { } /// Add a variant with no fields i.e. a unit variant - // TODO: finish pub fn indexed_variant_unit(self, name: &'static str, index: u8) -> Self { self.indexed_variant::(name, index, Fields::unit()) } diff --git a/src/tests.rs b/src/tests.rs index 02c99f77..2e0c99f0 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -237,5 +237,4 @@ fn basic_enum_with_index() { ); assert_type!(IndexedRustEnum, ty); - // TODO: assert on encoding too } diff --git a/src/ty/variant.rs b/src/ty/variant.rs index 109b9325..65b37c2b 100644 --- a/src/ty/variant.rs +++ b/src/ty/variant.rs @@ -175,7 +175,6 @@ pub struct Variant { feature = "serde", serde(skip_serializing_if = "Option::is_none", default) )] - // TODO: why is this a `u64` and not a `usize`? To ensure it's consistent across platforms? discriminant: Option, } @@ -204,14 +203,10 @@ impl Variant { } /// Creates a new indexed variant with the given fields. - pub fn indexed_fields(name: &'static str, index: u8, fields: FieldsBuilder) -> Self { + pub fn indexed_with_fields(name: &'static str, index: u8, fields: FieldsBuilder) -> Self { Self { name, fields: fields.finalize(), - // TODO: this is where it gets yucky. Store the index but leaving - // the discriminant empty here, and vice versa below in - // `with_discriminant`. OTOH discriminants are (likely) `usize` - // whereas `index` is `u8`. So perhaps it's as good as it gets. index: Some(index), discriminant: None, } diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index 5e6a45f5..0562e0de 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -167,11 +167,6 @@ fn c_like_enum_derive_with_scale_index_set() { ); assert_type!(E, ty); - // TODO: remove - assert_eq!( - vec![E::A.encode(), E::B.encode(), E::C.encode()], - vec![vec![0], vec![10], vec![13]], - ); } #[test] From 81e6fc36ce84b20165def5cf0f56b83bcf4f55c4 Mon Sep 17 00:00:00 2001 From: David Palm Date: Tue, 23 Mar 2021 14:24:12 +0100 Subject: [PATCH 30/72] fmt --- derive/src/utils.rs | 10 +++++++++- src/build.rs | 10 ++++++++-- src/tests.rs | 12 ++++++++++-- src/ty/variant.rs | 6 +++++- test_suite/tests/derive.rs | 2 +- test_suite/tests/json.rs | 2 +- 6 files changed, 34 insertions(+), 8 deletions(-) diff --git a/derive/src/utils.rs b/derive/src/utils.rs index 58550f1d..e527d4c5 100644 --- a/derive/src/utils.rs +++ b/derive/src/utils.rs @@ -18,7 +18,15 @@ use proc_macro2::TokenStream; use quote::quote; -use syn::{AttrStyle, Attribute, Lit, Meta, NestedMeta, Variant, spanned::Spanned}; +use syn::{ + spanned::Spanned, + AttrStyle, + Attribute, + Lit, + Meta, + NestedMeta, + Variant, +}; /// Look for a `#[codec(index = $int)]` attribute on a variant. If no attribute /// is found, fall back to the discriminant or just the variant index. diff --git a/src/build.rs b/src/build.rs index 243b9d7e..86a3a8a4 100644 --- a/src/build.rs +++ b/src/build.rs @@ -332,8 +332,14 @@ impl VariantsBuilder { } /// Add an indexed variant with fields constructed by the supplied [`FieldsBuilder`](`crate::build::FieldsBuilder`) - pub fn indexed_variant(mut self, name: &'static str, index: u8, fields: FieldsBuilder) -> Self { - self.variants.push(Variant::indexed_with_fields(name, index, fields)); + pub fn indexed_variant( + mut self, + name: &'static str, + index: u8, + fields: FieldsBuilder, + ) -> Self { + self.variants + .push(Variant::indexed_with_fields(name, index, fields)); self } diff --git a/src/tests.rs b/src/tests.rs index 2e0c99f0..20d7e420 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -208,8 +208,16 @@ fn basic_enum_with_index() { .path(Path::new("IndexedRustEnum", module_path!())) .variant( Variants::with_fields() - .indexed_variant("A", 3, Fields::unnamed().field_of::("bool")) - .indexed_variant("B", 0, Fields::named().field_of::("b", "bool")) + .indexed_variant( + "A", + 3, + Fields::unnamed().field_of::("bool"), + ) + .indexed_variant( + "B", + 0, + Fields::named().field_of::("b", "bool"), + ) .variant( "C", Fields::unnamed() diff --git a/src/ty/variant.rs b/src/ty/variant.rs index 65b37c2b..f127ef37 100644 --- a/src/ty/variant.rs +++ b/src/ty/variant.rs @@ -203,7 +203,11 @@ impl Variant { } /// Creates a new indexed variant with the given fields. - pub fn indexed_with_fields(name: &'static str, index: u8, fields: FieldsBuilder) -> Self { + pub fn indexed_with_fields( + name: &'static str, + index: u8, + fields: FieldsBuilder, + ) -> Self { Self { name, fields: fields.finalize(), diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index 0562e0de..6b51e0ce 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -21,8 +21,8 @@ use scale_info::{ prelude::{ boxed::Box, marker::PhantomData, - vec::Vec, vec, + vec::Vec, }, tuple_meta_type, Path, diff --git a/test_suite/tests/json.rs b/test_suite/tests/json.rs index b22881d7..2a233926 100644 --- a/test_suite/tests/json.rs +++ b/test_suite/tests/json.rs @@ -333,7 +333,7 @@ fn enums_with_scale_indexed_variants() { #[codec(index = 123)] Ape(u8), #[codec(index = 12)] - Boar { a: u16, b: u32}, + Boar { a: u16, b: u32 }, #[codec(index = 1)] Cat, #[codec(index = 0)] From 14bbbe9025d75cc696c53cf3ea933eb007043004 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 26 Apr 2021 17:08:13 +0100 Subject: [PATCH 31/72] Capture docs for types, fields, and enum variants --- derive/src/lib.rs | 23 +++++--- derive/src/utils.rs | 20 +++++++ src/build.rs | 59 +++++++++++--------- src/impls.rs | 14 ++--- src/registry.rs | 3 + src/tests.rs | 24 ++++---- src/ty/fields.rs | 23 ++++++-- src/ty/mod.rs | 14 ++++- src/ty/variant.rs | 17 +++++- test_suite/tests/derive.rs | 110 ++++++++++++++++++++++--------------- test_suite/tests/json.rs | 8 +-- 11 files changed, 205 insertions(+), 110 deletions(-) diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 91a6e8d3..28e63c08 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -96,6 +96,8 @@ fn generate_type(input: TokenStream2) -> Result { Data::Enum(ref e) => generate_variant_type(e, &scale_info), Data::Union(_) => return Err(Error::new_spanned(input, "Unions not supported")), }; + let docs = utils::get_doc_literals(&ast.attrs); + let type_info_impl = quote! { impl #impl_generics :: #scale_info ::TypeInfo for #ident #ty_generics #where_clause { type Identity = Self; @@ -103,6 +105,7 @@ fn generate_type(input: TokenStream2) -> Result { :: #scale_info ::Type::builder() .path(:: #scale_info ::Path::new(stringify!(#ident), module_path!())) .type_params(:: #scale_info ::prelude::vec![ #( #generic_type_ids ),* ]) + .docs(&[ #( #docs ),* ]) .#build_type } } @@ -149,15 +152,16 @@ fn generate_fields(fields: &FieldsList) -> Vec { StaticLifetimesReplace.visit_type_mut(&mut ty); let type_name = clean_type_string("e!(#ty).to_string()); + let docs = utils::get_doc_literals(&f.attrs); let method_call = if utils::is_compact(f) { quote!(.compact_of::<#ty>) } else { quote!(.field_of::<#ty>) }; if let Some(ident) = ident { - quote!(#method_call(stringify!(#ident), #type_name)) + quote!(#method_call(stringify!(#ident), #type_name, &[ #( #docs ),* ])) } else { - quote!(#method_call(#type_name)) + quote!(#method_call(#type_name, &[ #( #docs ),* ])) } }) .collect() @@ -214,8 +218,9 @@ fn generate_c_like_enum_def(variants: &VariantList, scale_info: &Ident) -> Token .map(|(i, v)| { let name = &v.ident; let discriminant = utils::variant_index(v, i); + let docs = utils::get_doc_literals(&v.attrs); quote! { - .variant(stringify!(#name), #discriminant as u64) + .variant(stringify!(#name), #discriminant as u64, &[ #( #docs ),* ]) } }); quote! { @@ -246,6 +251,8 @@ fn generate_variant_type(data_enum: &DataEnum, scale_info: &Ident) -> TokenStrea .map(|v| { let ident = &v.ident; let v_name = quote! {stringify!(#ident) }; + let docs = utils::get_doc_literals(&v.attrs); + match v.fields { Fields::Named(ref fs) => { let fields = generate_fields(&fs.named); @@ -253,7 +260,8 @@ fn generate_variant_type(data_enum: &DataEnum, scale_info: &Ident) -> TokenStrea .variant( #v_name, :: #scale_info::build::Fields::named() - #( #fields)* + #( #fields )*, + &[ #( #docs ),* ] ) } } @@ -263,13 +271,14 @@ fn generate_variant_type(data_enum: &DataEnum, scale_info: &Ident) -> TokenStrea .variant( #v_name, :: #scale_info::build::Fields::unnamed() - #( #fields)* + #( #fields )*, + &[ #( #docs ),* ] ) } } Fields::Unit => { quote! { - .variant_unit(#v_name) + .variant_unit(#v_name, &[ #( #docs ),* ]) } } } @@ -277,7 +286,7 @@ fn generate_variant_type(data_enum: &DataEnum, scale_info: &Ident) -> TokenStrea quote! { variant( :: #scale_info ::build::Variants::with_fields() - #( #variants)* + #( #variants )* ) } } diff --git a/derive/src/utils.rs b/derive/src/utils.rs index f3911c98..b19e22d3 100644 --- a/derive/src/utils.rs +++ b/derive/src/utils.rs @@ -16,6 +16,7 @@ //! //! NOTE: The code here is copied verbatim from `parity-scale-codec-derive`. +use alloc::vec::Vec; use proc_macro2::TokenStream; use quote::quote; use syn::{ @@ -28,6 +29,23 @@ use syn::{ Variant, }; +/// Return all doc attributes literals found. +pub fn get_doc_literals(attrs: &Vec) -> Vec { + attrs.iter() + .filter_map(|attr| { + if let Ok(syn::Meta::NameValue(meta)) = attr.parse_meta() { + if meta.path.get_ident().map_or(false, |ident| ident == "doc") { + Some(meta.lit) + } else { + None + } + } else { + None + } + }) + .collect() +} + /// Look for a `#[codec(index = $int)]` attribute on a variant. If no attribute /// is found, fall back to the discriminant or just the variant index. pub fn variant_index(v: &Variant, i: usize) -> TokenStream { @@ -107,3 +125,5 @@ where }) .next() } + + diff --git a/src/build.rs b/src/build.rs index 3bad9718..1b4090c5 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", "T") -//! .field_of::("data", "u64") +//! .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::("u32") -//! .field_of::("bool") +//! .field_of::("u32", &[]) +//! .field_of::("bool", &[]) //! ) //! } //! } @@ -84,9 +84,9 @@ //! .type_params(vec![MetaType::new::()]) //! .variant( //! Variants::with_fields() -//! .variant("A", Fields::unnamed().field_of::("T")) -//! .variant("B", Fields::named().field_of::("f", "u32")) -//! .variant("C", Fields::unit()) +//! .variant("A", Fields::unnamed().field_of::("T", &[]), &[]) +//! .variant("B", Fields::named().field_of::("f", "u32", &[]), &[]) +//! .variant("C", Fields::unit(), &[]), //! ) //! } //! } @@ -108,9 +108,9 @@ //! .path(Path::new("Foo", module_path!())) //! .variant( //! Variants::fieldless() -//! .variant("A", 1) -//! .variant("B", 2) -//! .variant("C", 33) +//! .variant("A", 1, &[]) +//! .variant("B", 2, &[]) +//! .variant("C", 33, &[]) //! ) //! } //! } @@ -146,6 +146,7 @@ pub mod state { pub struct TypeBuilder { path: Option, type_params: Vec, + docs: Vec<&'static str>, marker: PhantomData S>, } @@ -154,6 +155,7 @@ impl Default for TypeBuilder { TypeBuilder { path: Default::default(), type_params: Default::default(), + docs: Default::default(), marker: Default::default(), } } @@ -165,6 +167,7 @@ impl TypeBuilder { TypeBuilder { path: Some(path), type_params: self.type_params, + docs: self.docs, marker: Default::default(), } } @@ -176,7 +179,7 @@ impl TypeBuilder { D: Into, { let path = self.path.expect("Path not assigned"); - Type::new(path, self.type_params, type_def) + Type::new(path, self.type_params, type_def, self.docs) } /// Construct a "variant" type i.e an `enum` @@ -199,6 +202,12 @@ impl TypeBuilder { self.type_params = type_params.into_iter().collect(); self } + + /// Set the type documentation + pub fn docs(mut self, docs: &[&'static str]) -> Self { + self.docs = docs.to_vec(); + self + } } /// A fields builder has no fields (e.g. a unit struct) @@ -252,43 +261,43 @@ impl FieldsBuilder { impl FieldsBuilder { /// Add a named field with the type of the type parameter `T` - pub fn field_of(mut self, name: &'static str, type_name: &'static str) -> Self + pub fn field_of(mut self, name: &'static str, type_name: &'static str, docs: &[&'static str]) -> Self where T: TypeInfo + ?Sized + 'static, { - self.fields.push(Field::named_of::(name, type_name)); + self.fields.push(Field::named_of::(name, type_name, docs)); self } /// Add a named, [`Compact`] field of type `T`. - pub fn compact_of(mut self, name: &'static str, type_name: &'static str) -> Self + pub fn compact_of(mut self, name: &'static str, type_name: &'static str, docs: &[&'static str]) -> Self where T: scale::HasCompact, ::Type: TypeInfo + 'static, { self.fields - .push(Field::compact_of::(Some(name), type_name)); + .push(Field::compact_of::(Some(name), type_name, docs)); self } } impl FieldsBuilder { /// Add an unnamed field with the type of the type parameter `T` - pub fn field_of(mut self, type_name: &'static str) -> Self + pub fn field_of(mut self, type_name: &'static str, docs: &[&'static str]) -> Self where T: TypeInfo + ?Sized + 'static, { - self.fields.push(Field::unnamed_of::(type_name)); + self.fields.push(Field::unnamed_of::(type_name, docs)); self } /// Add an unnamed, [`Compact`] field of type `T`. - pub fn compact_of(mut self, type_name: &'static str) -> Self + pub fn compact_of(mut self, type_name: &'static str, docs: &[&'static str]) -> Self where T: scale::HasCompact, ::Type: TypeInfo + 'static, { - self.fields.push(Field::compact_of::(None, type_name)); + self.fields.push(Field::compact_of::(None, type_name, docs)); self } } @@ -326,22 +335,22 @@ pub struct VariantsBuilder { impl VariantsBuilder { /// Add a variant with fields constructed by the supplied [`FieldsBuilder`](`crate::build::FieldsBuilder`) - pub fn variant(mut self, name: &'static str, fields: FieldsBuilder) -> Self { - self.variants.push(Variant::with_fields(name, fields)); + pub fn variant(mut self, name: &'static str, fields: FieldsBuilder, docs: &[&'static str]) -> Self { + self.variants.push(Variant::with_fields(name, fields, docs.to_vec())); self } /// Add a variant with no fields i.e. a unit variant - pub fn variant_unit(self, name: &'static str) -> Self { - self.variant::(name, Fields::unit()) + pub fn variant_unit(self, name: &'static str, docs: &[&'static str]) -> Self { + self.variant::(name, Fields::unit(), docs) } } impl VariantsBuilder { /// Add a fieldless variant, explicitly setting the discriminant - pub fn variant(mut self, name: &'static str, discriminant: u64) -> Self { + pub fn variant(mut self, name: &'static str, discriminant: u64, docs: &[&'static str]) -> Self { self.variants - .push(Variant::with_discriminant(name, discriminant)); + .push(Variant::with_discriminant(name, discriminant, docs)); self } } diff --git a/src/impls.rs b/src/impls.rs index 16da5b06..090c737c 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -134,8 +134,8 @@ where .type_params(tuple_meta_type![T]) .variant( Variants::with_fields() - .variant_unit("None") - .variant("Some", Fields::unnamed().field_of::("T")), + .variant_unit("None", &[]) + .variant("Some", Fields::unnamed().field_of::("T", &[]), &[]), ) } } @@ -153,8 +153,8 @@ where .type_params(tuple_meta_type!(T, E)) .variant( Variants::with_fields() - .variant("Ok", Fields::unnamed().field_of::("T")) - .variant("Err", Fields::unnamed().field_of::("E")), + .variant("Ok", Fields::unnamed().field_of::("T", &[]), &[]) + .variant("Err", Fields::unnamed().field_of::("E", &[]), &[]), ) } } @@ -169,7 +169,7 @@ where Type::builder() .path(Path::prelude("Cow")) .type_params(tuple_meta_type!(T)) - .composite(Fields::unnamed().field_of::("T")) + .composite(Fields::unnamed().field_of::("T", &[])) } } @@ -184,7 +184,7 @@ where Type::builder() .path(Path::prelude("BTreeMap")) .type_params(tuple_meta_type![(K, V)]) - .composite(Fields::unnamed().field_of::<[(K, V)]>("[(K, V)]")) + .composite(Fields::unnamed().field_of::<[(K, V)]>("[(K, V)]", &[])) } } @@ -198,7 +198,7 @@ where Type::builder() .path(Path::prelude("BTreeSet")) .type_params(tuple_meta_type![T]) - .composite(Fields::unnamed().field_of::<[T]>("[T]")) + .composite(Fields::unnamed().field_of::<[T]>("[T]", &[])) } } diff --git a/src/registry.rs b/src/registry.rs index 5678d121..25830d8f 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -240,14 +240,17 @@ mod tests { .field_of::>( "boxed", "Box < RecursiveRefs >", + &[], ) .field_of::<&'static RecursiveRefs<'static>>( "reference", "&RecursiveRefs", + &[], ) .field_of::<&'static mut RecursiveRefs<'static>>( "mutable_reference", "&mut RecursiveRefs", + &[], ), ) } diff --git a/src/tests.rs b/src/tests.rs index fea9a82e..c5724223 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -63,8 +63,8 @@ fn prelude_items() { .type_params(tuple_meta_type!(u128)) .variant( Variants::with_fields() - .variant_unit("None") - .variant("Some", Fields::unnamed().field_of::("T")) + .variant_unit("None", &[]) + .variant("Some", Fields::unnamed().field_of::("T", &[]), &[]) ) ); assert_type!( @@ -74,8 +74,8 @@ fn prelude_items() { .type_params(tuple_meta_type!(bool, String)) .variant( Variants::with_fields() - .variant("Ok", Fields::unnamed().field_of::("T")) - .variant("Err", Fields::unnamed().field_of::("E")) + .variant("Ok", Fields::unnamed().field_of::("T", &[]), &[]) + .variant("Err", Fields::unnamed().field_of::("E", &[]), &[]) ) ); assert_type!(PhantomData, TypeDefPhantom::new(meta_type::())); @@ -84,7 +84,7 @@ fn prelude_items() { Type::builder() .path(Path::prelude("Cow")) .type_params(tuple_meta_type!(u128)) - .composite(Fields::unnamed().field_of::("T")) + .composite(Fields::unnamed().field_of::("T", &[])) ); } @@ -95,7 +95,7 @@ fn collections() { Type::builder() .path(Path::prelude("BTreeMap")) .type_params(tuple_meta_type![(String, u32)]) - .composite(Fields::unnamed().field_of::<[(String, u32)]>("[(K, V)]")) + .composite(Fields::unnamed().field_of::<[(String, u32)]>("[(K, V)]", &[])) ); assert_type!( @@ -103,7 +103,7 @@ fn collections() { Type::builder() .path(Path::prelude("BTreeSet")) .type_params(tuple_meta_type![String]) - .composite(Fields::unnamed().field_of::<[String]>("[T]")) + .composite(Fields::unnamed().field_of::<[String]>("[T]", &[])) ); } @@ -162,7 +162,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", "T")) + .composite(Fields::named().field_of::("data", "T", &[])) } } @@ -170,7 +170,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", "T")); + .composite(Fields::named().field_of::("data", "T", &[])); assert_type!(MyStruct, struct_bool_type_info); @@ -179,7 +179,7 @@ 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", "T")); + .composite(Fields::named().field_of::>>("data", "T", &[])); assert_type!(SelfTyped, expected_type); } @@ -201,14 +201,14 @@ fn basic_struct_with_phantoms() { Type::builder() .path(Path::new("SomeStruct", module_path!())) .type_params(tuple_meta_type!(T)) - .composite(Fields::named().field_of::("a", "u8")) + .composite(Fields::named().field_of::("a", "u8", &[])) } } let struct_bool_type_info = Type::builder() .path(Path::from_segments(vec!["scale_info", "tests", "SomeStruct"]).unwrap()) .type_params(tuple_meta_type!(bool)) - .composite(Fields::named().field_of::("a", "u8")); + .composite(Fields::named().field_of::("a", "u8", &[])); assert_type!(SomeStruct, struct_bool_type_info); } diff --git a/src/ty/fields.rs b/src/ty/fields.rs index 1ef06ce9..2dfecab9 100644 --- a/src/ty/fields.rs +++ b/src/ty/fields.rs @@ -79,6 +79,9 @@ pub struct Field { ty: T::Type, /// The name of the type of the field as it appears in the source code. type_name: T::String, + /// Documentation + #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty", default))] + docs: Vec, } impl IntoPortable for Field { @@ -89,6 +92,7 @@ impl IntoPortable for Field { name: self.name.map(|name| name.into_portable(registry)), ty: registry.register_type(&self.ty), type_name: self.type_name.into_portable(registry), + docs: registry.map_into_portable(self.docs), } } } @@ -101,11 +105,13 @@ impl Field { name: Option<&'static str>, ty: MetaType, type_name: &'static str, + docs: &[&'static str], ) -> Self { Self { name, ty, type_name, + docs: docs.to_vec() } } @@ -113,31 +119,31 @@ impl Field { /// /// Use this constructor if you want to instantiate from a given /// compile-time type. - pub fn named_of(name: &'static str, type_name: &'static str) -> Field + pub fn named_of(name: &'static str, type_name: &'static str, docs: &[&'static str]) -> Field where T: TypeInfo + ?Sized + 'static, { - Self::new(Some(name), MetaType::new::(), type_name) + Self::new(Some(name), MetaType::new::(), type_name, docs) } /// 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(type_name: &'static str) -> Field + pub fn unnamed_of(type_name: &'static str, docs: &[&'static str]) -> Field where T: TypeInfo + ?Sized + 'static, { - Self::new(None, MetaType::new::(), type_name) + Self::new(None, MetaType::new::(), type_name, docs) } /// Creates a new [`Compact`] field. - pub fn compact_of(name: Option<&'static str>, type_name: &'static str) -> Field + pub fn compact_of(name: Option<&'static str>, type_name: &'static str, docs: &[&'static str]) -> Field where T: HasCompact, ::Type: TypeInfo + 'static, { - Self::new(name, MetaType::new::<::Type>(), type_name) + Self::new(name, MetaType::new::<::Type>(), type_name, docs) } } @@ -163,4 +169,9 @@ where pub fn type_name(&self) -> &T::String { &self.type_name } + + /// Returns the documentation of the field. + pub fn docs(&self) -> &[T::String] { + &self.docs + } } diff --git a/src/ty/mod.rs b/src/ty/mod.rs index e3dd5cf4..3a90795a 100644 --- a/src/ty/mod.rs +++ b/src/ty/mod.rs @@ -78,6 +78,9 @@ pub struct Type { /// The actual type definition #[cfg_attr(feature = "serde", serde(rename = "def"))] type_def: TypeDef, + /// Documentation + #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty", default))] + docs: Vec, } impl IntoPortable for Type { @@ -88,6 +91,7 @@ impl IntoPortable for Type { path: self.path.into_portable(registry), type_params: registry.register_types(self.type_params), type_def: self.type_def.into_portable(registry), + docs: registry.map_into_portable(self.docs), } } } @@ -96,7 +100,7 @@ macro_rules! impl_from_type_def_for_type { ( $( $t:ty ), + $(,)?) => { $( impl From<$t> for Type { fn from(item: $t) -> Self { - Self::new(Path::voldemort(), Vec::new(), item) + Self::new(Path::voldemort(), Vec::new(), item, Vec::new()) } } )* } @@ -117,7 +121,7 @@ impl Type { TypeBuilder::default() } - pub(crate) fn new(path: Path, type_params: I, type_def: D) -> Self + pub(crate) fn new(path: Path, type_params: I, type_def: D, docs: Vec<&'static str>) -> Self where I: IntoIterator, D: Into, @@ -126,6 +130,7 @@ impl Type { path, type_params: type_params.into_iter().collect(), type_def: type_def.into(), + docs, } } } @@ -148,6 +153,11 @@ where pub fn type_def(&self) -> &TypeDef { &self.type_def } + + /// Returns the documentation of the type + pub fn docs(&self) -> &[T::String] { + &self.docs + } } /// The possible types a SCALE encodable Rust value could have. diff --git a/src/ty/variant.rs b/src/ty/variant.rs index dcf2db09..dc8d2a44 100644 --- a/src/ty/variant.rs +++ b/src/ty/variant.rs @@ -170,6 +170,9 @@ pub struct Variant { serde(skip_serializing_if = "Option::is_none", default) )] discriminant: Option, + /// Documentation + #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty", default))] + docs: Vec, } impl IntoPortable for Variant { @@ -180,26 +183,29 @@ impl IntoPortable for Variant { name: self.name.into_portable(registry), fields: registry.map_into_portable(self.fields), discriminant: self.discriminant, + docs: registry.map_into_portable(self.docs), } } } impl Variant { /// Creates a new variant with the given fields. - pub fn with_fields(name: &'static str, fields: FieldsBuilder) -> Self { + pub fn with_fields(name: &'static str, fields: FieldsBuilder, docs: Vec<&'static str>) -> Self { Self { name, fields: fields.finalize(), discriminant: None, + docs: docs.to_vec(), } } /// Creates a new variant with the given discriminant. - pub fn with_discriminant(name: &'static str, discriminant: u64) -> Self { + pub fn with_discriminant(name: &'static str, discriminant: u64, docs: &[&'static str]) -> Self { Self { name, fields: Vec::new(), discriminant: Some(discriminant), + docs: docs.to_vec(), } } } @@ -208,7 +214,7 @@ impl Variant where T: Form, { - /// Returns the name of the variant + /// Returns the name of the variant. pub fn name(&self) -> &T::String { &self.name } @@ -222,4 +228,9 @@ where pub fn discriminant(&self) -> Option { self.discriminant } + + /// Returns the documentation of the variant. + pub fn docs(&self) -> &[T::String] { + &self.docs + } } diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index febae6f3..155fafc2 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -57,8 +57,8 @@ fn struct_derive() { .type_params(tuple_meta_type!(bool, u8)) .composite( Fields::named() - .field_of::("t", "T") - .field_of::("u", "U"), + .field_of::("t", "T", &[]) + .field_of::("u", "U", &[]), ); assert_type!(S, struct_type); @@ -72,8 +72,8 @@ fn struct_derive() { .type_params(tuple_meta_type!(Box>, bool)) .composite( Fields::named() - .field_of::>>("t", "T") - .field_of::("u", "U"), + .field_of::>>("t", "T", &[]) + .field_of::("u", "U", &[]), ); assert_type!(SelfTyped, self_typed_type); } @@ -92,8 +92,8 @@ fn phantom_data_is_part_of_the_type_info() { .type_params(tuple_meta_type!(bool)) .composite( Fields::named() - .field_of::("a", "u8") - .field_of::>("m", "PhantomData"), + .field_of::("a", "u8", &[]) + .field_of::>("m", "PhantomData", &[]), ); assert_type!(P, ty); @@ -108,7 +108,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::("T")); + .composite(Fields::unnamed().field_of::("T", &[])); assert_type!(S, ty); } @@ -135,9 +135,11 @@ fn c_like_enum_derive() { B = 10, } - let ty = Type::builder() - .path(Path::new("E", "derive")) - .variant(Variants::fieldless().variant("A", 0u64).variant("B", 10u64)); + let ty = Type::builder().path(Path::new("E", "derive")).variant( + Variants::fieldless() + .variant("A", 0u64, &[]) + .variant("B", 10u64, &[]), + ); assert_type!(E, ty); } @@ -158,11 +160,11 @@ fn c_like_enum_derive_with_scale_index_set() { let ty = Type::builder().path(Path::new("E", "derive")).variant( Variants::fieldless() - .variant("A", 0) - .variant("B", 10) - .variant("C", 13) - .variant("D", 3) - .variant("E", 14), + .variant("A", 0, &[]) + .variant("B", 10, &[]) + .variant("C", 13, &[]) + .variant("D", 3, &[]) + .variant("E", 14, &[]), ); assert_type!(E, ty); @@ -183,9 +185,9 @@ fn enum_derive() { .type_params(tuple_meta_type!(bool)) .variant( Variants::with_fields() - .variant("A", Fields::unnamed().field_of::("T")) - .variant("B", Fields::named().field_of::("b", "T")) - .variant_unit("C"), + .variant("A", Fields::unnamed().field_of::("T", &[]), &[]) + .variant("B", Fields::named().field_of::("b", "T", &[]), &[]) + .variant_unit("C", &[]), ); assert_type!(E, ty); @@ -202,12 +204,17 @@ fn recursive_type_derive() { let ty = Type::builder().path(Path::new("Tree", "derive")).variant( Variants::with_fields() - .variant("Leaf", Fields::named().field_of::("value", "i32")) + .variant( + "Leaf", + Fields::named().field_of::("value", "i32", &[]), + &[], + ) .variant( "Node", Fields::named() - .field_of::>("right", "Box") - .field_of::>("left", "Box"), + .field_of::>("right", "Box", &[]) + .field_of::>("left", "Box", &[]), + &[], ), ); @@ -226,7 +233,7 @@ fn fields_with_type_alias() { let ty = Type::builder() .path(Path::new("S", "derive")) - .composite(Fields::named().field_of::("a", "BoolAlias")); + .composite(Fields::named().field_of::("a", "BoolAlias", &[])); assert_type!(S, ty); } @@ -254,8 +261,8 @@ fn associated_types_derive_without_bounds() { .type_params(tuple_meta_type!(ConcreteTypes)) .composite( Fields::named() - .field_of::("a", "T::A") - .field_of::("b", "&'static u64"), + .field_of::("a", "T::A", &[]) + .field_of::("b", "&'static u64", &[]), ); assert_type!(Assoc, struct_type); @@ -286,10 +293,10 @@ fn associated_types_named_like_the_derived_type_works() { .type_params(tuple_meta_type!(ConcreteTypes)) .composite( Fields::named() - .field_of::>("a", "Vec") - .field_of::>("b", "Vec<::Assoc>") - .field_of::("c", "T::Assoc") - .field_of::("d", "::Assoc"), + .field_of::>("a", "Vec", &[]) + .field_of::>("b", "Vec<::Assoc>", &[]) + .field_of::("c", "T::Assoc", &[]) + .field_of::("d", "::Assoc", &[]), ); assert_type!(Assoc, struct_type); @@ -309,8 +316,8 @@ fn scale_compact_types_work_in_structs() { .path(Path::new("Dense", "derive")) .composite( Fields::named() - .field_of::("a", "u8") - .compact_of::("b", "u16"), + .field_of::("a", "u8", &[]) + .compact_of::("b", "u16", &[]), ); assert_type!(Dense, ty_alt); } @@ -330,11 +337,20 @@ fn scale_compact_types_work_in_enums() { .type_params(tuple_meta_type!(u8, u16)) .variant( Variants::with_fields() - .variant("Id", Fields::unnamed().field_of::("AccountId")) - .variant("Index", Fields::unnamed().compact_of::("AccountIndex")) + .variant( + "Id", + Fields::unnamed().field_of::("AccountId", &[]), + &[], + ) + .variant( + "Index", + Fields::unnamed().compact_of::("AccountIndex", &[]), + &[], + ) .variant( "Address32", - Fields::unnamed().field_of::<[u8; 32]>("[u8; 32]"), + Fields::unnamed().field_of::<[u8; 32]>("[u8; 32]", &[]), + &[], ), ); @@ -356,8 +372,8 @@ fn struct_fields_marked_scale_skip_are_skipped() { .path(Path::new("Skippy", "derive")) .composite( Fields::named() - .field_of::("a", "u8") - .field_of::("c", "u32"), + .field_of::("a", "u8", &[]) + .field_of::("c", "u32", &[]), ); assert_type!(Skippy, ty); } @@ -373,9 +389,11 @@ fn enum_variants_marked_scale_skip_are_skipped() { C, } - let ty = Type::builder() - .path(Path::new("Skippy", "derive")) - .variant(Variants::fieldless().variant("A", 0).variant("C", 2)); + let ty = Type::builder().path(Path::new("Skippy", "derive")).variant( + Variants::fieldless() + .variant("A", 0, &[]) + .variant("C", 2, &[]), + ); assert_type!(Skippy, ty); } @@ -396,8 +414,12 @@ fn enum_variants_with_fields_marked_scale_skip_are_skipped() { let ty = Type::builder().path(Path::new("Skippy", "derive")).variant( Variants::with_fields() - .variant("Bajs", Fields::named().field_of::("b", "bool")) - .variant("Coo", Fields::unnamed().field_of::("bool")), + .variant( + "Bajs", + Fields::named().field_of::("b", "bool", &[]), + &[], + ) + .variant("Coo", Fields::unnamed().field_of::("bool", &[]), &[]), ); assert_type!(Skippy, ty); } @@ -422,7 +444,7 @@ fn type_parameters_with_default_bound_works() { let ty = Type::builder() .path(Path::new("Bat", "derive")) .type_params(tuple_meta_type!(MetaFormy)) - .composite(Fields::named().field_of::("one", "TTT")); + .composite(Fields::named().field_of::("one", "TTT", &[])); assert_type!(Bat, ty); } @@ -435,9 +457,9 @@ fn whitespace_scrubbing_works() { a: (u8, (bool, u8)), } - let ty = Type::builder() - .path(Path::new("A", "derive")) - .composite(Fields::named().field_of::<(u8, (bool, u8))>("a", "(u8, (bool, u8))")); + let ty = Type::builder().path(Path::new("A", "derive")).composite( + Fields::named().field_of::<(u8, (bool, u8))>("a", "(u8, (bool, u8))", &[]), + ); assert_type!(A, ty); } diff --git a/test_suite/tests/json.rs b/test_suite/tests/json.rs index 9ece5fc3..ae971557 100644 --- a/test_suite/tests/json.rs +++ b/test_suite/tests/json.rs @@ -221,10 +221,10 @@ fn test_struct_with_some_fields_marked_as_compact() { .path(Path::new("Dense", module_path!())) .composite( Fields::named() - .compact_of::("a", "u128") - .field_of::("a_not_compact", "u128") - .field_of::<[u8; 32]>("b", "[u8; 32]") - .compact_of::("c", "u64"), + .compact_of::("a", "u128", &[]) + .field_of::("a_not_compact", "u128", &[]) + .field_of::<[u8; 32]>("b", "[u8; 32]", &[]) + .compact_of::("c", "u64", &[]), ) } } From 4e696dce7565df1dab3ae9edc6afc79cf92d6a4f Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 26 Apr 2021 17:41:22 +0100 Subject: [PATCH 32/72] Add docs to derive tests --- test_suite/tests/derive.rs | 48 +++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index 155fafc2..5b8432e0 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -47,7 +47,11 @@ macro_rules! assert_type { fn struct_derive() { #[allow(unused)] #[derive(TypeInfo)] + /// Type docs. + /// Multiline. struct S { + /// Field docs + /// Multiline pub t: T, pub u: U, } @@ -55,9 +59,10 @@ fn struct_derive() { let struct_type = Type::builder() .path(Path::new("S", "derive")) .type_params(tuple_meta_type!(bool, u8)) + .docs(&[" Type docs.", " Multiline."]) .composite( Fields::named() - .field_of::("t", "T", &[]) + .field_of::("t", "T", &[" Field docs", " Multiline"]) .field_of::("u", "U", &[]), ); @@ -103,12 +108,17 @@ fn phantom_data_is_part_of_the_type_info() { fn tuple_struct_derive() { #[allow(unused)] #[derive(TypeInfo)] - struct S(T); + /// Type docs. + struct S( + /// Unnamed field docs. + T + ); let ty = Type::builder() .path(Path::new("S", "derive")) .type_params(tuple_meta_type!(bool)) - .composite(Fields::unnamed().field_of::("T", &[])); + .docs(&[" Type docs."]) + .composite(Fields::unnamed().field_of::("T", &[" Unnamed field docs."])); assert_type!(S, ty); } @@ -130,15 +140,20 @@ fn unit_struct_derive() { fn c_like_enum_derive() { #[allow(unused)] #[derive(TypeInfo)] + /// Enum docs. enum E { + /// Unit variant. A, + /// Variant with discriminator. B = 10, } - let ty = Type::builder().path(Path::new("E", "derive")).variant( + let ty = Type::builder().path(Path::new("E", "derive")) + .docs(&[" Enum docs."]) + .variant( Variants::fieldless() - .variant("A", 0u64, &[]) - .variant("B", 10u64, &[]), + .variant("A", 0u64, &[" Unit variant."]) + .variant("B", 10u64, &[" Variant with discriminator."]), ); assert_type!(E, ty); @@ -174,20 +189,31 @@ fn c_like_enum_derive_with_scale_index_set() { fn enum_derive() { #[allow(unused)] #[derive(TypeInfo)] + /// Enum docs. enum E { - A(T), - B { b: T }, + /// Unnamed fields variant. + A( + /// Unnamed field. + T + ), + /// Named fields variant. + B { + /// Named field. + b: T + }, + /// Unit variant. C, } let ty = Type::builder() .path(Path::new("E", "derive")) .type_params(tuple_meta_type!(bool)) + .docs(&[" Enum docs."]) .variant( Variants::with_fields() - .variant("A", Fields::unnamed().field_of::("T", &[]), &[]) - .variant("B", Fields::named().field_of::("b", "T", &[]), &[]) - .variant_unit("C", &[]), + .variant("A", Fields::unnamed().field_of::("T", &[" Unnamed field."]), &[" Unnamed fields variant."]) + .variant("B", Fields::named().field_of::("b", "T", &[" Named field."]), &[" Named fields variant."]) + .variant_unit("C", &[" Unit variant."]), ); assert_type!(E, ty); From 55fc739ca8b92c585853df3209a4445190510e73 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 26 Apr 2021 17:47:50 +0100 Subject: [PATCH 33/72] Fmt --- test_suite/tests/derive.rs | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index 5b8432e0..5dc84c0e 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -111,7 +111,7 @@ fn tuple_struct_derive() { /// Type docs. struct S( /// Unnamed field docs. - T + T, ); let ty = Type::builder() @@ -148,13 +148,14 @@ fn c_like_enum_derive() { B = 10, } - let ty = Type::builder().path(Path::new("E", "derive")) + let ty = Type::builder() + .path(Path::new("E", "derive")) .docs(&[" Enum docs."]) .variant( - Variants::fieldless() - .variant("A", 0u64, &[" Unit variant."]) - .variant("B", 10u64, &[" Variant with discriminator."]), - ); + Variants::fieldless() + .variant("A", 0u64, &[" Unit variant."]) + .variant("B", 10u64, &[" Variant with discriminator."]), + ); assert_type!(E, ty); } @@ -194,12 +195,12 @@ fn enum_derive() { /// Unnamed fields variant. A( /// Unnamed field. - T + T, ), /// Named fields variant. B { /// Named field. - b: T + b: T, }, /// Unit variant. C, @@ -211,8 +212,16 @@ fn enum_derive() { .docs(&[" Enum docs."]) .variant( Variants::with_fields() - .variant("A", Fields::unnamed().field_of::("T", &[" Unnamed field."]), &[" Unnamed fields variant."]) - .variant("B", Fields::named().field_of::("b", "T", &[" Named field."]), &[" Named fields variant."]) + .variant( + "A", + Fields::unnamed().field_of::("T", &[" Unnamed field."]), + &[" Unnamed fields variant."], + ) + .variant( + "B", + Fields::named().field_of::("b", "T", &[" Named field."]), + &[" Named fields variant."], + ) .variant_unit("C", &[" Unit variant."]), ); From ded2f3faa419a9612f410663a76895d2e50594b8 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 27 Apr 2021 09:24:12 +0100 Subject: [PATCH 34/72] Fmt --- derive/src/utils.rs | 5 ++--- src/build.rs | 37 ++++++++++++++++++++++++++++++------- src/impls.rs | 10 +++++----- src/tests.rs | 10 +++++----- src/ty/fields.rs | 26 +++++++++++++++++++++----- src/ty/mod.rs | 12 ++++++++++-- src/ty/variant.rs | 17 ++++++++++++++--- 7 files changed, 87 insertions(+), 30 deletions(-) diff --git a/derive/src/utils.rs b/derive/src/utils.rs index b19e22d3..7bb8763a 100644 --- a/derive/src/utils.rs +++ b/derive/src/utils.rs @@ -31,7 +31,8 @@ use syn::{ /// Return all doc attributes literals found. pub fn get_doc_literals(attrs: &Vec) -> Vec { - attrs.iter() + attrs + .iter() .filter_map(|attr| { if let Ok(syn::Meta::NameValue(meta)) = attr.parse_meta() { if meta.path.get_ident().map_or(false, |ident| ident == "doc") { @@ -125,5 +126,3 @@ where }) .next() } - - diff --git a/src/build.rs b/src/build.rs index 1b4090c5..a455ef21 100644 --- a/src/build.rs +++ b/src/build.rs @@ -261,16 +261,27 @@ impl FieldsBuilder { impl FieldsBuilder { /// Add a named field with the type of the type parameter `T` - pub fn field_of(mut self, name: &'static str, type_name: &'static str, docs: &[&'static str]) -> Self + pub fn field_of( + mut self, + name: &'static str, + type_name: &'static str, + docs: &[&'static str], + ) -> Self where T: TypeInfo + ?Sized + 'static, { - self.fields.push(Field::named_of::(name, type_name, docs)); + self.fields + .push(Field::named_of::(name, type_name, docs)); self } /// Add a named, [`Compact`] field of type `T`. - pub fn compact_of(mut self, name: &'static str, type_name: &'static str, docs: &[&'static str]) -> Self + pub fn compact_of( + mut self, + name: &'static str, + type_name: &'static str, + docs: &[&'static str], + ) -> Self where T: scale::HasCompact, ::Type: TypeInfo + 'static, @@ -297,7 +308,8 @@ impl FieldsBuilder { T: scale::HasCompact, ::Type: TypeInfo + 'static, { - self.fields.push(Field::compact_of::(None, type_name, docs)); + self.fields + .push(Field::compact_of::(None, type_name, docs)); self } } @@ -335,8 +347,14 @@ pub struct VariantsBuilder { impl VariantsBuilder { /// Add a variant with fields constructed by the supplied [`FieldsBuilder`](`crate::build::FieldsBuilder`) - pub fn variant(mut self, name: &'static str, fields: FieldsBuilder, docs: &[&'static str]) -> Self { - self.variants.push(Variant::with_fields(name, fields, docs.to_vec())); + pub fn variant( + mut self, + name: &'static str, + fields: FieldsBuilder, + docs: &[&'static str], + ) -> Self { + self.variants + .push(Variant::with_fields(name, fields, docs.to_vec())); self } @@ -348,7 +366,12 @@ impl VariantsBuilder { impl VariantsBuilder { /// Add a fieldless variant, explicitly setting the discriminant - pub fn variant(mut self, name: &'static str, discriminant: u64, docs: &[&'static str]) -> Self { + pub fn variant( + mut self, + name: &'static str, + discriminant: u64, + docs: &[&'static str], + ) -> Self { self.variants .push(Variant::with_discriminant(name, discriminant, docs)); self diff --git a/src/impls.rs b/src/impls.rs index 090c737c..59268bde 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -132,11 +132,11 @@ where Type::builder() .path(Path::prelude("Option")) .type_params(tuple_meta_type![T]) - .variant( - Variants::with_fields() - .variant_unit("None", &[]) - .variant("Some", Fields::unnamed().field_of::("T", &[]), &[]), - ) + .variant(Variants::with_fields().variant_unit("None", &[]).variant( + "Some", + Fields::unnamed().field_of::("T", &[]), + &[], + )) } } diff --git a/src/tests.rs b/src/tests.rs index c5724223..de7679e1 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -61,11 +61,11 @@ fn prelude_items() { Type::builder() .path(Path::prelude("Option")) .type_params(tuple_meta_type!(u128)) - .variant( - Variants::with_fields() - .variant_unit("None", &[]) - .variant("Some", Fields::unnamed().field_of::("T", &[]), &[]) - ) + .variant(Variants::with_fields().variant_unit("None", &[]).variant( + "Some", + Fields::unnamed().field_of::("T", &[]), + &[] + )) ); assert_type!( Result, diff --git a/src/ty/fields.rs b/src/ty/fields.rs index 2dfecab9..a31628dc 100644 --- a/src/ty/fields.rs +++ b/src/ty/fields.rs @@ -80,7 +80,10 @@ pub struct Field { /// The name of the type of the field as it appears in the source code. type_name: T::String, /// Documentation - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty", default))] + #[cfg_attr( + feature = "serde", + serde(skip_serializing_if = "Vec::is_empty", default) + )] docs: Vec, } @@ -111,7 +114,7 @@ impl Field { name, ty, type_name, - docs: docs.to_vec() + docs: docs.to_vec(), } } @@ -119,7 +122,11 @@ impl Field { /// /// Use this constructor if you want to instantiate from a given /// compile-time type. - pub fn named_of(name: &'static str, type_name: &'static str, docs: &[&'static str]) -> Field + pub fn named_of( + name: &'static str, + type_name: &'static str, + docs: &[&'static str], + ) -> Field where T: TypeInfo + ?Sized + 'static, { @@ -138,12 +145,21 @@ impl Field { } /// Creates a new [`Compact`] field. - pub fn compact_of(name: Option<&'static str>, type_name: &'static str, docs: &[&'static str]) -> Field + pub fn compact_of( + name: Option<&'static str>, + type_name: &'static str, + docs: &[&'static str], + ) -> Field where T: HasCompact, ::Type: TypeInfo + 'static, { - Self::new(name, MetaType::new::<::Type>(), type_name, docs) + Self::new( + name, + MetaType::new::<::Type>(), + type_name, + docs, + ) } } diff --git a/src/ty/mod.rs b/src/ty/mod.rs index 3a90795a..cf9cc8ba 100644 --- a/src/ty/mod.rs +++ b/src/ty/mod.rs @@ -79,7 +79,10 @@ pub struct Type { #[cfg_attr(feature = "serde", serde(rename = "def"))] type_def: TypeDef, /// Documentation - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty", default))] + #[cfg_attr( + feature = "serde", + serde(skip_serializing_if = "Vec::is_empty", default) + )] docs: Vec, } @@ -121,7 +124,12 @@ impl Type { TypeBuilder::default() } - pub(crate) fn new(path: Path, type_params: I, type_def: D, docs: Vec<&'static str>) -> Self + pub(crate) fn new( + path: Path, + type_params: I, + type_def: D, + docs: Vec<&'static str>, + ) -> Self where I: IntoIterator, D: Into, diff --git a/src/ty/variant.rs b/src/ty/variant.rs index dc8d2a44..3f6fd550 100644 --- a/src/ty/variant.rs +++ b/src/ty/variant.rs @@ -171,7 +171,10 @@ pub struct Variant { )] discriminant: Option, /// Documentation - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty", default))] + #[cfg_attr( + feature = "serde", + serde(skip_serializing_if = "Vec::is_empty", default) + )] docs: Vec, } @@ -190,7 +193,11 @@ impl IntoPortable for Variant { impl Variant { /// Creates a new variant with the given fields. - pub fn with_fields(name: &'static str, fields: FieldsBuilder, docs: Vec<&'static str>) -> Self { + pub fn with_fields( + name: &'static str, + fields: FieldsBuilder, + docs: Vec<&'static str>, + ) -> Self { Self { name, fields: fields.finalize(), @@ -200,7 +207,11 @@ impl Variant { } /// Creates a new variant with the given discriminant. - pub fn with_discriminant(name: &'static str, discriminant: u64, docs: &[&'static str]) -> Self { + pub fn with_discriminant( + name: &'static str, + discriminant: u64, + docs: &[&'static str], + ) -> Self { Self { name, fields: Vec::new(), From 3b78d47f6d6884628c46cab41c5f750b7f092a2b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 27 Apr 2021 09:38:19 +0100 Subject: [PATCH 35/72] Make clippy happy --- derive/src/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/derive/src/utils.rs b/derive/src/utils.rs index 7bb8763a..f7ab6120 100644 --- a/derive/src/utils.rs +++ b/derive/src/utils.rs @@ -30,7 +30,7 @@ use syn::{ }; /// Return all doc attributes literals found. -pub fn get_doc_literals(attrs: &Vec) -> Vec { +pub fn get_doc_literals(attrs: &[syn::Attribute]) -> Vec { attrs .iter() .filter_map(|attr| { From c74422da0cda42f02ac74da387b3e9f98741f274 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 27 Apr 2021 10:47:49 +0100 Subject: [PATCH 36/72] Fix struct docs tests --- test_suite/tests/derive.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index 5dc84c0e..911a197a 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -50,8 +50,7 @@ fn struct_derive() { /// Type docs. /// Multiline. struct S { - /// Field docs - /// Multiline + /// Field docs. pub t: T, pub u: U, } @@ -62,7 +61,7 @@ fn struct_derive() { .docs(&[" Type docs.", " Multiline."]) .composite( Fields::named() - .field_of::("t", "T", &[" Field docs", " Multiline"]) + .field_of::("t", "T", &[" Field docs."]) .field_of::("u", "U", &[]), ); @@ -75,9 +74,10 @@ fn struct_derive() { let self_typed_type = Type::builder() .path(Path::new("S", "derive")) .type_params(tuple_meta_type!(Box>, bool)) + .docs(&[" Type docs.", " Multiline."]) .composite( Fields::named() - .field_of::>>("t", "T", &[]) + .field_of::>>("t", "T", &[" Field docs."]) .field_of::("u", "U", &[]), ); assert_type!(SelfTyped, self_typed_type); From 329d9153c9c794435265d6834688df88d40d312b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 27 Apr 2021 10:48:13 +0100 Subject: [PATCH 37/72] Fix struct docs tests --- test_suite/tests/derive.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index 911a197a..28f4a3b8 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -74,7 +74,11 @@ fn struct_derive() { let self_typed_type = Type::builder() .path(Path::new("S", "derive")) .type_params(tuple_meta_type!(Box>, bool)) - .docs(&[" Type docs.", " Multiline."]) + .docs(&[ + " Type docs.", + " clear\ + Multiline.", + ]) .composite( Fields::named() .field_of::>>("t", "T", &[" Field docs."]) From 637ab5aaf17e0b8974e92d06bd304021ea3e4e8f Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 27 Apr 2021 11:18:47 +0100 Subject: [PATCH 38/72] Add missing Vec import --- src/ty/fields.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ty/fields.rs b/src/ty/fields.rs index a31628dc..685f96b0 100644 --- a/src/ty/fields.rs +++ b/src/ty/fields.rs @@ -18,6 +18,7 @@ use crate::{ MetaForm, PortableForm, }, + prelude::vec::Vec, IntoPortable, MetaType, Registry, From efdd3e48ac72eaaf180ab3613a357dd5c7385e15 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 27 Apr 2021 11:26:23 +0100 Subject: [PATCH 39/72] Fix test --- test_suite/tests/derive.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index 28f4a3b8..911a197a 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -74,11 +74,7 @@ fn struct_derive() { let self_typed_type = Type::builder() .path(Path::new("S", "derive")) .type_params(tuple_meta_type!(Box>, bool)) - .docs(&[ - " Type docs.", - " clear\ - Multiline.", - ]) + .docs(&[" Type docs.", " Multiline."]) .composite( Fields::named() .field_of::>>("t", "T", &[" Field docs."]) From 77fc88a6189c89e5b3212ed128534fb020c2149f Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 27 Apr 2021 12:14:58 +0100 Subject: [PATCH 40/72] Clear docs --- src/registry.rs | 129 +++++++++++++++++++++++++++++++++++++++++++- src/ty/composite.rs | 7 +++ src/ty/fields.rs | 5 ++ src/ty/mod.rs | 17 ++++++ src/ty/variant.rs | 15 ++++++ 5 files changed, 172 insertions(+), 1 deletion(-) diff --git a/src/registry.rs b/src/registry.rs index 25830d8f..f242fbed 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -189,13 +189,25 @@ impl PortableRegistry { (id, ty) }) } + + /// Clears all docs from types. + /// + /// Use when the docs are not required to produce smaller encoded metadata. + pub fn clear_docs(&mut self) { + for ty in &mut self.types { + ty.clear_docs() + } + } } #[cfg(test)] mod tests { use super::*; use crate::{ - build::Fields, + build::{ + Fields, + Variants, + }, meta_type, Path, TypeDef, @@ -268,4 +280,119 @@ mod tests { panic!("Should be a composite type definition") } } + + #[test] + fn clear_docs() { + #[allow(unused)] + /// docs + struct S { + /// docs + pub t: bool, + pub u: u8, + } + + impl TypeInfo for S { + type Identity = Self; + + fn type_info() -> Type { + Type::builder() + .path(Path::new("S", module_path!())) + .docs(&[" docs"]) + .composite( + Fields::named() + .field_of::("t", "bool", &[" docs"]) + .field_of::("u", "u8", &[]), + ) + } + } + + #[allow(unused)] + struct T( + /// docs + u32, + ); + + impl TypeInfo for T { + type Identity = Self; + + fn type_info() -> Type { + Type::builder() + .path(Path::new("T", module_path!())) + .docs(&[" docs"]) + .composite(Fields::unnamed().field_of::("u32", &[" docs"])) + } + } + + #[allow(unused)] + /// docs + enum E { + /// docs + A( + /// docs + bool, + ), + /// docs + B { + /// docs + b: u8, + }, + /// docs + C, + } + + impl TypeInfo for E { + type Identity = Self; + + fn type_info() -> Type { + Type::builder() + .path(Path::new("E", "derive")) + .type_params(tuple_meta_type!(bool)) + .docs(&[" Enum docs."]) + .variant( + Variants::with_fields() + .variant( + "A", + Fields::unnamed().field_of::("bool", &[" docs"]), + &[" Unnamed fields variant."], + ) + .variant( + "B", + Fields::named().field_of::("b", "u8", &[" docs"]), + &[" docs"], + ) + .variant_unit("C", &[" docs"]), + ) + } + } + + let mut registry = Registry::new(); + registry.register_type(&meta_type::()); + registry.register_type(&meta_type::()); + registry.register_type(&meta_type::()); + + let mut registry: PortableRegistry = registry.into(); + + registry.clear_docs(); + + for ty in registry.types { + assert!(ty.docs().is_empty()); + match ty.type_def() { + TypeDef::Composite(c) => { + for f in c.fields() { + assert!(f.docs().is_empty()) + } + } + TypeDef::Variant(v) => { + for var in v.variants() { + assert!(var.docs().is_empty()); + + for f in var.fields() { + assert!(f.docs().is_empty()) + } + } + } + _ => {} + } + } + } } diff --git a/src/ty/composite.rs b/src/ty/composite.rs index 769c58b8..60cb3ae7 100644 --- a/src/ty/composite.rs +++ b/src/ty/composite.rs @@ -109,4 +109,11 @@ where pub fn fields(&self) -> &[Field] { &self.fields } + + /// Clear the docs of the field. + pub fn clear_docs(&mut self) { + for field in &mut self.fields { + field.clear_docs() + } + } } diff --git a/src/ty/fields.rs b/src/ty/fields.rs index 685f96b0..a64b4992 100644 --- a/src/ty/fields.rs +++ b/src/ty/fields.rs @@ -191,4 +191,9 @@ where pub fn docs(&self) -> &[T::String] { &self.docs } + + /// Clear the docs of the field. + pub fn clear_docs(&mut self) { + self.docs.clear() + } } diff --git a/src/ty/mod.rs b/src/ty/mod.rs index cf9cc8ba..400db24c 100644 --- a/src/ty/mod.rs +++ b/src/ty/mod.rs @@ -86,6 +86,23 @@ pub struct Type { docs: Vec, } +impl Type { + /// Clear docs from this type. + pub fn clear_docs(&mut self) { + self.docs.clear(); + match &mut self.type_def { + TypeDef::Composite(composite) => composite.clear_docs(), + TypeDef::Variant(variant) => variant.clear_docs(), + TypeDef::Sequence(_) => {} + TypeDef::Array(_) => {} + TypeDef::Tuple(_) => {} + TypeDef::Primitive(_) => {} + TypeDef::Compact(_) => {} + TypeDef::Phantom(_) => {} + } + } +} + impl IntoPortable for Type { type Output = Type; diff --git a/src/ty/variant.rs b/src/ty/variant.rs index 3f6fd550..5a78c4d9 100644 --- a/src/ty/variant.rs +++ b/src/ty/variant.rs @@ -122,6 +122,13 @@ where pub fn variants(&self) -> &[Variant] { &self.variants } + + /// Clear docs for all variants. + pub fn clear_docs(&mut self) { + for variant in &mut self.variants { + variant.clear_docs() + } + } } /// A struct enum variant with either named (struct) or unnamed (tuple struct) @@ -244,4 +251,12 @@ where pub fn docs(&self) -> &[T::String] { &self.docs } + + /// Clear the docs for this variant. + pub fn clear_docs(&mut self) { + self.docs.clear(); + for field in &mut self.fields { + field.clear_docs() + } + } } From f06b059e443e0bbefb0677ac819bd592131c76fa Mon Sep 17 00:00:00 2001 From: David Palm Date: Sat, 1 May 2021 15:07:43 +0200 Subject: [PATCH 41/72] Cleanup --- test_suite/tests/derive.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index 6b51e0ce..d9b55ebb 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -21,7 +21,6 @@ use scale_info::{ prelude::{ boxed::Box, marker::PhantomData, - vec, vec::Vec, }, tuple_meta_type, From d15566fd97fd029047daad75bca120cbd86f625d Mon Sep 17 00:00:00 2001 From: David Palm Date: Thu, 6 May 2021 15:21:36 +0200 Subject: [PATCH 42/72] Random change to kick CI in the butt --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 86a24411..8ac3a455 100644 --- a/README.md +++ b/README.md @@ -54,8 +54,7 @@ pub enum TypeDef { The following "built-in" types have predefined `TypeInfo` definitions: -- **Primitives:** `bool`, `char`, `str`, `u8`, `u16`, `u32`, `u64`, `u128`, `i8`, `i16`, `i32`, `i64 -`, `i128`. +- **Primitives:** `bool`, `char`, `str`, `u8`, `u16`, `u32`, `u64`, `u128`, `i8`, `i16`, `i32`, `i64`, `i128`. - **Sequence:** Variable size sequence of elements of `T`, where `T` implements `TypeInfo`. e.g. `[T]`, `&[T]`, `&mut [T]`, `Vec` @@ -234,7 +233,7 @@ struct Foo { #[codec(compact)] a: S } You may experience the following error when using this generic type without the correct bounds: -``` +```sh error[E0275]: overflow evaluating the requirement `_::_parity_scale_codec::Compact<_>: Decode` ``` From 0d4d12606694f46495aad31eb3c09499c9cc3e50 Mon Sep 17 00:00:00 2001 From: David Palm Date: Thu, 6 May 2021 15:29:15 +0200 Subject: [PATCH 43/72] Fix(?) trybuild --- .../ui/fail_with_invalid_codec_attrs.stderr | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test_suite/tests/ui/fail_with_invalid_codec_attrs.stderr b/test_suite/tests/ui/fail_with_invalid_codec_attrs.stderr index 2fa7f609..96a1a344 100644 --- a/test_suite/tests/ui/fail_with_invalid_codec_attrs.stderr +++ b/test_suite/tests/ui/fail_with_invalid_codec_attrs.stderr @@ -10,6 +10,12 @@ error: Invalid attribute on field, only `#[codec(skip)]`, `#[codec(compact)]` an 13 | Thing(#[codec(index = 3)] u32), | ^^^^^^^^^ +error: expected literal + --> $DIR/fail_with_invalid_codec_attrs.rs:18:21 + | +18 | #[codec(index = a)] + | ^ + error: proc-macro derive panicked --> $DIR/fail_with_invalid_codec_attrs.rs:16:18 | @@ -19,10 +25,10 @@ error: proc-macro derive panicked = help: message: scale-info: Bad index in `#[codec(index = …)]`, see `parity-scale-codec` error: Error("expected literal") error: expected literal - --> $DIR/fail_with_invalid_codec_attrs.rs:18:21 + --> $DIR/fail_with_invalid_codec_attrs.rs:24:25 | -18 | #[codec(index = a)] - | ^ +24 | #[codec(encode_as = u8, compact)] + | ^^ error: proc-macro derive panicked --> $DIR/fail_with_invalid_codec_attrs.rs:22:18 @@ -31,9 +37,3 @@ error: proc-macro derive panicked | ^^^^^^^^ | = help: message: scale-info: Bad index in `#[codec(index = …)]`, see `parity-scale-codec` error: Error("expected literal") - -error: expected literal - --> $DIR/fail_with_invalid_codec_attrs.rs:24:25 - | -24 | #[codec(encode_as = u8, compact)] - | ^^ From 4151589ad76f13a0ea3c60547522797b01eea613 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 25 May 2021 12:23:29 +0100 Subject: [PATCH 44/72] Promote build to it's own mod, split fields and variant builders --- src/build/fields.rs | 128 ++++++++++++++++++++++ src/{build.rs => build/mod.rs} | 192 ++------------------------------- src/build/variant.rs | 116 ++++++++++++++++++++ 3 files changed, 250 insertions(+), 186 deletions(-) create mode 100644 src/build/fields.rs rename src/{build.rs => build/mod.rs} (53%) create mode 100644 src/build/variant.rs diff --git a/src/build/fields.rs b/src/build/fields.rs new file mode 100644 index 00000000..d0eb7040 --- /dev/null +++ b/src/build/fields.rs @@ -0,0 +1,128 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::prelude::{ + marker::PhantomData, + vec::Vec, +}; + +use crate::{ + Field, + TypeInfo, + form::MetaForm, +}; + +/// A fields builder has no fields (e.g. a unit struct) +pub enum NoFields {} +/// A fields builder only allows named fields (e.g. a struct) +pub enum NamedFields {} +/// A fields builder only allows unnamed fields (e.g. a tuple) +pub enum UnnamedFields {} + +/// Provides FieldsBuilder constructors +pub enum Fields {} + +impl Fields { + /// The type construct has no fields + pub fn unit() -> FieldsBuilder { + FieldsBuilder::::default() + } + + /// Fields for a type construct with named fields + pub fn named() -> FieldsBuilder { + FieldsBuilder::default() + } + + /// Fields for a type construct with unnamed fields + pub fn unnamed() -> FieldsBuilder { + FieldsBuilder::default() + } +} + +/// 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, + marker: PhantomData T>, +} + +impl Default for FieldsBuilder { + fn default() -> Self { + Self { + fields: Vec::new(), + marker: Default::default(), + } + } +} + +impl FieldsBuilder { + /// Complete building and return the set of fields + pub fn finalize(self) -> Vec> { + self.fields + } +} + +impl FieldsBuilder { + /// Add a named field with the type of the type parameter `T` + pub fn field_of( + mut self, + name: &'static str, + type_name: &'static str, + docs: &[&'static str], + ) -> Self + where + T: TypeInfo + ?Sized + 'static, + { + self.fields + .push(Field::named_of::(name, type_name, docs)); + self + } + + /// Add a named, [`Compact`] field of type `T`. + pub fn compact_of( + mut self, + name: &'static str, + type_name: &'static str, + docs: &[&'static str], + ) -> Self + where + T: scale::HasCompact, + ::Type: TypeInfo + 'static, + { + self.fields + .push(Field::compact_of::(Some(name), type_name, docs)); + self + } +} + +impl FieldsBuilder { + /// Add an unnamed field with the type of the type parameter `T` + pub fn field_of(mut self, type_name: &'static str, docs: &[&'static str]) -> Self + where + T: TypeInfo + ?Sized + 'static, + { + self.fields.push(Field::unnamed_of::(type_name, docs)); + self + } + + /// Add an unnamed, [`Compact`] field of type `T`. + pub fn compact_of(mut self, type_name: &'static str, docs: &[&'static str]) -> Self + where + T: scale::HasCompact, + ::Type: TypeInfo + 'static, + { + self.fields + .push(Field::compact_of::(None, type_name, docs)); + self + } +} \ No newline at end of file diff --git a/src/build.rs b/src/build/mod.rs similarity index 53% rename from src/build.rs rename to src/build/mod.rs index a455ef21..2072dd10 100644 --- a/src/build.rs +++ b/src/build/mod.rs @@ -116,22 +116,23 @@ //! } //! ``` +mod fields; +mod variant; + +pub use self::fields::*; +pub use self::variant::*; + use crate::prelude::{ marker::PhantomData, vec::Vec, }; use crate::{ - form::MetaForm, - Field, MetaType, Path, Type, TypeDef, TypeDefComposite, - TypeDefVariant, - TypeInfo, - Variant, }; /// State types for type builders which require a Path @@ -209,184 +210,3 @@ impl TypeBuilder { self } } - -/// A fields builder has no fields (e.g. a unit struct) -pub enum NoFields {} -/// A fields builder only allows named fields (e.g. a struct) -pub enum NamedFields {} -/// A fields builder only allows unnamed fields (e.g. a tuple) -pub enum UnnamedFields {} - -/// Provides FieldsBuilder constructors -pub enum Fields {} - -impl Fields { - /// The type construct has no fields - pub fn unit() -> FieldsBuilder { - FieldsBuilder::::default() - } - - /// Fields for a type construct with named fields - pub fn named() -> FieldsBuilder { - FieldsBuilder::default() - } - - /// Fields for a type construct with unnamed fields - pub fn unnamed() -> FieldsBuilder { - FieldsBuilder::default() - } -} - -/// 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, - marker: PhantomData T>, -} - -impl Default for FieldsBuilder { - fn default() -> Self { - Self { - fields: Vec::new(), - marker: Default::default(), - } - } -} - -impl FieldsBuilder { - /// Complete building and return the set of fields - pub fn finalize(self) -> Vec> { - self.fields - } -} - -impl FieldsBuilder { - /// Add a named field with the type of the type parameter `T` - pub fn field_of( - mut self, - name: &'static str, - type_name: &'static str, - docs: &[&'static str], - ) -> Self - where - T: TypeInfo + ?Sized + 'static, - { - self.fields - .push(Field::named_of::(name, type_name, docs)); - self - } - - /// Add a named, [`Compact`] field of type `T`. - pub fn compact_of( - mut self, - name: &'static str, - type_name: &'static str, - docs: &[&'static str], - ) -> Self - where - T: scale::HasCompact, - ::Type: TypeInfo + 'static, - { - self.fields - .push(Field::compact_of::(Some(name), type_name, docs)); - self - } -} - -impl FieldsBuilder { - /// Add an unnamed field with the type of the type parameter `T` - pub fn field_of(mut self, type_name: &'static str, docs: &[&'static str]) -> Self - where - T: TypeInfo + ?Sized + 'static, - { - self.fields.push(Field::unnamed_of::(type_name, docs)); - self - } - - /// Add an unnamed, [`Compact`] field of type `T`. - pub fn compact_of(mut self, type_name: &'static str, docs: &[&'static str]) -> Self - where - T: scale::HasCompact, - ::Type: TypeInfo + 'static, - { - self.fields - .push(Field::compact_of::(None, type_name, docs)); - self - } -} - -/// Build a type with no variants. -pub enum NoVariants {} -/// Build a type where at least one variant has fields. -pub enum VariantFields {} -/// Build a type where *all* variants have no fields and the discriminant can -/// be directly chosen or accessed -pub enum Fieldless {} - -/// Empty enum for VariantsBuilder constructors for the type builder DSL. -pub enum Variants {} - -impl Variants { - /// Build a set of variants, at least one of which will have fields. - pub fn with_fields() -> VariantsBuilder { - VariantsBuilder::new() - } - - /// Build a set of variants, none of which will have fields, and the discriminant can - /// be directly chosen or accessed - pub fn fieldless() -> VariantsBuilder { - VariantsBuilder::new() - } -} - -/// Builds a definition of a variant type i.e an `enum` -#[derive(Default)] -pub struct VariantsBuilder { - variants: Vec, - marker: PhantomData T>, -} - -impl VariantsBuilder { - /// Add a variant with fields constructed by the supplied [`FieldsBuilder`](`crate::build::FieldsBuilder`) - pub fn variant( - mut self, - name: &'static str, - fields: FieldsBuilder, - docs: &[&'static str], - ) -> Self { - self.variants - .push(Variant::with_fields(name, fields, docs.to_vec())); - self - } - - /// Add a variant with no fields i.e. a unit variant - pub fn variant_unit(self, name: &'static str, docs: &[&'static str]) -> Self { - self.variant::(name, Fields::unit(), docs) - } -} - -impl VariantsBuilder { - /// Add a fieldless variant, explicitly setting the discriminant - pub fn variant( - mut self, - name: &'static str, - discriminant: u64, - docs: &[&'static str], - ) -> Self { - self.variants - .push(Variant::with_discriminant(name, discriminant, docs)); - self - } -} - -impl VariantsBuilder { - fn new() -> Self { - VariantsBuilder { - variants: Vec::new(), - marker: Default::default(), - } - } - - fn finalize(self) -> TypeDefVariant { - TypeDefVariant::new(self.variants) - } -} diff --git a/src/build/variant.rs b/src/build/variant.rs new file mode 100644 index 00000000..473fd592 --- /dev/null +++ b/src/build/variant.rs @@ -0,0 +1,116 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::prelude::{ + marker::PhantomData, + vec::Vec, +}; + +use crate::{ + TypeDefVariant, + Variant, +}; + +use super::*; + +/// Build a type with no variants. +pub enum NoVariants {} +/// Build a type where at least one variant has fields. +pub enum VariantFields {} +/// Build a type where *all* variants have no fields and the discriminant can +/// be directly chosen or accessed +pub enum Fieldless {} + +/// Empty enum for VariantsBuilder constructors for the type builder DSL. +pub enum Variants {} + +impl Variants { + /// Build a set of variants, at least one of which will have fields. + pub fn with_fields() -> VariantsBuilder { + VariantsBuilder::new() + } + + /// Build a set of variants, none of which will have fields, and the discriminant can + /// be directly chosen or accessed + pub fn fieldless() -> VariantsBuilder { + VariantsBuilder::new() + } +} + +/// Builds a definition of a variant type i.e an `enum` +#[derive(Default)] +pub struct VariantsBuilder { + variants: Vec, + marker: PhantomData T>, +} + +impl VariantsBuilder { + /// Add a variant with fields constructed by the supplied [`FieldsBuilder`](`crate::build::FieldsBuilder`) + pub fn variant( + mut self, + name: &'static str, + fields: FieldsBuilder, + docs: &[&'static str], + ) -> Self { + self.variants + .push(Variant::with_fields(name, fields, docs.to_vec())); + self + } + + /// Add a variant with no fields i.e. a unit variant + pub fn variant_unit(self, name: &'static str, docs: &[&'static str]) -> Self { + self.variant::(name, Fields::unit(), docs) + } +} + +impl VariantsBuilder { + /// Add a fieldless variant, explicitly setting the discriminant + pub fn variant( + mut self, + name: &'static str, + discriminant: u64, + docs: &[&'static str], + ) -> Self { + self.variants + .push(Variant::with_discriminant(name, discriminant, docs)); + self + } +} + +impl VariantsBuilder { + fn new() -> Self { + VariantsBuilder { + variants: Vec::new(), + marker: Default::default(), + } + } + + /// Construct a new [`TypeDefVariant`] from the initialized builder variants. + pub fn finalize(self) -> TypeDefVariant { + TypeDefVariant::new(self.variants) + } +} + +// pub struct VariantBuilder { +// name: &'static str, +// fields: Option>, +// discriminant: Option, +// docs: Vec<&'static str>, +// } +// +// impl VariantBuilder { +// pub fn new(name: &'static str) -> Self { +// Self { name, fields: None, discriminant: None, docs: Vec::new() } +// } +// } \ No newline at end of file From a0743b0af9186914122862ea6b2786c0b441fa69 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 25 May 2021 16:42:58 +0100 Subject: [PATCH 45/72] Refactor variant construction with builder --- src/build/mod.rs | 2 +- src/build/variant.rs | 123 +++++++++++++++++-------------------------- src/impls.rs | 26 ++++++--- src/registry.rs | 23 +++++--- src/tests.rs | 27 +++++++--- src/ty/variant.rs | 51 ++++++++---------- 6 files changed, 124 insertions(+), 128 deletions(-) diff --git a/src/build/mod.rs b/src/build/mod.rs index 2072dd10..33b09273 100644 --- a/src/build/mod.rs +++ b/src/build/mod.rs @@ -184,7 +184,7 @@ impl TypeBuilder { } /// Construct a "variant" type i.e an `enum` - pub fn variant(self, builder: VariantsBuilder) -> Type { + pub fn variant(self, builder: Variants) -> Type { self.build(builder.finalize()) } diff --git a/src/build/variant.rs b/src/build/variant.rs index 473fd592..dee074ad 100644 --- a/src/build/variant.rs +++ b/src/build/variant.rs @@ -12,105 +12,80 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::prelude::{ - marker::PhantomData, - vec::Vec, -}; +use crate::prelude::vec::Vec; use crate::{ + form::MetaForm, + Field, TypeDefVariant, Variant, }; use super::*; -/// Build a type with no variants. -pub enum NoVariants {} -/// Build a type where at least one variant has fields. -pub enum VariantFields {} -/// Build a type where *all* variants have no fields and the discriminant can -/// be directly chosen or accessed -pub enum Fieldless {} - -/// Empty enum for VariantsBuilder constructors for the type builder DSL. -pub enum Variants {} - -impl Variants { - /// Build a set of variants, at least one of which will have fields. - pub fn with_fields() -> VariantsBuilder { - VariantsBuilder::new() - } - - /// Build a set of variants, none of which will have fields, and the discriminant can - /// be directly chosen or accessed - pub fn fieldless() -> VariantsBuilder { - VariantsBuilder::new() - } -} - /// Builds a definition of a variant type i.e an `enum` #[derive(Default)] -pub struct VariantsBuilder { +pub struct Variants { variants: Vec, - marker: PhantomData T>, } -impl VariantsBuilder { - /// Add a variant with fields constructed by the supplied [`FieldsBuilder`](`crate::build::FieldsBuilder`) - pub fn variant( +impl Variants { + /// Create a new [`VariantsBuilder`]. + pub fn new() -> Self { + Variants { + variants: Vec::new(), + } + } + + /// Add a variant with the + pub fn variant( mut self, - name: &'static str, - fields: FieldsBuilder, - docs: &[&'static str], + builder: VariantBuilder, ) -> Self { - self.variants - .push(Variant::with_fields(name, fields, docs.to_vec())); + self.variants.push(builder.finalize()); self } - /// Add a variant with no fields i.e. a unit variant - pub fn variant_unit(self, name: &'static str, docs: &[&'static str]) -> Self { - self.variant::(name, Fields::unit(), docs) + /// Construct a new [`TypeDefVariant`] from the initialized builder variants. + pub fn finalize(self) -> TypeDefVariant { + TypeDefVariant::new(self.variants) } } -impl VariantsBuilder { - /// Add a fieldless variant, explicitly setting the discriminant - pub fn variant( - mut self, - name: &'static str, - discriminant: u64, - docs: &[&'static str], - ) -> Self { - self.variants - .push(Variant::with_discriminant(name, discriminant, docs)); +/// Build a [`Variant`]. +pub struct VariantBuilder { + name: &'static str, + fields: Vec>, + index: Option, + docs: Vec<&'static str>, +} + +impl VariantBuilder { + /// Create a new [`VariantBuilder`]. + pub fn new(name: &'static str) -> Self { + Self { name, fields: Vec::new(), index: None, docs: Vec::new() } + } + + /// Initialize the variant's index. + pub fn index(mut self, index: u64) -> Self { + self.index = Some(index); self } -} -impl VariantsBuilder { - fn new() -> Self { - VariantsBuilder { - variants: Vec::new(), - marker: Default::default(), - } + /// Initialize the variant's fields. + pub fn fields(mut self, fields_builder: FieldsBuilder) -> Self { + self.fields = fields_builder.finalize(); + self } - /// Construct a new [`TypeDefVariant`] from the initialized builder variants. - pub fn finalize(self) -> TypeDefVariant { - TypeDefVariant::new(self.variants) + /// Initialize the variant's documentation. + pub fn docs(mut self, docs: &[&'static str]) -> Self { + self.docs = docs.to_vec(); + self } -} -// pub struct VariantBuilder { -// name: &'static str, -// fields: Option>, -// discriminant: Option, -// docs: Vec<&'static str>, -// } -// -// impl VariantBuilder { -// pub fn new(name: &'static str) -> Self { -// Self { name, fields: None, discriminant: None, docs: Vec::new() } -// } -// } \ No newline at end of file + /// Complete building and create final [`Variant`] instance. + pub fn finalize(self) -> Variant { + Variant::new(self.name, self.fields, self.index, self.docs) + } +} \ No newline at end of file diff --git a/src/impls.rs b/src/impls.rs index 1ea5f6be..7a9d9d85 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -39,6 +39,7 @@ use crate::{ TypeDefSequence, TypeDefTuple, TypeInfo, + Variant, }; macro_rules! impl_metadata_for_primitives { @@ -136,11 +137,16 @@ where Type::builder() .path(Path::prelude("Option")) .type_params(tuple_meta_type![T]) - .variant(Variants::with_fields().variant_unit("None", &[]).variant( - "Some", - Fields::unnamed().field_of::("T", &[]), - &[], - )) + .variant( + Variants::new() + .variant( + Variant::builder("None") + ) + .variant( + Variant::builder("Some") + .fields(Fields::unnamed().field_of::("T", &[])) + ) + ) } } @@ -156,9 +162,13 @@ where .path(Path::prelude("Result")) .type_params(tuple_meta_type!(T, E)) .variant( - Variants::with_fields() - .variant("Ok", Fields::unnamed().field_of::("T", &[]), &[]) - .variant("Err", Fields::unnamed().field_of::("E", &[]), &[]), + Variants::new() + .variant(Variant::builder("Ok") + .fields(Fields::unnamed().field_of::("T", &[])) + ) + .variant(Variant::builder("Err") + .fields(Fields::unnamed().field_of::("E", &[])) + ) ) } } diff --git a/src/registry.rs b/src/registry.rs index 36d74733..a951804f 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -211,6 +211,7 @@ mod tests { Path, TypeDef, TypeInfo, + ty::Variant, }; #[test] @@ -348,18 +349,24 @@ mod tests { .type_params(tuple_meta_type!(bool)) .docs(&[" Enum docs."]) .variant( - Variants::with_fields() + Variants::new() .variant( - "A", - Fields::unnamed().field_of::("bool", &[" docs"]), - &[" Unnamed fields variant."], + Variant::builder("A") + .fields( + Fields::unnamed().field_of::("bool", &[" docs"]) + ) + .docs(&[" Unnamed fields variant."]) ) .variant( - "B", - Fields::named().field_of::("b", "u8", &[" docs"]), - &[" docs"], + Variant::builder("B") + .fields( + Fields::named().field_of::("b", "u8", &[" docs"]) + ) + .docs(&[" docs"]) ) - .variant_unit("C", &[" docs"]), + .variant( + Variant::builder("C").docs(&[" docs"]) + ), ) } } diff --git a/src/tests.rs b/src/tests.rs index de7679e1..eb335b67 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -61,11 +61,16 @@ fn prelude_items() { Type::builder() .path(Path::prelude("Option")) .type_params(tuple_meta_type!(u128)) - .variant(Variants::with_fields().variant_unit("None", &[]).variant( - "Some", - Fields::unnamed().field_of::("T", &[]), - &[] - )) + .variant( + Variants::new() + .variant( + Variant::builder("None") + ) + .variant( + Variant::builder("Some") + .fields(Fields::unnamed().field_of::("T", &[])) + ) + ) ); assert_type!( Result, @@ -73,9 +78,15 @@ fn prelude_items() { .path(Path::prelude("Result")) .type_params(tuple_meta_type!(bool, String)) .variant( - Variants::with_fields() - .variant("Ok", Fields::unnamed().field_of::("T", &[]), &[]) - .variant("Err", Fields::unnamed().field_of::("E", &[]), &[]) + Variants::new() + .variant( + Variant::builder("Ok") + .fields(Fields::unnamed().field_of::("T", &[])) + ) + .variant( + Variant::builder("Err") + .fields(Fields::unnamed().field_of::("E", &[])) + ) ) ); assert_type!(PhantomData, TypeDefPhantom::new(meta_type::())); diff --git a/src/ty/variant.rs b/src/ty/variant.rs index 5a78c4d9..3d13f8c3 100644 --- a/src/ty/variant.rs +++ b/src/ty/variant.rs @@ -15,7 +15,7 @@ use crate::prelude::vec::Vec; use crate::{ - build::FieldsBuilder, + build::VariantBuilder, form::{ Form, MetaForm, @@ -165,18 +165,19 @@ pub struct Variant { serde(skip_serializing_if = "Vec::is_empty", default) )] fields: Vec>, - /// The discriminant of the variant. + /// The index of the variant. /// /// # Note /// - /// Even though setting the discriminant is optional - /// every C-like enum variant has a discriminant specified - /// upon compile-time. + /// In order of precedence: + /// - The index specified by the `#[codec(index = $int)]` attribute. + /// - The explicit discriminant in a "C-like" enum.l + /// - The position the variant appears in an enum definition. #[cfg_attr( feature = "serde", serde(skip_serializing_if = "Option::is_none", default) )] - discriminant: Option, + index: Option, /// Documentation #[cfg_attr( feature = "serde", @@ -192,38 +193,30 @@ impl IntoPortable for Variant { Variant { name: self.name.into_portable(registry), fields: registry.map_into_portable(self.fields), - discriminant: self.discriminant, + index: self.index, docs: registry.map_into_portable(self.docs), } } } impl Variant { - /// Creates a new variant with the given fields. - pub fn with_fields( - name: &'static str, - fields: FieldsBuilder, - docs: Vec<&'static str>, - ) -> Self { - Self { - name, - fields: fields.finalize(), - discriminant: None, - docs: docs.to_vec(), - } + /// Creates a [`VariantBuilder`] for a new variant. + pub fn builder(name: &'static str) -> VariantBuilder { + VariantBuilder::new(name) } - /// Creates a new variant with the given discriminant. - pub fn with_discriminant( + /// Creates a new variant. + pub(crate) fn new( name: &'static str, - discriminant: u64, - docs: &[&'static str], + fields: Vec>, + index: Option, + docs: Vec<&'static str>, ) -> Self { Self { name, - fields: Vec::new(), - discriminant: Some(discriminant), - docs: docs.to_vec(), + fields, + index, + docs, } } } @@ -242,9 +235,9 @@ where &self.fields } - /// Returns the discriminant of the variant. - pub fn discriminant(&self) -> Option { - self.discriminant + /// Returns the index of the variant. + pub fn index(&self) -> Option { + self.index } /// Returns the documentation of the variant. From fd6f89367949c73223f07a371ad94578af3fe3b1 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 25 May 2021 17:36:10 +0100 Subject: [PATCH 46/72] Fix up derive and unit tests with Variant builder --- derive/src/lib.rs | 57 +++++++++++--------- src/build/mod.rs | 2 +- test_suite/tests/derive.rs | 105 +++++++++++++++++++++---------------- test_suite/tests/json.rs | 12 ++--- 4 files changed, 97 insertions(+), 79 deletions(-) diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 28e63c08..d9771dfe 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -220,12 +220,16 @@ fn generate_c_like_enum_def(variants: &VariantList, scale_info: &Ident) -> Token let discriminant = utils::variant_index(v, i); let docs = utils::get_doc_literals(&v.attrs); quote! { - .variant(stringify!(#name), #discriminant as u64, &[ #( #docs ),* ]) + .variant( + :: #scale_info ::Variant::builder(stringify!(#name)) + .index(#discriminant as u64) + .docs(&[ #( #docs ),* ]) + ) } }); quote! { variant( - :: #scale_info ::build::Variants::fieldless() + :: #scale_info ::build::Variants::new() #( #variants )* ) } @@ -253,39 +257,40 @@ fn generate_variant_type(data_enum: &DataEnum, scale_info: &Ident) -> TokenStrea let v_name = quote! {stringify!(#ident) }; let docs = utils::get_doc_literals(&v.attrs); - match v.fields { - Fields::Named(ref fs) => { - let fields = generate_fields(&fs.named); - quote! { - .variant( - #v_name, + let fields = + match v.fields { + Fields::Named(ref fs) => { + let fields = generate_fields(&fs.named); + quote! { :: #scale_info::build::Fields::named() - #( #fields )*, - &[ #( #docs ),* ] - ) + #( #fields )* + } } - } - Fields::Unnamed(ref fs) => { - let fields = generate_fields(&fs.unnamed); - quote! { - .variant( - #v_name, + Fields::Unnamed(ref fs) => { + let fields = generate_fields(&fs.unnamed); + quote! { :: #scale_info::build::Fields::unnamed() - #( #fields )*, - &[ #( #docs ),* ] - ) + #( #fields )* + } } - } - Fields::Unit => { - quote! { - .variant_unit(#v_name, &[ #( #docs ),* ]) + Fields::Unit => { + quote! { + :: #scale_info::build::Fields::unit() + } } - } + }; + + quote! { + .variant( + :: #scale_info::Variant::builder(#v_name) + .fields(#fields) + .docs(&[ #( #docs ),* ]) + ) } }); quote! { variant( - :: #scale_info ::build::Variants::with_fields() + :: #scale_info ::build::Variants::new() #( #variants )* ) } diff --git a/src/build/mod.rs b/src/build/mod.rs index 33b09273..f3aef23f 100644 --- a/src/build/mod.rs +++ b/src/build/mod.rs @@ -83,7 +83,7 @@ //! .path(Path::new("Foo", module_path!())) //! .type_params(vec![MetaType::new::()]) //! .variant( -//! Variants::with_fields() +//! Variants::new() //! .variant("A", Fields::unnamed().field_of::("T", &[]), &[]) //! .variant("B", Fields::named().field_of::("f", "u32", &[]), &[]) //! .variant("C", Fields::unit(), &[]), diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index 911a197a..d1043bc7 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -27,6 +27,7 @@ use scale_info::{ Path, Type, TypeInfo, + Variant, }; fn assert_type(expected: E) @@ -152,9 +153,13 @@ fn c_like_enum_derive() { .path(Path::new("E", "derive")) .docs(&[" Enum docs."]) .variant( - Variants::fieldless() - .variant("A", 0u64, &[" Unit variant."]) - .variant("B", 10u64, &[" Variant with discriminator."]), + Variants::new() + .variant( + Variant::builder("A").index(0).docs(&[" Unit variant."]) + ) + .variant( + Variant::builder("B").index(10).docs(&[" Variant with discriminator."]) + ), ); assert_type!(E, ty); @@ -175,12 +180,12 @@ fn c_like_enum_derive_with_scale_index_set() { } let ty = Type::builder().path(Path::new("E", "derive")).variant( - Variants::fieldless() - .variant("A", 0, &[]) - .variant("B", 10, &[]) - .variant("C", 13, &[]) - .variant("D", 3, &[]) - .variant("E", 14, &[]), + Variants::new() + .variant(Variant::builder("A").index(0)) + .variant(Variant::builder("B").index(10)) + .variant(Variant::builder("C").index(13)) + .variant(Variant::builder("D").index(3)) + .variant(Variant::builder("E").index(14)) ); assert_type!(E, ty); @@ -211,18 +216,18 @@ fn enum_derive() { .type_params(tuple_meta_type!(bool)) .docs(&[" Enum docs."]) .variant( - Variants::with_fields() + Variants::new() .variant( - "A", - Fields::unnamed().field_of::("T", &[" Unnamed field."]), - &[" Unnamed fields variant."], + Variant::builder("A") + .fields(Fields::unnamed().field_of::("T", &[" Unnamed field."])) + .docs(&[" Unnamed fields variant."]) ) .variant( - "B", - Fields::named().field_of::("b", "T", &[" Named field."]), - &[" Named fields variant."], + Variant::builder("B") + .fields(Fields::named().field_of::("b", "T", &[" Named field."])) + .docs(&[" Named fields variant."]) ) - .variant_unit("C", &[" Unit variant."]), + .variant(Variant::builder("C").docs(&[" Unit variant."])), ); assert_type!(E, ty); @@ -238,19 +243,20 @@ fn recursive_type_derive() { } let ty = Type::builder().path(Path::new("Tree", "derive")).variant( - Variants::with_fields() + Variants::new() .variant( - "Leaf", - Fields::named().field_of::("value", "i32", &[]), - &[], + Variant::builder("Leaf") + .fields(Fields::named() + .field_of::("value", "i32", &[]) + ) ) .variant( - "Node", - Fields::named() - .field_of::>("right", "Box", &[]) - .field_of::>("left", "Box", &[]), - &[], - ), + Variant::builder("Node") + .fields(Fields::named() + .field_of::>("right", "Box", &[]) + .field_of::>("left", "Box", &[]), + ) + ) ); assert_type!(Tree, ty); @@ -371,21 +377,24 @@ fn scale_compact_types_work_in_enums() { .path(Path::new("MutilatedMultiAddress", "derive")) .type_params(tuple_meta_type!(u8, u16)) .variant( - Variants::with_fields() + Variants::new() .variant( - "Id", - Fields::unnamed().field_of::("AccountId", &[]), - &[], + Variant::builder("Id") + .fields(Fields::unnamed() + .field_of::("AccountId", &[]) + ) ) .variant( - "Index", - Fields::unnamed().compact_of::("AccountIndex", &[]), - &[], + Variant::builder("Index") + .fields(Fields::unnamed() + .compact_of::("AccountIndex", &[]) + ) ) .variant( - "Address32", - Fields::unnamed().field_of::<[u8; 32]>("[u8; 32]", &[]), - &[], + Variant::builder("Address32") + .fields(Fields::unnamed() + .field_of::<[u8; 32]>("[u8; 32]", &[]) + ) ), ); @@ -425,9 +434,9 @@ fn enum_variants_marked_scale_skip_are_skipped() { } let ty = Type::builder().path(Path::new("Skippy", "derive")).variant( - Variants::fieldless() - .variant("A", 0, &[]) - .variant("C", 2, &[]), + Variants::new() + .variant(Variant::builder("A").index(0)) + .variant(Variant::builder("C").index(2)), ); assert_type!(Skippy, ty); } @@ -448,13 +457,17 @@ fn enum_variants_with_fields_marked_scale_skip_are_skipped() { } let ty = Type::builder().path(Path::new("Skippy", "derive")).variant( - Variants::with_fields() - .variant( - "Bajs", - Fields::named().field_of::("b", "bool", &[]), - &[], + Variants::new() + .variant(Variant::builder("Bajs") + .fields(Fields::named() + .field_of::("b", "bool", &[]) + ) + ) + .variant(Variant::builder("Coo") + .fields(Fields::unnamed() + .field_of::("bool", &[]) + ) ) - .variant("Coo", Fields::unnamed().field_of::("bool", &[]), &[]), ); assert_type!(Skippy, ty); } diff --git a/test_suite/tests/json.rs b/test_suite/tests/json.rs index 38434ecf..c5883098 100644 --- a/test_suite/tests/json.rs +++ b/test_suite/tests/json.rs @@ -281,9 +281,9 @@ fn test_clike_enum() { "def": { "variant": { "variants": [ - { "name": "A", "discriminant": 0, }, - { "name": "B", "discriminant": 42, }, - { "name": "C", "discriminant": 2, }, + { "name": "A", "index": 0, }, + { "name": "B", "index": 42, }, + { "name": "C", "index": 2, }, ], }, } @@ -564,15 +564,15 @@ fn test_registry() { "variants": [ { "name": "A", - "discriminant": 0, + "index": 0, }, { "name": "B", - "discriminant": 1, + "index": 1, }, { "name": "C", - "discriminant": 2, + "index": 2, }, ] } From 52f5e83a7ee6c5af6b8f0e523c6b5bb497e82f22 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 25 May 2021 17:37:33 +0100 Subject: [PATCH 47/72] Fmt --- derive/src/lib.rs | 37 ++++++++++---------- src/build/fields.rs | 24 ++++++------- src/build/mod.rs | 6 ++-- src/build/variant.rs | 14 ++++---- src/impls.rs | 24 ++++++------- src/registry.rs | 21 +++++------ src/tests.rs | 12 +++---- test_suite/tests/derive.rs | 72 ++++++++++++++++++++------------------ 8 files changed, 105 insertions(+), 105 deletions(-) diff --git a/derive/src/lib.rs b/derive/src/lib.rs index d9771dfe..350ccf7b 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -257,28 +257,27 @@ fn generate_variant_type(data_enum: &DataEnum, scale_info: &Ident) -> TokenStrea let v_name = quote! {stringify!(#ident) }; let docs = utils::get_doc_literals(&v.attrs); - let fields = - match v.fields { - Fields::Named(ref fs) => { - let fields = generate_fields(&fs.named); - quote! { - :: #scale_info::build::Fields::named() - #( #fields )* - } + let fields = match v.fields { + Fields::Named(ref fs) => { + let fields = generate_fields(&fs.named); + quote! { + :: #scale_info::build::Fields::named() + #( #fields )* } - Fields::Unnamed(ref fs) => { - let fields = generate_fields(&fs.unnamed); - quote! { - :: #scale_info::build::Fields::unnamed() - #( #fields )* - } + } + Fields::Unnamed(ref fs) => { + let fields = generate_fields(&fs.unnamed); + quote! { + :: #scale_info::build::Fields::unnamed() + #( #fields )* } - Fields::Unit => { - quote! { - :: #scale_info::build::Fields::unit() - } + } + Fields::Unit => { + quote! { + :: #scale_info::build::Fields::unit() } - }; + } + }; quote! { .variant( diff --git a/src/build/fields.rs b/src/build/fields.rs index d0eb7040..c4e15a27 100644 --- a/src/build/fields.rs +++ b/src/build/fields.rs @@ -18,9 +18,9 @@ use crate::prelude::{ }; use crate::{ + form::MetaForm, Field, TypeInfo, - form::MetaForm, }; /// A fields builder has no fields (e.g. a unit struct) @@ -80,8 +80,8 @@ impl FieldsBuilder { type_name: &'static str, docs: &[&'static str], ) -> Self - where - T: TypeInfo + ?Sized + 'static, + where + T: TypeInfo + ?Sized + 'static, { self.fields .push(Field::named_of::(name, type_name, docs)); @@ -95,9 +95,9 @@ impl FieldsBuilder { type_name: &'static str, docs: &[&'static str], ) -> Self - where - T: scale::HasCompact, - ::Type: TypeInfo + 'static, + where + T: scale::HasCompact, + ::Type: TypeInfo + 'static, { self.fields .push(Field::compact_of::(Some(name), type_name, docs)); @@ -108,8 +108,8 @@ impl FieldsBuilder { impl FieldsBuilder { /// Add an unnamed field with the type of the type parameter `T` pub fn field_of(mut self, type_name: &'static str, docs: &[&'static str]) -> Self - where - T: TypeInfo + ?Sized + 'static, + where + T: TypeInfo + ?Sized + 'static, { self.fields.push(Field::unnamed_of::(type_name, docs)); self @@ -117,12 +117,12 @@ impl FieldsBuilder { /// Add an unnamed, [`Compact`] field of type `T`. pub fn compact_of(mut self, type_name: &'static str, docs: &[&'static str]) -> Self - where - T: scale::HasCompact, - ::Type: TypeInfo + 'static, + where + T: scale::HasCompact, + ::Type: TypeInfo + 'static, { self.fields .push(Field::compact_of::(None, type_name, docs)); self } -} \ No newline at end of file +} diff --git a/src/build/mod.rs b/src/build/mod.rs index f3aef23f..fe377cbd 100644 --- a/src/build/mod.rs +++ b/src/build/mod.rs @@ -119,8 +119,10 @@ mod fields; mod variant; -pub use self::fields::*; -pub use self::variant::*; +pub use self::{ + fields::*, + variant::*, +}; use crate::prelude::{ marker::PhantomData, diff --git a/src/build/variant.rs b/src/build/variant.rs index dee074ad..9eb87e24 100644 --- a/src/build/variant.rs +++ b/src/build/variant.rs @@ -38,10 +38,7 @@ impl Variants { } /// Add a variant with the - pub fn variant( - mut self, - builder: VariantBuilder, - ) -> Self { + pub fn variant(mut self, builder: VariantBuilder) -> Self { self.variants.push(builder.finalize()); self } @@ -63,7 +60,12 @@ pub struct VariantBuilder { impl VariantBuilder { /// Create a new [`VariantBuilder`]. pub fn new(name: &'static str) -> Self { - Self { name, fields: Vec::new(), index: None, docs: Vec::new() } + Self { + name, + fields: Vec::new(), + index: None, + docs: Vec::new(), + } } /// Initialize the variant's index. @@ -88,4 +90,4 @@ impl VariantBuilder { pub fn finalize(self) -> Variant { Variant::new(self.name, self.fields, self.index, self.docs) } -} \ No newline at end of file +} diff --git a/src/impls.rs b/src/impls.rs index 7a9d9d85..5ad2ea94 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -138,14 +138,10 @@ where .path(Path::prelude("Option")) .type_params(tuple_meta_type![T]) .variant( - Variants::new() - .variant( - Variant::builder("None") - ) - .variant( - Variant::builder("Some") - .fields(Fields::unnamed().field_of::("T", &[])) - ) + Variants::new().variant(Variant::builder("None")).variant( + Variant::builder("Some") + .fields(Fields::unnamed().field_of::("T", &[])), + ), ) } } @@ -163,12 +159,14 @@ where .type_params(tuple_meta_type!(T, E)) .variant( Variants::new() - .variant(Variant::builder("Ok") - .fields(Fields::unnamed().field_of::("T", &[])) - ) - .variant(Variant::builder("Err") - .fields(Fields::unnamed().field_of::("E", &[])) + .variant( + Variant::builder("Ok") + .fields(Fields::unnamed().field_of::("T", &[])), ) + .variant( + Variant::builder("Err") + .fields(Fields::unnamed().field_of::("E", &[])), + ), ) } } diff --git a/src/registry.rs b/src/registry.rs index a951804f..61a2eddf 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -208,10 +208,10 @@ mod tests { Variants, }, meta_type, + ty::Variant, Path, TypeDef, TypeInfo, - ty::Variant, }; #[test] @@ -353,20 +353,21 @@ mod tests { .variant( Variant::builder("A") .fields( - Fields::unnamed().field_of::("bool", &[" docs"]) + Fields::unnamed() + .field_of::("bool", &[" docs"]), ) - .docs(&[" Unnamed fields variant."]) + .docs(&[" Unnamed fields variant."]), ) .variant( Variant::builder("B") - .fields( - Fields::named().field_of::("b", "u8", &[" docs"]) - ) - .docs(&[" docs"]) + .fields(Fields::named().field_of::( + "b", + "u8", + &[" docs"], + )) + .docs(&[" docs"]), ) - .variant( - Variant::builder("C").docs(&[" docs"]) - ), + .variant(Variant::builder("C").docs(&[" docs"])), ) } } diff --git a/src/tests.rs b/src/tests.rs index eb335b67..98e90589 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -62,14 +62,10 @@ fn prelude_items() { .path(Path::prelude("Option")) .type_params(tuple_meta_type!(u128)) .variant( - Variants::new() - .variant( - Variant::builder("None") - ) - .variant( - Variant::builder("Some") - .fields(Fields::unnamed().field_of::("T", &[])) - ) + Variants::new().variant(Variant::builder("None")).variant( + Variant::builder("Some") + .fields(Fields::unnamed().field_of::("T", &[])) + ) ) ); assert_type!( diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index d1043bc7..1aa8814a 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -154,11 +154,11 @@ fn c_like_enum_derive() { .docs(&[" Enum docs."]) .variant( Variants::new() + .variant(Variant::builder("A").index(0).docs(&[" Unit variant."])) .variant( - Variant::builder("A").index(0).docs(&[" Unit variant."]) - ) - .variant( - Variant::builder("B").index(10).docs(&[" Variant with discriminator."]) + Variant::builder("B") + .index(10) + .docs(&[" Variant with discriminator."]), ), ); @@ -185,7 +185,7 @@ fn c_like_enum_derive_with_scale_index_set() { .variant(Variant::builder("B").index(10)) .variant(Variant::builder("C").index(13)) .variant(Variant::builder("D").index(3)) - .variant(Variant::builder("E").index(14)) + .variant(Variant::builder("E").index(14)), ); assert_type!(E, ty); @@ -219,13 +219,19 @@ fn enum_derive() { Variants::new() .variant( Variant::builder("A") - .fields(Fields::unnamed().field_of::("T", &[" Unnamed field."])) - .docs(&[" Unnamed fields variant."]) + .fields( + Fields::unnamed().field_of::("T", &[" Unnamed field."]), + ) + .docs(&[" Unnamed fields variant."]), ) .variant( Variant::builder("B") - .fields(Fields::named().field_of::("b", "T", &[" Named field."])) - .docs(&[" Named fields variant."]) + .fields(Fields::named().field_of::( + "b", + "T", + &[" Named field."], + )) + .docs(&[" Named fields variant."]), ) .variant(Variant::builder("C").docs(&[" Unit variant."])), ); @@ -245,18 +251,19 @@ fn recursive_type_derive() { let ty = Type::builder().path(Path::new("Tree", "derive")).variant( Variants::new() .variant( - Variant::builder("Leaf") - .fields(Fields::named() - .field_of::("value", "i32", &[]) - ) + Variant::builder("Leaf").fields(Fields::named().field_of::( + "value", + "i32", + &[], + )), ) .variant( - Variant::builder("Node") - .fields(Fields::named() + Variant::builder("Node").fields( + Fields::named() .field_of::>("right", "Box", &[]) .field_of::>("left", "Box", &[]), - ) - ) + ), + ), ); assert_type!(Tree, ty); @@ -380,21 +387,15 @@ fn scale_compact_types_work_in_enums() { Variants::new() .variant( Variant::builder("Id") - .fields(Fields::unnamed() - .field_of::("AccountId", &[]) - ) + .fields(Fields::unnamed().field_of::("AccountId", &[])), ) .variant( Variant::builder("Index") - .fields(Fields::unnamed() - .compact_of::("AccountIndex", &[]) - ) + .fields(Fields::unnamed().compact_of::("AccountIndex", &[])), ) .variant( Variant::builder("Address32") - .fields(Fields::unnamed() - .field_of::<[u8; 32]>("[u8; 32]", &[]) - ) + .fields(Fields::unnamed().field_of::<[u8; 32]>("[u8; 32]", &[])), ), ); @@ -458,16 +459,17 @@ fn enum_variants_with_fields_marked_scale_skip_are_skipped() { let ty = Type::builder().path(Path::new("Skippy", "derive")).variant( Variants::new() - .variant(Variant::builder("Bajs") - .fields(Fields::named() - .field_of::("b", "bool", &[]) - ) - ) - .variant(Variant::builder("Coo") - .fields(Fields::unnamed() - .field_of::("bool", &[]) - ) + .variant( + Variant::builder("Bajs").fields(Fields::named().field_of::( + "b", + "bool", + &[], + )), ) + .variant( + Variant::builder("Coo") + .fields(Fields::unnamed().field_of::("bool", &[])), + ), ); assert_type!(Skippy, ty); } From 2d2ab5c3d527ee8dc558d5c1aebd33c427e31de8 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 25 May 2021 17:44:05 +0100 Subject: [PATCH 48/72] Condense build module back to single file --- src/{build/mod.rs => build.rs} | 186 +++++++++++++++++++++++++++++++-- src/build/fields.rs | 128 ----------------------- src/build/variant.rs | 93 ----------------- 3 files changed, 178 insertions(+), 229 deletions(-) rename src/{build/mod.rs => build.rs} (55%) delete mode 100644 src/build/fields.rs delete mode 100644 src/build/variant.rs diff --git a/src/build/mod.rs b/src/build.rs similarity index 55% rename from src/build/mod.rs rename to src/build.rs index fe377cbd..e71d300e 100644 --- a/src/build/mod.rs +++ b/src/build.rs @@ -116,25 +116,22 @@ //! } //! ``` -mod fields; -mod variant; - -pub use self::{ - fields::*, - variant::*, -}; - use crate::prelude::{ marker::PhantomData, vec::Vec, }; use crate::{ + form::MetaForm, + Field, MetaType, Path, Type, TypeDef, TypeDefComposite, + TypeDefVariant, + TypeInfo, + Variant, }; /// State types for type builders which require a Path @@ -212,3 +209,176 @@ impl TypeBuilder { self } } + +/// A fields builder has no fields (e.g. a unit struct) +pub enum NoFields {} +/// A fields builder only allows named fields (e.g. a struct) +pub enum NamedFields {} +/// A fields builder only allows unnamed fields (e.g. a tuple) +pub enum UnnamedFields {} + +/// Provides FieldsBuilder constructors +pub enum Fields {} + +impl Fields { + /// The type construct has no fields + pub fn unit() -> FieldsBuilder { + FieldsBuilder::::default() + } + + /// Fields for a type construct with named fields + pub fn named() -> FieldsBuilder { + FieldsBuilder::default() + } + + /// Fields for a type construct with unnamed fields + pub fn unnamed() -> FieldsBuilder { + FieldsBuilder::default() + } +} + +/// 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, + marker: PhantomData T>, +} + +impl Default for FieldsBuilder { + fn default() -> Self { + Self { + fields: Vec::new(), + marker: Default::default(), + } + } +} + +impl FieldsBuilder { + /// Complete building and return the set of fields + pub fn finalize(self) -> Vec> { + self.fields + } +} + +impl FieldsBuilder { + /// Add a named field with the type of the type parameter `T` + pub fn field_of( + mut self, + name: &'static str, + type_name: &'static str, + docs: &[&'static str], + ) -> Self + where + T: TypeInfo + ?Sized + 'static, + { + self.fields + .push(Field::named_of::(name, type_name, docs)); + self + } + + /// Add a named, [`Compact`] field of type `T`. + pub fn compact_of( + mut self, + name: &'static str, + type_name: &'static str, + docs: &[&'static str], + ) -> Self + where + T: scale::HasCompact, + ::Type: TypeInfo + 'static, + { + self.fields + .push(Field::compact_of::(Some(name), type_name, docs)); + self + } +} + +impl FieldsBuilder { + /// Add an unnamed field with the type of the type parameter `T` + pub fn field_of(mut self, type_name: &'static str, docs: &[&'static str]) -> Self + where + T: TypeInfo + ?Sized + 'static, + { + self.fields.push(Field::unnamed_of::(type_name, docs)); + self + } + + /// Add an unnamed, [`Compact`] field of type `T`. + pub fn compact_of(mut self, type_name: &'static str, docs: &[&'static str]) -> Self + where + T: scale::HasCompact, + ::Type: TypeInfo + 'static, + { + self.fields + .push(Field::compact_of::(None, type_name, docs)); + self + } +} + +/// Builds a definition of a variant type i.e an `enum` +#[derive(Default)] +pub struct Variants { + variants: Vec, +} + +impl Variants { + /// Create a new [`VariantsBuilder`]. + pub fn new() -> Self { + Variants { + variants: Vec::new(), + } + } + + /// Add a variant with the + pub fn variant(mut self, builder: VariantBuilder) -> Self { + self.variants.push(builder.finalize()); + self + } + + /// Construct a new [`TypeDefVariant`] from the initialized builder variants. + pub fn finalize(self) -> TypeDefVariant { + TypeDefVariant::new(self.variants) + } +} + +/// Build a [`Variant`]. +pub struct VariantBuilder { + name: &'static str, + fields: Vec>, + index: Option, + docs: Vec<&'static str>, +} + +impl VariantBuilder { + /// Create a new [`VariantBuilder`]. + pub fn new(name: &'static str) -> Self { + Self { + name, + fields: Vec::new(), + index: None, + docs: Vec::new(), + } + } + + /// Initialize the variant's index. + pub fn index(mut self, index: u64) -> Self { + self.index = Some(index); + self + } + + /// Initialize the variant's fields. + pub fn fields(mut self, fields_builder: FieldsBuilder) -> Self { + self.fields = fields_builder.finalize(); + self + } + + /// Initialize the variant's documentation. + pub fn docs(mut self, docs: &[&'static str]) -> Self { + self.docs = docs.to_vec(); + self + } + + /// Complete building and create final [`Variant`] instance. + pub fn finalize(self) -> Variant { + Variant::new(self.name, self.fields, self.index, self.docs) + } +} diff --git a/src/build/fields.rs b/src/build/fields.rs deleted file mode 100644 index c4e15a27..00000000 --- a/src/build/fields.rs +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::prelude::{ - marker::PhantomData, - vec::Vec, -}; - -use crate::{ - form::MetaForm, - Field, - TypeInfo, -}; - -/// A fields builder has no fields (e.g. a unit struct) -pub enum NoFields {} -/// A fields builder only allows named fields (e.g. a struct) -pub enum NamedFields {} -/// A fields builder only allows unnamed fields (e.g. a tuple) -pub enum UnnamedFields {} - -/// Provides FieldsBuilder constructors -pub enum Fields {} - -impl Fields { - /// The type construct has no fields - pub fn unit() -> FieldsBuilder { - FieldsBuilder::::default() - } - - /// Fields for a type construct with named fields - pub fn named() -> FieldsBuilder { - FieldsBuilder::default() - } - - /// Fields for a type construct with unnamed fields - pub fn unnamed() -> FieldsBuilder { - FieldsBuilder::default() - } -} - -/// 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, - marker: PhantomData T>, -} - -impl Default for FieldsBuilder { - fn default() -> Self { - Self { - fields: Vec::new(), - marker: Default::default(), - } - } -} - -impl FieldsBuilder { - /// Complete building and return the set of fields - pub fn finalize(self) -> Vec> { - self.fields - } -} - -impl FieldsBuilder { - /// Add a named field with the type of the type parameter `T` - pub fn field_of( - mut self, - name: &'static str, - type_name: &'static str, - docs: &[&'static str], - ) -> Self - where - T: TypeInfo + ?Sized + 'static, - { - self.fields - .push(Field::named_of::(name, type_name, docs)); - self - } - - /// Add a named, [`Compact`] field of type `T`. - pub fn compact_of( - mut self, - name: &'static str, - type_name: &'static str, - docs: &[&'static str], - ) -> Self - where - T: scale::HasCompact, - ::Type: TypeInfo + 'static, - { - self.fields - .push(Field::compact_of::(Some(name), type_name, docs)); - self - } -} - -impl FieldsBuilder { - /// Add an unnamed field with the type of the type parameter `T` - pub fn field_of(mut self, type_name: &'static str, docs: &[&'static str]) -> Self - where - T: TypeInfo + ?Sized + 'static, - { - self.fields.push(Field::unnamed_of::(type_name, docs)); - self - } - - /// Add an unnamed, [`Compact`] field of type `T`. - pub fn compact_of(mut self, type_name: &'static str, docs: &[&'static str]) -> Self - where - T: scale::HasCompact, - ::Type: TypeInfo + 'static, - { - self.fields - .push(Field::compact_of::(None, type_name, docs)); - self - } -} diff --git a/src/build/variant.rs b/src/build/variant.rs deleted file mode 100644 index 9eb87e24..00000000 --- a/src/build/variant.rs +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::prelude::vec::Vec; - -use crate::{ - form::MetaForm, - Field, - TypeDefVariant, - Variant, -}; - -use super::*; - -/// Builds a definition of a variant type i.e an `enum` -#[derive(Default)] -pub struct Variants { - variants: Vec, -} - -impl Variants { - /// Create a new [`VariantsBuilder`]. - pub fn new() -> Self { - Variants { - variants: Vec::new(), - } - } - - /// Add a variant with the - pub fn variant(mut self, builder: VariantBuilder) -> Self { - self.variants.push(builder.finalize()); - self - } - - /// Construct a new [`TypeDefVariant`] from the initialized builder variants. - pub fn finalize(self) -> TypeDefVariant { - TypeDefVariant::new(self.variants) - } -} - -/// Build a [`Variant`]. -pub struct VariantBuilder { - name: &'static str, - fields: Vec>, - index: Option, - docs: Vec<&'static str>, -} - -impl VariantBuilder { - /// Create a new [`VariantBuilder`]. - pub fn new(name: &'static str) -> Self { - Self { - name, - fields: Vec::new(), - index: None, - docs: Vec::new(), - } - } - - /// Initialize the variant's index. - pub fn index(mut self, index: u64) -> Self { - self.index = Some(index); - self - } - - /// Initialize the variant's fields. - pub fn fields(mut self, fields_builder: FieldsBuilder) -> Self { - self.fields = fields_builder.finalize(); - self - } - - /// Initialize the variant's documentation. - pub fn docs(mut self, docs: &[&'static str]) -> Self { - self.docs = docs.to_vec(); - self - } - - /// Complete building and create final [`Variant`] instance. - pub fn finalize(self) -> Variant { - Variant::new(self.name, self.fields, self.index, self.docs) - } -} From c4bf49d25b88de41160fb368c58682cbf809943b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 25 May 2021 21:01:37 +0100 Subject: [PATCH 49/72] Fix up doc tests --- src/build.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/build.rs b/src/build.rs index e71d300e..9f72de4c 100644 --- a/src/build.rs +++ b/src/build.rs @@ -65,7 +65,7 @@ //! ``` //! ## Enum with fields //! ``` -//! # use scale_info::{build::{Fields, Variants}, MetaType, Path, Type, TypeInfo}; +//! # use scale_info::{build::{Fields, Variants}, MetaType, Path, Type, TypeInfo, Variant}; //! enum Foo{ //! A(T), //! B { f: u32 }, @@ -84,16 +84,25 @@ //! .type_params(vec![MetaType::new::()]) //! .variant( //! Variants::new() -//! .variant("A", Fields::unnamed().field_of::("T", &[]), &[]) -//! .variant("B", Fields::named().field_of::("f", "u32", &[]), &[]) -//! .variant("C", Fields::unit(), &[]), +//! .variant( +//! Variant::builder("A") +//! .fields(Fields::unnamed().field_of::("T", &[])) +//! ) +//! .variant( +//! Variant::builder("B") +//! .fields(Fields::named().field_of::("f", "u32", &[])) +//! ) +//! .variant( +//! Variant::builder("A") +//! .fields(Fields::unit()) +//! ) //! ) //! } //! } //! ``` //! ## Enum without fields //! ``` -//! # use scale_info::{build::{Fields, Variants}, MetaType, Path, Type, TypeInfo}; +//! # use scale_info::{build::{Fields, Variants}, MetaType, Path, Type, TypeInfo, Variant}; //! enum Foo { //! A, //! B, @@ -107,10 +116,10 @@ //! Type::builder() //! .path(Path::new("Foo", module_path!())) //! .variant( -//! Variants::fieldless() -//! .variant("A", 1, &[]) -//! .variant("B", 2, &[]) -//! .variant("C", 33, &[]) +//! Variants::new() +//! .variant(Variant::builder("A").index(1)) +//! .variant(Variant::builder("B").index(2)) +//! .variant(Variant::builder("C").index(33)) //! ) //! } //! } From 05d875b68fcbb00b6a3fe8df8432bc54300a49c4 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 25 May 2021 21:15:12 +0100 Subject: [PATCH 50/72] Fix up README --- README.md | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 86a24411..c71543a3 100644 --- a/README.md +++ b/README.md @@ -155,10 +155,14 @@ where .path(Path::new("Foo", module_path!())) .type_params(vec![MetaType::new::()]) .variant( - Variants::with_fields() - .variant("A", Fields::unnamed().field_of::("T")) - .variant("B", Fields::named().field_of::("f", "u32")) - .variant("C", Fields::unit()) + Variants::new() + .variant( + Variant::builder("A").fields(Fields::unnamed().field_of::("T", &[])) + ) + .variant( + Variant::builder("B").fields(Fields::named().field_of::("f", "u32", &[])) + ) + .variant(Variant::builder("C").fields(Fields::unit())) ) } } @@ -181,10 +185,10 @@ impl TypeInfo for Foo { Type::builder() .path(Path::new("Foo", module_path!())) .variant( - Variants::fieldless() - .variant("A", 1) - .variant("B", 2) - .variant("C", 33) + Variants::new() + .variant(Variant::builder("A").index(1)) + .variant(Variant::builder("B").index(2)) + .variant(Variant::builder("C").index(33)) ) } } From 790a6b8228ceec718dd7db8cff63b9089d9863ec Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 26 May 2021 09:27:32 +0100 Subject: [PATCH 51/72] Define initial field builder --- src/build.rs | 69 +++++++++++++++++++++++++++++++++++++++++++++++- src/ty/fields.rs | 34 ++++++++++++++++-------- 2 files changed, 91 insertions(+), 12 deletions(-) diff --git a/src/build.rs b/src/build.rs index 9f72de4c..d1a7d250 100644 --- a/src/build.rs +++ b/src/build.rs @@ -280,7 +280,7 @@ impl FieldsBuilder { T: TypeInfo + ?Sized + 'static, { self.fields - .push(Field::named_of::(name, type_name, docs)); + .push(Field::named_of::(name, Some(type_name), docs)); self } @@ -323,6 +323,73 @@ impl FieldsBuilder { } } +/// Type states for building a field. +pub mod field_state { + /// A name has not been assigned to the field. + pub enum NameNotAssigned {} + /// A name has been assigned to the field. + pub enum NameAssigned {} + /// A type has not been assigned to the field. + pub enum TypeNotAssigned {} + /// A type has been assigned to the field. + pub enum TypeAssigned {} +} + +/// Construct a valid [`Field`]. +pub struct FieldBuilder { + field: Field, + marker: PhantomData (F, N, T)>, +} + +impl FieldBuilder { + /// Initialize the field name. + pub fn name(self, name: &'static str) -> FieldBuilder { + FieldBuilder { field: Field { name: Some(name), .. self.field }, marker: PhantomData } + } +} + +impl FieldBuilder { + /// Initialize the type of the field. + pub fn ty(self) -> FieldBuilder + where + TY: TypeInfo + 'static + { + FieldBuilder { field: Field { ty: MetaType::new::(), .. self.field }, marker: PhantomData } + } + + /// Initializes the type of the field as a compact type. + pub fn compact(self) -> FieldBuilder + where + TY: scale::HasCompact, + ::Type: TypeInfo + 'static, + { + FieldBuilder { + field: Field { + ty: MetaType::new::<::Type>(), + .. self.field + }, + marker: PhantomData + } + } +} + +impl FieldBuilder { + /// Initialize the type name of a field (optional). + pub fn type_name(self, type_name: &'static str) -> FieldBuilder { + FieldBuilder { field: Field { type_name: Some(type_name), .. self.field }, marker: PhantomData } + } + + /// Initialize the documentation of a field (optional). + pub fn docs(self, docs: Vec<&'static str>) -> FieldBuilder { + FieldBuilder { field: Field { docs, .. self.field }, marker: PhantomData } + } + + /// Complete building and return a new [`Field`]. + pub fn finalize(self) -> Field { + self.field + } +} + /// Builds a definition of a variant type i.e an `enum` #[derive(Default)] pub struct Variants { diff --git a/src/ty/fields.rs b/src/ty/fields.rs index a64b4992..e446acc6 100644 --- a/src/ty/fields.rs +++ b/src/ty/fields.rs @@ -30,6 +30,7 @@ use scale::{ }; #[cfg(feature = "serde")] use serde::{ + de::DeserializeOwned, Deserialize, Serialize, }; @@ -65,6 +66,13 @@ use serde::{ /// alias, there are no guarantees provided, and the type name representation /// may change. #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "serde", + serde(bound( + serialize = "T::Type: Serialize, T::String: Serialize", + deserialize = "T::Type: DeserializeOwned, T::String: DeserializeOwned", + )) +)] #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] #[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))] #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug, Encode)] @@ -74,18 +82,22 @@ pub struct Field { feature = "serde", serde(skip_serializing_if = "Option::is_none", default) )] - name: Option, + pub(crate) name: Option, /// The type of the field. #[cfg_attr(feature = "serde", serde(rename = "type"))] - ty: T::Type, + pub(crate) ty: T::Type, /// The name of the type of the field as it appears in the source code. - type_name: T::String, + #[cfg_attr( + feature = "serde", + serde(skip_serializing_if = "Option::is_none", default) + )] + pub(crate) type_name: Option, /// Documentation #[cfg_attr( feature = "serde", serde(skip_serializing_if = "Vec::is_empty", default) )] - docs: Vec, + pub(crate) docs: Vec, } impl IntoPortable for Field { @@ -95,7 +107,7 @@ impl IntoPortable for Field { Field { name: self.name.map(|name| name.into_portable(registry)), ty: registry.register_type(&self.ty), - type_name: self.type_name.into_portable(registry), + type_name: self.type_name.map(|tn| tn.into_portable(registry)), docs: registry.map_into_portable(self.docs), } } @@ -108,7 +120,7 @@ impl Field { pub fn new( name: Option<&'static str>, ty: MetaType, - type_name: &'static str, + type_name: Option<&'static str>, docs: &[&'static str], ) -> Self { Self { @@ -125,7 +137,7 @@ impl Field { /// compile-time type. pub fn named_of( name: &'static str, - type_name: &'static str, + type_name: Option<&'static str>, docs: &[&'static str], ) -> Field where @@ -142,7 +154,7 @@ impl Field { where T: TypeInfo + ?Sized + 'static, { - Self::new(None, MetaType::new::(), type_name, docs) + Self::new(None, MetaType::new::(), Some(type_name), docs) } /// Creates a new [`Compact`] field. @@ -158,7 +170,7 @@ impl Field { Self::new( name, MetaType::new::<::Type>(), - type_name, + Some(type_name), docs, ) } @@ -183,8 +195,8 @@ where /// 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 + pub fn type_name(&self) -> Option<&T::String> { + self.type_name.as_ref() } /// Returns the documentation of the field. From 0f3b795fe685abfcf5bed534e4c57d17cc5ddb99 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 26 May 2021 12:36:59 +0100 Subject: [PATCH 52/72] Fix up field building --- derive/src/lib.rs | 22 ++++-- src/build.rs | 157 +++++++++++++++++++++---------------- src/impls.rs | 19 ++--- src/registry.rs | 62 ++++++++------- src/tests.rs | 32 +++++--- src/ty/fields.rs | 64 +++------------ test_suite/tests/derive.rs | 150 ++++++++++++++++++++--------------- test_suite/tests/json.rs | 8 +- 8 files changed, 269 insertions(+), 245 deletions(-) diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 350ccf7b..14bf528d 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -153,16 +153,24 @@ fn generate_fields(fields: &FieldsList) -> Vec { let type_name = clean_type_string("e!(#ty).to_string()); let docs = utils::get_doc_literals(&f.attrs); - let method_call = if utils::is_compact(f) { - quote!(.compact_of::<#ty>) + let type_of_method = if utils::is_compact(f) { + quote!(compact) } else { - quote!(.field_of::<#ty>) + quote!(ty) }; - if let Some(ident) = ident { - quote!(#method_call(stringify!(#ident), #type_name, &[ #( #docs ),* ])) + let name = if let Some(ident) = ident { + quote!(.name(stringify!(#ident))) } else { - quote!(#method_call(#type_name, &[ #( #docs ),* ])) - } + quote!() + }; + quote!( + .field(|f| f + .#type_of_method::<#ty>() + #name + .type_name(#type_name) + .docs(&[ #( #docs ),* ]) + ) + ) }) .collect() } diff --git a/src/build.rs b/src/build.rs index d1a7d250..46d1bc90 100644 --- a/src/build.rs +++ b/src/build.rs @@ -269,56 +269,31 @@ impl FieldsBuilder { } impl FieldsBuilder { - /// Add a named field with the type of the type parameter `T` - pub fn field_of( - mut self, - name: &'static str, - type_name: &'static str, - docs: &[&'static str], - ) -> Self + /// Add a named field constructed using the builder. + pub fn field(mut self, builder: F) -> Self where - T: TypeInfo + ?Sized + 'static, + F: Fn( + FieldBuilder, + ) + -> FieldBuilder, { - self.fields - .push(Field::named_of::(name, Some(type_name), docs)); - self - } - - /// Add a named, [`Compact`] field of type `T`. - pub fn compact_of( - mut self, - name: &'static str, - type_name: &'static str, - docs: &[&'static str], - ) -> Self - where - T: scale::HasCompact, - ::Type: TypeInfo + 'static, - { - self.fields - .push(Field::compact_of::(Some(name), type_name, docs)); + let builder = builder(FieldBuilder::new()); + self.fields.push(builder.finalize()); self } } impl FieldsBuilder { - /// Add an unnamed field with the type of the type parameter `T` - pub fn field_of(mut self, type_name: &'static str, docs: &[&'static str]) -> Self + /// Add an unnamed field constructed using the builder. + pub fn field(mut self, builder: F) -> Self where - T: TypeInfo + ?Sized + 'static, + F: Fn( + FieldBuilder, + ) + -> FieldBuilder, { - self.fields.push(Field::unnamed_of::(type_name, docs)); - self - } - - /// Add an unnamed, [`Compact`] field of type `T`. - pub fn compact_of(mut self, type_name: &'static str, docs: &[&'static str]) -> Self - where - T: scale::HasCompact, - ::Type: TypeInfo + 'static, - { - self.fields - .push(Field::compact_of::(None, type_name, docs)); + let builder = builder(FieldBuilder::new()); + self.fields.push(builder.finalize()); self } } @@ -336,57 +311,105 @@ pub mod field_state { } /// Construct a valid [`Field`]. -pub struct FieldBuilder { - field: Field, - marker: PhantomData (F, N, T)>, +pub struct FieldBuilder< + N = field_state::NameNotAssigned, + T = field_state::TypeNotAssigned, +> { + name: Option<&'static str>, + ty: Option, + type_name: Option<&'static str>, + docs: &'static [&'static str], + marker: PhantomData (N, T)>, } -impl FieldBuilder { +impl FieldBuilder { /// Initialize the field name. - pub fn name(self, name: &'static str) -> FieldBuilder { - FieldBuilder { field: Field { name: Some(name), .. self.field }, marker: PhantomData } + pub fn name(self, name: &'static str) -> FieldBuilder { + FieldBuilder { + name: Some(name), + ty: self.ty, + type_name: self.type_name, + docs: self.docs, + marker: PhantomData, + } } } -impl FieldBuilder { +impl FieldBuilder { /// Initialize the type of the field. - pub fn ty(self) -> FieldBuilder - where - TY: TypeInfo + 'static + pub fn ty(self) -> FieldBuilder + where + TY: TypeInfo + 'static + ?Sized, { - FieldBuilder { field: Field { ty: MetaType::new::(), .. self.field }, marker: PhantomData } + FieldBuilder { + name: self.name, + ty: Some(MetaType::new::()), + type_name: self.type_name, + docs: self.docs, + marker: PhantomData, + } } /// Initializes the type of the field as a compact type. - pub fn compact(self) -> FieldBuilder - where - TY: scale::HasCompact, - ::Type: TypeInfo + 'static, + pub fn compact(self) -> FieldBuilder + where + TY: scale::HasCompact, + ::Type: TypeInfo + 'static, { FieldBuilder { - field: Field { - ty: MetaType::new::<::Type>(), - .. self.field - }, - marker: PhantomData + name: self.name, + ty: Some(MetaType::new::<::Type>()), + type_name: self.type_name, + docs: self.docs, + marker: PhantomData, } } } -impl FieldBuilder { +impl FieldBuilder { + /// Create a new FieldBuilder. + pub fn new() -> Self { + FieldBuilder { + name: None, + ty: None, + type_name: None, + docs: &[], + marker: PhantomData, + } + } + /// Initialize the type name of a field (optional). - pub fn type_name(self, type_name: &'static str) -> FieldBuilder { - FieldBuilder { field: Field { type_name: Some(type_name), .. self.field }, marker: PhantomData } + pub fn type_name(self, type_name: &'static str) -> FieldBuilder { + FieldBuilder { + name: self.name, + ty: self.ty, + type_name: Some(type_name), + docs: self.docs, + marker: PhantomData, + } } /// Initialize the documentation of a field (optional). - pub fn docs(self, docs: Vec<&'static str>) -> FieldBuilder { - FieldBuilder { field: Field { docs, .. self.field }, marker: PhantomData } + pub fn docs(self, docs: &'static [&'static str]) -> FieldBuilder { + FieldBuilder { + name: self.name, + ty: self.ty, + type_name: self.type_name, + docs, + marker: PhantomData, + } } +} +impl FieldBuilder { /// Complete building and return a new [`Field`]. pub fn finalize(self) -> Field { - self.field + Field::new( + self.name, + self.ty.expect("Type should be set by builder"), + self.type_name, + &self.docs, + ) } } diff --git a/src/impls.rs b/src/impls.rs index 5ad2ea94..4debf570 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -137,12 +137,9 @@ where Type::builder() .path(Path::prelude("Option")) .type_params(tuple_meta_type![T]) - .variant( - Variants::new().variant(Variant::builder("None")).variant( - Variant::builder("Some") - .fields(Fields::unnamed().field_of::("T", &[])), - ), - ) + .variant(Variants::new().variant(Variant::builder("None")).variant( + Variant::builder("Some").fields(Fields::unnamed().field(|f| f.ty::())), + )) } } @@ -161,11 +158,11 @@ where Variants::new() .variant( Variant::builder("Ok") - .fields(Fields::unnamed().field_of::("T", &[])), + .fields(Fields::unnamed().field(|f| f.ty::())), ) .variant( Variant::builder("Err") - .fields(Fields::unnamed().field_of::("E", &[])), + .fields(Fields::unnamed().field(|f| f.ty::())), ), ) } @@ -181,7 +178,7 @@ where Type::builder() .path(Path::prelude("Cow")) .type_params(tuple_meta_type!(T)) - .composite(Fields::unnamed().field_of::("T", &[])) + .composite(Fields::unnamed().field(|f| f.ty::())) } } @@ -196,7 +193,7 @@ where Type::builder() .path(Path::prelude("BTreeMap")) .type_params(tuple_meta_type![(K, V)]) - .composite(Fields::unnamed().field_of::<[(K, V)]>("[(K, V)]", &[])) + .composite(Fields::unnamed().field(|f| f.ty::<[(K, V)]>())) } } @@ -210,7 +207,7 @@ where Type::builder() .path(Path::prelude("BTreeSet")) .type_params(tuple_meta_type![T]) - .composite(Fields::unnamed().field_of::<[T]>("[T]", &[])) + .composite(Fields::unnamed().field(|f| f.ty::<[T]>())) } } diff --git a/src/registry.rs b/src/registry.rs index 61a2eddf..96b099a3 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -249,21 +249,21 @@ mod tests { .path(Path::new("RecursiveRefs", module_path!())) .composite( Fields::named() - .field_of::>( - "boxed", - "Box < RecursiveRefs >", - &[], - ) - .field_of::<&'static RecursiveRefs<'static>>( - "reference", - "&RecursiveRefs", - &[], - ) - .field_of::<&'static mut RecursiveRefs<'static>>( - "mutable_reference", - "&mut RecursiveRefs", - &[], - ), + .field(|f| { + f.ty::>() + .name("boxed") + .type_name("Box < RecursiveRefs >") + }) + .field(|f| { + f.ty::<&'static RecursiveRefs<'static>>() + .name("reference") + .type_name("&RecursiveRefs") + }) + .field(|f| { + f.ty::<&'static mut RecursiveRefs<'static>>() + .name("mutable_reference") + .type_name("&mut RecursiveRefs") + }), ) } } @@ -300,8 +300,13 @@ mod tests { .docs(&[" docs"]) .composite( Fields::named() - .field_of::("t", "bool", &[" docs"]) - .field_of::("u", "u8", &[]), + .field(|f| { + f.ty::() + .name("t") + .type_name("bool") + .docs(&[" docs"]) + }) + .field(|f| f.ty::().name("u").type_name("u8")), ) } } @@ -319,7 +324,10 @@ mod tests { Type::builder() .path(Path::new("T", module_path!())) .docs(&[" docs"]) - .composite(Fields::unnamed().field_of::("u32", &[" docs"])) + .composite( + Fields::unnamed() + .field(|f| f.ty::().type_name("u32").docs(&[" docs"])), + ) } } @@ -352,19 +360,19 @@ mod tests { Variants::new() .variant( Variant::builder("A") - .fields( - Fields::unnamed() - .field_of::("bool", &[" docs"]), - ) + .fields(Fields::unnamed().field(|f| { + f.ty::().type_name("bool").docs(&[" docs"]) + })) .docs(&[" Unnamed fields variant."]), ) .variant( Variant::builder("B") - .fields(Fields::named().field_of::( - "b", - "u8", - &[" docs"], - )) + .fields(Fields::named().field(|f| { + f.ty::() + .name("b") + .type_name("u8") + .docs(&[" docs"]) + })) .docs(&[" docs"]), ) .variant(Variant::builder("C").docs(&[" docs"])), diff --git a/src/tests.rs b/src/tests.rs index 98e90589..d02db199 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -63,8 +63,9 @@ fn prelude_items() { .type_params(tuple_meta_type!(u128)) .variant( Variants::new().variant(Variant::builder("None")).variant( - Variant::builder("Some") - .fields(Fields::unnamed().field_of::("T", &[])) + Variant::builder("Some").fields( + Fields::unnamed().field(|f| f.ty::().type_name("T")) + ) ) ) ); @@ -77,11 +78,11 @@ fn prelude_items() { Variants::new() .variant( Variant::builder("Ok") - .fields(Fields::unnamed().field_of::("T", &[])) + .fields(Fields::unnamed().field(|f| f.ty::().type_name("T"))) ) .variant( Variant::builder("Err") - .fields(Fields::unnamed().field_of::("E", &[])) + .fields(Fields::unnamed().field(|f| f.ty::().type_name("E"))) ) ) ); @@ -91,7 +92,7 @@ fn prelude_items() { Type::builder() .path(Path::prelude("Cow")) .type_params(tuple_meta_type!(u128)) - .composite(Fields::unnamed().field_of::("T", &[])) + .composite(Fields::unnamed().field(|f| f.ty::().type_name("T"))) ); } @@ -102,7 +103,7 @@ fn collections() { Type::builder() .path(Path::prelude("BTreeMap")) .type_params(tuple_meta_type![(String, u32)]) - .composite(Fields::unnamed().field_of::<[(String, u32)]>("[(K, V)]", &[])) + .composite(Fields::unnamed().field(|f| f.ty::<[(String, u32)]>().type_name("[(K, V)]"))) ); assert_type!( @@ -110,7 +111,7 @@ fn collections() { Type::builder() .path(Path::prelude("BTreeSet")) .type_params(tuple_meta_type![String]) - .composite(Fields::unnamed().field_of::<[String]>("[T]", &[])) + .composite(Fields::unnamed().field(|f| f.ty::<[String]>().type_name("[T]"))) ); } @@ -169,7 +170,9 @@ fn struct_with_generics() { Type::builder() .path(Path::new("MyStruct", module_path!())) .type_params(tuple_meta_type!(T)) - .composite(Fields::named().field_of::("data", "T", &[])) + .composite( + Fields::named().field(|f| f.ty::().name("data").type_name("T")), + ) } } @@ -177,7 +180,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", "T", &[])); + .composite(Fields::named().field(|f| f.ty::().name("data").type_name("T"))); assert_type!(MyStruct, struct_bool_type_info); @@ -186,7 +189,10 @@ 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", "T", &[])); + .composite( + Fields::named() + .field(|f| f.ty::>>().name("data").type_name("T")), + ); assert_type!(SelfTyped, expected_type); } @@ -208,14 +214,16 @@ fn basic_struct_with_phantoms() { Type::builder() .path(Path::new("SomeStruct", module_path!())) .type_params(tuple_meta_type!(T)) - .composite(Fields::named().field_of::("a", "u8", &[])) + .composite( + Fields::named().field(|f| f.ty::().name("a").type_name("u8")), + ) } } let struct_bool_type_info = Type::builder() .path(Path::from_segments(vec!["scale_info", "tests", "SomeStruct"]).unwrap()) .type_params(tuple_meta_type!(bool)) - .composite(Fields::named().field_of::("a", "u8", &[])); + .composite(Fields::named().field(|f| f.ty::().name("a").type_name("u8"))); assert_type!(SomeStruct, struct_bool_type_info); } diff --git a/src/ty/fields.rs b/src/ty/fields.rs index e446acc6..7eb6391e 100644 --- a/src/ty/fields.rs +++ b/src/ty/fields.rs @@ -13,6 +13,7 @@ // limitations under the License. use crate::{ + build::FieldBuilder, form::{ Form, MetaForm, @@ -22,12 +23,8 @@ use crate::{ IntoPortable, MetaType, Registry, - TypeInfo, -}; -use scale::{ - Encode, - HasCompact, }; +use scale::Encode; #[cfg(feature = "serde")] use serde::{ de::DeserializeOwned, @@ -82,22 +79,22 @@ pub struct Field { feature = "serde", serde(skip_serializing_if = "Option::is_none", default) )] - pub(crate) name: Option, + name: Option, /// The type of the field. #[cfg_attr(feature = "serde", serde(rename = "type"))] - pub(crate) ty: T::Type, + ty: T::Type, /// The name of the type of the field as it appears in the source code. #[cfg_attr( feature = "serde", serde(skip_serializing_if = "Option::is_none", default) )] - pub(crate) type_name: Option, + type_name: Option, /// Documentation #[cfg_attr( feature = "serde", serde(skip_serializing_if = "Vec::is_empty", default) )] - pub(crate) docs: Vec, + docs: Vec, } impl IntoPortable for Field { @@ -114,6 +111,11 @@ impl IntoPortable for Field { } impl Field { + /// Returns a new [`FieldBuilder`] for constructing a field. + pub fn builder() -> FieldBuilder { + FieldBuilder::new() + } + /// Creates a new field. /// /// Use this constructor if you want to instantiate from a given meta type. @@ -130,50 +132,6 @@ impl Field { docs: docs.to_vec(), } } - - /// 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, - type_name: Option<&'static str>, - docs: &[&'static str], - ) -> Field - where - T: TypeInfo + ?Sized + 'static, - { - Self::new(Some(name), MetaType::new::(), type_name, docs) - } - - /// 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(type_name: &'static str, docs: &[&'static str]) -> Field - where - T: TypeInfo + ?Sized + 'static, - { - Self::new(None, MetaType::new::(), Some(type_name), docs) - } - - /// Creates a new [`Compact`] field. - pub fn compact_of( - name: Option<&'static str>, - type_name: &'static str, - docs: &[&'static str], - ) -> Field - where - T: HasCompact, - ::Type: TypeInfo + 'static, - { - Self::new( - name, - MetaType::new::<::Type>(), - Some(type_name), - docs, - ) - } } impl Field diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index 1aa8814a..dad3655f 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -62,8 +62,13 @@ fn struct_derive() { .docs(&[" Type docs.", " Multiline."]) .composite( Fields::named() - .field_of::("t", "T", &[" Field docs."]) - .field_of::("u", "U", &[]), + .field(|f| { + f.ty::() + .name("t") + .type_name("T") + .docs(&[" Field docs."]) + }) + .field(|f| f.ty::().name("u").type_name("U")), ); assert_type!(S, struct_type); @@ -78,8 +83,13 @@ fn struct_derive() { .docs(&[" Type docs.", " Multiline."]) .composite( Fields::named() - .field_of::>>("t", "T", &[" Field docs."]) - .field_of::("u", "U", &[]), + .field(|f| { + f.ty::>>() + .name("t") + .type_name("T") + .docs(&[" Field docs."]) + }) + .field(|f| f.ty::().name("u").type_name("U")), ); assert_type!(SelfTyped, self_typed_type); } @@ -98,8 +108,12 @@ fn phantom_data_is_part_of_the_type_info() { .type_params(tuple_meta_type!(bool)) .composite( Fields::named() - .field_of::("a", "u8", &[]) - .field_of::>("m", "PhantomData", &[]), + .field(|f| f.ty::().name("a").type_name("u8")) + .field(|f| { + f.ty::>() + .name("m") + .type_name("PhantomData") + }), ); assert_type!(P, ty); @@ -119,7 +133,11 @@ fn tuple_struct_derive() { .path(Path::new("S", "derive")) .type_params(tuple_meta_type!(bool)) .docs(&[" Type docs."]) - .composite(Fields::unnamed().field_of::("T", &[" Unnamed field docs."])); + .composite(Fields::unnamed().field(|f| { + f.ty::() + .type_name("T") + .docs(&[" Unnamed field docs."]) + })); assert_type!(S, ty); } @@ -219,18 +237,19 @@ fn enum_derive() { Variants::new() .variant( Variant::builder("A") - .fields( - Fields::unnamed().field_of::("T", &[" Unnamed field."]), - ) + .fields(Fields::unnamed().field(|f| { + f.ty::().type_name("T").docs(&[" Unnamed field."]) + })) .docs(&[" Unnamed fields variant."]), ) .variant( Variant::builder("B") - .fields(Fields::named().field_of::( - "b", - "T", - &[" Named field."], - )) + .fields(Fields::named().field(|f| { + f.ty::() + .name("b") + .type_name("T") + .docs(&[" Named field."]) + })) .docs(&[" Named fields variant."]), ) .variant(Variant::builder("C").docs(&[" Unit variant."])), @@ -250,18 +269,18 @@ fn recursive_type_derive() { let ty = Type::builder().path(Path::new("Tree", "derive")).variant( Variants::new() - .variant( - Variant::builder("Leaf").fields(Fields::named().field_of::( - "value", - "i32", - &[], - )), - ) + .variant(Variant::builder("Leaf").fields( + Fields::named().field(|f| f.ty::().name("value").type_name("i32")), + )) .variant( Variant::builder("Node").fields( Fields::named() - .field_of::>("right", "Box", &[]) - .field_of::>("left", "Box", &[]), + .field(|f| { + f.ty::>().name("right").type_name("Box") + }) + .field(|f| { + f.ty::>().name("left").type_name("Box") + }), ), ), ); @@ -279,9 +298,9 @@ fn fields_with_type_alias() { a: BoolAlias, } - let ty = Type::builder() - .path(Path::new("S", "derive")) - .composite(Fields::named().field_of::("a", "BoolAlias", &[])); + let ty = Type::builder().path(Path::new("S", "derive")).composite( + Fields::named().field(|f| f.ty::().name("a").type_name("BoolAlias")), + ); assert_type!(S, ty); } @@ -309,8 +328,8 @@ fn associated_types_derive_without_bounds() { .type_params(tuple_meta_type!(ConcreteTypes)) .composite( Fields::named() - .field_of::("a", "T::A", &[]) - .field_of::("b", "&'static u64", &[]), + .field(|f| f.ty::().name("a").type_name("T::A")) + .field(|f| f.ty::().name("b").type_name("&'static u64")), ); assert_type!(Assoc, struct_type); @@ -341,10 +360,10 @@ fn associated_types_named_like_the_derived_type_works() { .type_params(tuple_meta_type!(ConcreteTypes)) .composite( Fields::named() - .field_of::>("a", "Vec", &[]) - .field_of::>("b", "Vec<::Assoc>", &[]) - .field_of::("c", "T::Assoc", &[]) - .field_of::("d", "::Assoc", &[]), + .field(|f| f.ty::>().name("a").type_name("Vec")) + .field(|f| f.ty::>().name("b").type_name("Vec<::Assoc>")) + .field(|f| f.ty::().name("c").type_name("T::Assoc")) + .field(|f| f.ty::().name("d").type_name("::Assoc")), ); assert_type!(Assoc, struct_type); @@ -364,8 +383,8 @@ fn scale_compact_types_work_in_structs() { .path(Path::new("Dense", "derive")) .composite( Fields::named() - .field_of::("a", "u8", &[]) - .compact_of::("b", "u16", &[]), + .field(|f| f.ty::().name("a").type_name("u8")) + .field(|f| f.compact::().name("b").type_name("u16")), ); assert_type!(Dense, ty_alt); } @@ -385,18 +404,18 @@ fn scale_compact_types_work_in_enums() { .type_params(tuple_meta_type!(u8, u16)) .variant( Variants::new() + .variant(Variant::builder("Id").fields( + Fields::unnamed().field(|f| f.ty::().type_name("AccountId")), + )) .variant( - Variant::builder("Id") - .fields(Fields::unnamed().field_of::("AccountId", &[])), + Variant::builder("Index").fields( + Fields::unnamed() + .field(|f| f.compact::().type_name("AccountIndex")), + ), ) - .variant( - Variant::builder("Index") - .fields(Fields::unnamed().compact_of::("AccountIndex", &[])), - ) - .variant( - Variant::builder("Address32") - .fields(Fields::unnamed().field_of::<[u8; 32]>("[u8; 32]", &[])), - ), + .variant(Variant::builder("Address32").fields( + Fields::unnamed().field(|f| f.ty::<[u8; 32]>().type_name("[u8; 32]")), + )), ); assert_type!(MutilatedMultiAddress, ty); @@ -417,8 +436,8 @@ fn struct_fields_marked_scale_skip_are_skipped() { .path(Path::new("Skippy", "derive")) .composite( Fields::named() - .field_of::("a", "u8", &[]) - .field_of::("c", "u32", &[]), + .field(|f| f.ty::().name("a").type_name("u8")) + .field(|f| f.ty::().name("c").type_name("u32")), ); assert_type!(Skippy, ty); } @@ -457,20 +476,16 @@ fn enum_variants_with_fields_marked_scale_skip_are_skipped() { Coo(bool), } - let ty = Type::builder().path(Path::new("Skippy", "derive")).variant( - Variants::new() - .variant( - Variant::builder("Bajs").fields(Fields::named().field_of::( - "b", - "bool", - &[], + let ty = + Type::builder().path(Path::new("Skippy", "derive")).variant( + Variants::new() + .variant(Variant::builder("Bajs").fields( + Fields::named().field(|f| f.ty::().name("b").type_name("bool")), + )) + .variant(Variant::builder("Coo").fields( + Fields::unnamed().field(|f| f.ty::().type_name("bool")), )), - ) - .variant( - Variant::builder("Coo") - .fields(Fields::unnamed().field_of::("bool", &[])), - ), - ); + ); assert_type!(Skippy, ty); } @@ -494,7 +509,9 @@ fn type_parameters_with_default_bound_works() { let ty = Type::builder() .path(Path::new("Bat", "derive")) .type_params(tuple_meta_type!(MetaFormy)) - .composite(Fields::named().field_of::("one", "TTT", &[])); + .composite( + Fields::named().field(|f| f.ty::().name("one").type_name("TTT")), + ); assert_type!(Bat, ty); } @@ -507,9 +524,14 @@ fn whitespace_scrubbing_works() { a: (u8, (bool, u8)), } - let ty = Type::builder().path(Path::new("A", "derive")).composite( - Fields::named().field_of::<(u8, (bool, u8))>("a", "(u8, (bool, u8))", &[]), - ); + let ty = + Type::builder() + .path(Path::new("A", "derive")) + .composite(Fields::named().field(|f| { + f.ty::<(u8, (bool, u8))>() + .name("a") + .type_name("(u8, (bool, u8))") + })); assert_type!(A, ty); } diff --git a/test_suite/tests/json.rs b/test_suite/tests/json.rs index c5883098..fb1ac45a 100644 --- a/test_suite/tests/json.rs +++ b/test_suite/tests/json.rs @@ -221,10 +221,10 @@ fn test_struct_with_some_fields_marked_as_compact() { .path(Path::new("Dense", module_path!())) .composite( Fields::named() - .compact_of::("a", "u128", &[]) - .field_of::("a_not_compact", "u128", &[]) - .field_of::<[u8; 32]>("b", "[u8; 32]", &[]) - .compact_of::("c", "u64", &[]), + .field(|f| f.compact::().name("a").type_name("u128")) + .field(|f| f.ty::().name("a_not_compact").type_name("u128")) + .field(|f| f.ty::<[u8; 32]>().name("b").type_name("[u8; 32]")) + .field(|f| f.compact::().name("c").type_name("u64")), ) } } From 655279a3a8d6cee26cd706afa9baa843262731d5 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 26 May 2021 12:47:14 +0100 Subject: [PATCH 53/72] Fix tests --- src/build.rs | 12 ++++++------ src/tests.rs | 15 +++++++-------- test_suite/tests/json.rs | 6 +++--- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/build.rs b/src/build.rs index 46d1bc90..ac6c0b65 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", "T", &[]) -//! .field_of::("data", "u64", &[]) +//! .field(|f| f.ty::().name("bar").type_name("T")) +//! .field(|f| f.ty::().name("data").type_name("u64")) //! ) //! } //! } @@ -57,8 +57,8 @@ //! Type::builder() //! .path(Path::new("Foo", module_path!())) //! .composite(Fields::unnamed() -//! .field_of::("u32", &[]) -//! .field_of::("bool", &[]) +//! .field(|f| f.ty::().type_name("u32")) +//! .field(|f| f.ty::().type_name("bool")) //! ) //! } //! } @@ -86,11 +86,11 @@ //! Variants::new() //! .variant( //! Variant::builder("A") -//! .fields(Fields::unnamed().field_of::("T", &[])) +//! .fields(Fields::unnamed().field(|f| f.ty::().type_name("T"))) //! ) //! .variant( //! Variant::builder("B") -//! .fields(Fields::named().field_of::("f", "u32", &[])) +//! .fields(Fields::named().field(|f| f.ty::().name("f").type_name("u32"))) //! ) //! .variant( //! Variant::builder("A") diff --git a/src/tests.rs b/src/tests.rs index d02db199..8e702340 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -63,9 +63,8 @@ fn prelude_items() { .type_params(tuple_meta_type!(u128)) .variant( Variants::new().variant(Variant::builder("None")).variant( - Variant::builder("Some").fields( - Fields::unnamed().field(|f| f.ty::().type_name("T")) - ) + Variant::builder("Some") + .fields(Fields::unnamed().field(|f| f.ty::())) ) ) ); @@ -78,11 +77,11 @@ fn prelude_items() { Variants::new() .variant( Variant::builder("Ok") - .fields(Fields::unnamed().field(|f| f.ty::().type_name("T"))) + .fields(Fields::unnamed().field(|f| f.ty::())) ) .variant( Variant::builder("Err") - .fields(Fields::unnamed().field(|f| f.ty::().type_name("E"))) + .fields(Fields::unnamed().field(|f| f.ty::())) ) ) ); @@ -92,7 +91,7 @@ fn prelude_items() { Type::builder() .path(Path::prelude("Cow")) .type_params(tuple_meta_type!(u128)) - .composite(Fields::unnamed().field(|f| f.ty::().type_name("T"))) + .composite(Fields::unnamed().field(|f| f.ty::())) ); } @@ -103,7 +102,7 @@ fn collections() { Type::builder() .path(Path::prelude("BTreeMap")) .type_params(tuple_meta_type![(String, u32)]) - .composite(Fields::unnamed().field(|f| f.ty::<[(String, u32)]>().type_name("[(K, V)]"))) + .composite(Fields::unnamed().field(|f| f.ty::<[(String, u32)]>())) ); assert_type!( @@ -111,7 +110,7 @@ fn collections() { Type::builder() .path(Path::prelude("BTreeSet")) .type_params(tuple_meta_type![String]) - .composite(Fields::unnamed().field(|f| f.ty::<[String]>().type_name("[T]"))) + .composite(Fields::unnamed().field(|f| f.ty::<[String]>())) ); } diff --git a/test_suite/tests/json.rs b/test_suite/tests/json.rs index fb1ac45a..9777569f 100644 --- a/test_suite/tests/json.rs +++ b/test_suite/tests/json.rs @@ -103,7 +103,7 @@ fn test_builtins() { }, { "name": "Some", - "fields": [ { "type": 0, "typeName": "T" } ] + "fields": [ { "type": 0 } ] }, ] } @@ -117,11 +117,11 @@ fn test_builtins() { "variants": [ { "name": "Ok", - "fields": [ { "type": 0, "typeName": "T" } ] + "fields": [ { "type": 0 } ] }, { "name": "Err", - "fields": [ { "type": 1, "typeName": "E" } ] + "fields": [ { "type": 1 } ] } ] } From 63b986aa7cec0d77a890960954a706b67fffd20d Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 26 May 2021 12:54:15 +0100 Subject: [PATCH 54/72] Fully qualify calls to stringify --- derive/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 14bf528d..57542355 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -103,7 +103,7 @@ fn generate_type(input: TokenStream2) -> Result { type Identity = Self; fn type_info() -> :: #scale_info ::Type { :: #scale_info ::Type::builder() - .path(:: #scale_info ::Path::new(stringify!(#ident), module_path!())) + .path(:: #scale_info ::Path::new(::core::stringify!(#ident), module_path!())) .type_params(:: #scale_info ::prelude::vec![ #( #generic_type_ids ),* ]) .docs(&[ #( #docs ),* ]) .#build_type @@ -159,7 +159,7 @@ fn generate_fields(fields: &FieldsList) -> Vec { quote!(ty) }; let name = if let Some(ident) = ident { - quote!(.name(stringify!(#ident))) + quote!(.name(::core::stringify!(#ident))) } else { quote!() }; @@ -229,7 +229,7 @@ fn generate_c_like_enum_def(variants: &VariantList, scale_info: &Ident) -> Token let docs = utils::get_doc_literals(&v.attrs); quote! { .variant( - :: #scale_info ::Variant::builder(stringify!(#name)) + :: #scale_info ::Variant::builder(::core::stringify!(#name)) .index(#discriminant as u64) .docs(&[ #( #docs ),* ]) ) @@ -262,7 +262,7 @@ fn generate_variant_type(data_enum: &DataEnum, scale_info: &Ident) -> TokenStrea .filter(|v| !utils::should_skip(&v.attrs)) .map(|v| { let ident = &v.ident; - let v_name = quote! {stringify!(#ident) }; + let v_name = quote! {::core::stringify!(#ident) }; let docs = utils::get_doc_literals(&v.attrs); let fields = match v.fields { From 150ef4ebeea79fd34bdda161ad83465432db40e8 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 26 May 2021 12:59:14 +0100 Subject: [PATCH 55/72] Default impl for FieldBuilder --- src/build.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/build.rs b/src/build.rs index ac6c0b65..fbaa4d8a 100644 --- a/src/build.rs +++ b/src/build.rs @@ -322,6 +322,18 @@ pub struct FieldBuilder< marker: PhantomData (N, T)>, } +impl Default for FieldBuilder { + fn default() -> Self { + FieldBuilder { + name: Default::default(), + ty: Default::default(), + type_name: Default::default(), + docs: Default::default(), + marker: Default::default(), + } + } +} + impl FieldBuilder { /// Initialize the field name. pub fn name(self, name: &'static str) -> FieldBuilder { @@ -369,13 +381,7 @@ impl FieldBuilder { impl FieldBuilder { /// Create a new FieldBuilder. pub fn new() -> Self { - FieldBuilder { - name: None, - ty: None, - type_name: None, - docs: &[], - marker: PhantomData, - } + Default::default() } /// Initialize the type name of a field (optional). From 43551f495908c983349345285feaa9275505f86d Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 26 May 2021 13:01:25 +0100 Subject: [PATCH 56/72] Fix up default impl --- src/build.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/build.rs b/src/build.rs index fbaa4d8a..24df9928 100644 --- a/src/build.rs +++ b/src/build.rs @@ -334,6 +334,13 @@ impl Default for FieldBuilder { } } +impl FieldBuilder { + /// Create a new FieldBuilder. + pub fn new() -> Self { + Default::default() + } +} + impl FieldBuilder { /// Initialize the field name. pub fn name(self, name: &'static str) -> FieldBuilder { @@ -379,11 +386,6 @@ impl FieldBuilder { } impl FieldBuilder { - /// Create a new FieldBuilder. - pub fn new() -> Self { - Default::default() - } - /// Initialize the type name of a field (optional). pub fn type_name(self, type_name: &'static str) -> FieldBuilder { FieldBuilder { From 0decd01a2efc476b9d913766d61afa9e2d2b2848 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 26 May 2021 13:32:44 +0100 Subject: [PATCH 57/72] Fix spelling errors --- test_suite/tests/derive.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index dad3655f..b194f017 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -163,7 +163,7 @@ fn c_like_enum_derive() { enum E { /// Unit variant. A, - /// Variant with discriminator. + /// Variant with discriminant. B = 10, } @@ -176,7 +176,7 @@ fn c_like_enum_derive() { .variant( Variant::builder("B") .index(10) - .docs(&[" Variant with discriminator."]), + .docs(&[" Variant with discriminant."]), ), ); From e031939e23a69b5a27e6cf158c7e841e93296ebf Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 26 May 2021 13:35:16 +0100 Subject: [PATCH 58/72] Remove clear_docs --- src/registry.rs | 145 +------------------------------------------- src/ty/composite.rs | 7 --- src/ty/fields.rs | 5 -- src/ty/mod.rs | 17 ------ src/ty/variant.rs | 15 ----- 5 files changed, 1 insertion(+), 188 deletions(-) diff --git a/src/registry.rs b/src/registry.rs index 96b099a3..a461caff 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -188,27 +188,14 @@ impl PortableRegistry { (id, ty) }) } - - /// Clears all docs from types. - /// - /// Use when the docs are not required to produce smaller encoded metadata. - pub fn clear_docs(&mut self) { - for ty in &mut self.types { - ty.clear_docs() - } - } } #[cfg(test)] mod tests { use super::*; use crate::{ - build::{ - Fields, - Variants, - }, + build::Fields, meta_type, - ty::Variant, Path, TypeDef, TypeInfo, @@ -280,134 +267,4 @@ mod tests { panic!("Should be a composite type definition") } } - - #[test] - fn clear_docs() { - #[allow(unused)] - /// docs - struct S { - /// docs - pub t: bool, - pub u: u8, - } - - impl TypeInfo for S { - type Identity = Self; - - fn type_info() -> Type { - Type::builder() - .path(Path::new("S", module_path!())) - .docs(&[" docs"]) - .composite( - Fields::named() - .field(|f| { - f.ty::() - .name("t") - .type_name("bool") - .docs(&[" docs"]) - }) - .field(|f| f.ty::().name("u").type_name("u8")), - ) - } - } - - #[allow(unused)] - struct T( - /// docs - u32, - ); - - impl TypeInfo for T { - type Identity = Self; - - fn type_info() -> Type { - Type::builder() - .path(Path::new("T", module_path!())) - .docs(&[" docs"]) - .composite( - Fields::unnamed() - .field(|f| f.ty::().type_name("u32").docs(&[" docs"])), - ) - } - } - - #[allow(unused)] - /// docs - enum E { - /// docs - A( - /// docs - bool, - ), - /// docs - B { - /// docs - b: u8, - }, - /// docs - C, - } - - impl TypeInfo for E { - type Identity = Self; - - fn type_info() -> Type { - Type::builder() - .path(Path::new("E", "derive")) - .type_params(tuple_meta_type!(bool)) - .docs(&[" Enum docs."]) - .variant( - Variants::new() - .variant( - Variant::builder("A") - .fields(Fields::unnamed().field(|f| { - f.ty::().type_name("bool").docs(&[" docs"]) - })) - .docs(&[" Unnamed fields variant."]), - ) - .variant( - Variant::builder("B") - .fields(Fields::named().field(|f| { - f.ty::() - .name("b") - .type_name("u8") - .docs(&[" docs"]) - })) - .docs(&[" docs"]), - ) - .variant(Variant::builder("C").docs(&[" docs"])), - ) - } - } - - let mut registry = Registry::new(); - registry.register_type(&meta_type::()); - registry.register_type(&meta_type::()); - registry.register_type(&meta_type::()); - - let mut registry: PortableRegistry = registry.into(); - - registry.clear_docs(); - - for ty in registry.types { - assert!(ty.docs().is_empty()); - match ty.type_def() { - TypeDef::Composite(c) => { - for f in c.fields() { - assert!(f.docs().is_empty()) - } - } - TypeDef::Variant(v) => { - for var in v.variants() { - assert!(var.docs().is_empty()); - - for f in var.fields() { - assert!(f.docs().is_empty()) - } - } - } - _ => {} - } - } - } } diff --git a/src/ty/composite.rs b/src/ty/composite.rs index 60cb3ae7..769c58b8 100644 --- a/src/ty/composite.rs +++ b/src/ty/composite.rs @@ -109,11 +109,4 @@ where pub fn fields(&self) -> &[Field] { &self.fields } - - /// Clear the docs of the field. - pub fn clear_docs(&mut self) { - for field in &mut self.fields { - field.clear_docs() - } - } } diff --git a/src/ty/fields.rs b/src/ty/fields.rs index 7eb6391e..97e77a8a 100644 --- a/src/ty/fields.rs +++ b/src/ty/fields.rs @@ -161,9 +161,4 @@ where pub fn docs(&self) -> &[T::String] { &self.docs } - - /// Clear the docs of the field. - pub fn clear_docs(&mut self) { - self.docs.clear() - } } diff --git a/src/ty/mod.rs b/src/ty/mod.rs index 400db24c..cf9cc8ba 100644 --- a/src/ty/mod.rs +++ b/src/ty/mod.rs @@ -86,23 +86,6 @@ pub struct Type { docs: Vec, } -impl Type { - /// Clear docs from this type. - pub fn clear_docs(&mut self) { - self.docs.clear(); - match &mut self.type_def { - TypeDef::Composite(composite) => composite.clear_docs(), - TypeDef::Variant(variant) => variant.clear_docs(), - TypeDef::Sequence(_) => {} - TypeDef::Array(_) => {} - TypeDef::Tuple(_) => {} - TypeDef::Primitive(_) => {} - TypeDef::Compact(_) => {} - TypeDef::Phantom(_) => {} - } - } -} - impl IntoPortable for Type { type Output = Type; diff --git a/src/ty/variant.rs b/src/ty/variant.rs index 3d13f8c3..acb36930 100644 --- a/src/ty/variant.rs +++ b/src/ty/variant.rs @@ -122,13 +122,6 @@ where pub fn variants(&self) -> &[Variant] { &self.variants } - - /// Clear docs for all variants. - pub fn clear_docs(&mut self) { - for variant in &mut self.variants { - variant.clear_docs() - } - } } /// A struct enum variant with either named (struct) or unnamed (tuple struct) @@ -244,12 +237,4 @@ where pub fn docs(&self) -> &[T::String] { &self.docs } - - /// Clear the docs for this variant. - pub fn clear_docs(&mut self) { - self.docs.clear(); - for field in &mut self.fields { - field.clear_docs() - } - } } From fdd96c3f8cb303543429139a56c70537ae4c0e4e Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 26 May 2021 14:05:08 +0100 Subject: [PATCH 59/72] Fully qualify module_path --- derive/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 57542355..9f0fd26a 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -103,7 +103,7 @@ fn generate_type(input: TokenStream2) -> Result { type Identity = Self; fn type_info() -> :: #scale_info ::Type { :: #scale_info ::Type::builder() - .path(:: #scale_info ::Path::new(::core::stringify!(#ident), module_path!())) + .path(:: #scale_info ::Path::new(::core::stringify!(#ident), ::core::module_path!())) .type_params(:: #scale_info ::prelude::vec![ #( #generic_type_ids ),* ]) .docs(&[ #( #docs ),* ]) .#build_type From 585a6712c1b6bff3b33835b59821d7ee4af34a63 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 26 May 2021 14:05:30 +0100 Subject: [PATCH 60/72] Update derive/src/lib.rs Co-authored-by: Robin Freyler --- derive/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 57542355..b74962ff 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -230,7 +230,7 @@ fn generate_c_like_enum_def(variants: &VariantList, scale_info: &Ident) -> Token quote! { .variant( :: #scale_info ::Variant::builder(::core::stringify!(#name)) - .index(#discriminant as u64) + .index(#discriminant as ::core::primitive::u64) .docs(&[ #( #docs ),* ]) ) } From 4d73ae4aba3feea59dc2f0e30d2d1ab2fb13e5f5 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 26 May 2021 16:40:56 +0100 Subject: [PATCH 61/72] Use callback for variant builder --- derive/src/lib.rs | 10 ++-- src/build.rs | 36 +++++------ src/impls.rs | 19 +++--- src/tests.rs | 13 ++-- src/ty/variant.rs | 6 -- test_suite/tests/derive.rs | 118 +++++++++++++++++++------------------ 6 files changed, 95 insertions(+), 107 deletions(-) diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 50c84b69..915f62e2 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -228,8 +228,8 @@ fn generate_c_like_enum_def(variants: &VariantList, scale_info: &Ident) -> Token let discriminant = utils::variant_index(v, i); let docs = utils::get_doc_literals(&v.attrs); quote! { - .variant( - :: #scale_info ::Variant::builder(::core::stringify!(#name)) + .variant(::core::stringify!(#name), |v| + v .index(#discriminant as ::core::primitive::u64) .docs(&[ #( #docs ),* ]) ) @@ -288,10 +288,8 @@ fn generate_variant_type(data_enum: &DataEnum, scale_info: &Ident) -> TokenStrea }; quote! { - .variant( - :: #scale_info::Variant::builder(#v_name) - .fields(#fields) - .docs(&[ #( #docs ),* ]) + .variant(#v_name, |v| + v.fields(#fields).docs(&[ #( #docs ),* ]) ) } }); diff --git a/src/build.rs b/src/build.rs index 24df9928..506fcb31 100644 --- a/src/build.rs +++ b/src/build.rs @@ -84,18 +84,9 @@ //! .type_params(vec![MetaType::new::()]) //! .variant( //! Variants::new() -//! .variant( -//! Variant::builder("A") -//! .fields(Fields::unnamed().field(|f| f.ty::().type_name("T"))) -//! ) -//! .variant( -//! Variant::builder("B") -//! .fields(Fields::named().field(|f| f.ty::().name("f").type_name("u32"))) -//! ) -//! .variant( -//! Variant::builder("A") -//! .fields(Fields::unit()) -//! ) +//! .variant("A", |v| v.fields(Fields::unnamed().field(|f| f.ty::().type_name("T")))) +//! .variant("B", |v| v.fields(Fields::named().field(|f| f.ty::().name("f").type_name("u32")))) +//! .variant_unit("A") //! ) //! } //! } @@ -117,9 +108,9 @@ //! .path(Path::new("Foo", module_path!())) //! .variant( //! Variants::new() -//! .variant(Variant::builder("A").index(1)) -//! .variant(Variant::builder("B").index(2)) -//! .variant(Variant::builder("C").index(33)) +//! .variant("A", |v| v.index(1)) +//! .variant("B", |v| v.index(2)) +//! .variant("C", |v| v.index(33)) //! ) //! } //! } @@ -435,8 +426,19 @@ impl Variants { } } - /// Add a variant with the - pub fn variant(mut self, builder: VariantBuilder) -> Self { + /// Add a variant + pub fn variant(mut self, name: &'static str, builder: F) -> Self + where + F: Fn(VariantBuilder) -> VariantBuilder, + { + let builder = builder(VariantBuilder::new(name)); + self.variants.push(builder.finalize()); + self + } + + /// Add a variant no fields. + pub fn variant_unit(mut self, name: &'static str) -> Self { + let builder = VariantBuilder::new(name); self.variants.push(builder.finalize()); self } diff --git a/src/impls.rs b/src/impls.rs index 4debf570..51cfa714 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -39,7 +39,6 @@ use crate::{ TypeDefSequence, TypeDefTuple, TypeInfo, - Variant, }; macro_rules! impl_metadata_for_primitives { @@ -137,9 +136,9 @@ where Type::builder() .path(Path::prelude("Option")) .type_params(tuple_meta_type![T]) - .variant(Variants::new().variant(Variant::builder("None")).variant( - Variant::builder("Some").fields(Fields::unnamed().field(|f| f.ty::())), - )) + .variant(Variants::new().variant("None", |v| v).variant("Some", |v| { + v.fields(Fields::unnamed().field(|f| f.ty::())) + })) } } @@ -156,14 +155,10 @@ where .type_params(tuple_meta_type!(T, E)) .variant( Variants::new() - .variant( - Variant::builder("Ok") - .fields(Fields::unnamed().field(|f| f.ty::())), - ) - .variant( - Variant::builder("Err") - .fields(Fields::unnamed().field(|f| f.ty::())), - ), + .variant("Ok", |v| v.fields(Fields::unnamed().field(|f| f.ty::()))) + .variant("Err", |v| { + v.fields(Fields::unnamed().field(|f| f.ty::())) + }), ) } } diff --git a/src/tests.rs b/src/tests.rs index 8e702340..653d66c4 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -61,12 +61,9 @@ fn prelude_items() { Type::builder() .path(Path::prelude("Option")) .type_params(tuple_meta_type!(u128)) - .variant( - Variants::new().variant(Variant::builder("None")).variant( - Variant::builder("Some") - .fields(Fields::unnamed().field(|f| f.ty::())) - ) - ) + .variant(Variants::new().variant("None", |v| v).variant("Some", |v| { + v.fields(Fields::unnamed().field(|f| f.ty::())) + })) ); assert_type!( Result, @@ -76,11 +73,11 @@ fn prelude_items() { .variant( Variants::new() .variant( - Variant::builder("Ok") + "Ok", |v| v .fields(Fields::unnamed().field(|f| f.ty::())) ) .variant( - Variant::builder("Err") + "Err", |v| v .fields(Fields::unnamed().field(|f| f.ty::())) ) ) diff --git a/src/ty/variant.rs b/src/ty/variant.rs index acb36930..d2ca6846 100644 --- a/src/ty/variant.rs +++ b/src/ty/variant.rs @@ -15,7 +15,6 @@ use crate::prelude::vec::Vec; use crate::{ - build::VariantBuilder, form::{ Form, MetaForm, @@ -193,11 +192,6 @@ impl IntoPortable for Variant { } impl Variant { - /// Creates a [`VariantBuilder`] for a new variant. - pub fn builder(name: &'static str) -> VariantBuilder { - VariantBuilder::new(name) - } - /// Creates a new variant. pub(crate) fn new( name: &'static str, diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index b194f017..4198b3b9 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -27,7 +27,6 @@ use scale_info::{ Path, Type, TypeInfo, - Variant, }; fn assert_type(expected: E) @@ -172,12 +171,8 @@ fn c_like_enum_derive() { .docs(&[" Enum docs."]) .variant( Variants::new() - .variant(Variant::builder("A").index(0).docs(&[" Unit variant."])) - .variant( - Variant::builder("B") - .index(10) - .docs(&[" Variant with discriminant."]), - ), + .variant("A", |v| v.index(0).docs(&[" Unit variant."])) + .variant("B", |v| v.index(10).docs(&[" Variant with discriminant."])), ); assert_type!(E, ty); @@ -199,11 +194,11 @@ fn c_like_enum_derive_with_scale_index_set() { let ty = Type::builder().path(Path::new("E", "derive")).variant( Variants::new() - .variant(Variant::builder("A").index(0)) - .variant(Variant::builder("B").index(10)) - .variant(Variant::builder("C").index(13)) - .variant(Variant::builder("D").index(3)) - .variant(Variant::builder("E").index(14)), + .variant("A", |v| v.index(0)) + .variant("B", |v| v.index(10)) + .variant("C", |v| v.index(13)) + .variant("D", |v| v.index(3)) + .variant("E", |v| v.index(14)), ); assert_type!(E, ty); @@ -235,24 +230,22 @@ fn enum_derive() { .docs(&[" Enum docs."]) .variant( Variants::new() - .variant( - Variant::builder("A") - .fields(Fields::unnamed().field(|f| { - f.ty::().type_name("T").docs(&[" Unnamed field."]) - })) - .docs(&[" Unnamed fields variant."]), - ) - .variant( - Variant::builder("B") - .fields(Fields::named().field(|f| { - f.ty::() - .name("b") - .type_name("T") - .docs(&[" Named field."]) - })) - .docs(&[" Named fields variant."]), - ) - .variant(Variant::builder("C").docs(&[" Unit variant."])), + .variant("A", |v| { + v.fields(Fields::unnamed().field(|f| { + f.ty::().type_name("T").docs(&[" Unnamed field."]) + })) + .docs(&[" Unnamed fields variant."]) + }) + .variant("B", |v| { + v.fields(Fields::named().field(|f| { + f.ty::() + .name("b") + .type_name("T") + .docs(&[" Named field."]) + })) + .docs(&[" Named fields variant."]) + }) + .variant("C", |v| v.docs(&[" Unit variant."])), ); assert_type!(E, ty); @@ -269,11 +262,14 @@ fn recursive_type_derive() { let ty = Type::builder().path(Path::new("Tree", "derive")).variant( Variants::new() - .variant(Variant::builder("Leaf").fields( - Fields::named().field(|f| f.ty::().name("value").type_name("i32")), - )) - .variant( - Variant::builder("Node").fields( + .variant("Leaf", |v| { + v.fields( + Fields::named() + .field(|f| f.ty::().name("value").type_name("i32")), + ) + }) + .variant("Node", |v| { + v.fields( Fields::named() .field(|f| { f.ty::>().name("right").type_name("Box") @@ -281,8 +277,8 @@ fn recursive_type_derive() { .field(|f| { f.ty::>().name("left").type_name("Box") }), - ), - ), + ) + }), ); assert_type!(Tree, ty); @@ -404,18 +400,23 @@ fn scale_compact_types_work_in_enums() { .type_params(tuple_meta_type!(u8, u16)) .variant( Variants::new() - .variant(Variant::builder("Id").fields( - Fields::unnamed().field(|f| f.ty::().type_name("AccountId")), - )) - .variant( - Variant::builder("Index").fields( + .variant("Id", |v| { + v.fields( + Fields::unnamed().field(|f| f.ty::().type_name("AccountId")), + ) + }) + .variant("Index", |v| { + v.fields( Fields::unnamed() .field(|f| f.compact::().type_name("AccountIndex")), - ), - ) - .variant(Variant::builder("Address32").fields( - Fields::unnamed().field(|f| f.ty::<[u8; 32]>().type_name("[u8; 32]")), - )), + ) + }) + .variant("Address32", |v| { + v.fields( + Fields::unnamed() + .field(|f| f.ty::<[u8; 32]>().type_name("[u8; 32]")), + ) + }), ); assert_type!(MutilatedMultiAddress, ty); @@ -455,8 +456,8 @@ fn enum_variants_marked_scale_skip_are_skipped() { let ty = Type::builder().path(Path::new("Skippy", "derive")).variant( Variants::new() - .variant(Variant::builder("A").index(0)) - .variant(Variant::builder("C").index(2)), + .variant("A", |v| v.index(0)) + .variant("C", |v| v.index(2)), ); assert_type!(Skippy, ty); } @@ -476,16 +477,17 @@ fn enum_variants_with_fields_marked_scale_skip_are_skipped() { Coo(bool), } - let ty = - Type::builder().path(Path::new("Skippy", "derive")).variant( - Variants::new() - .variant(Variant::builder("Bajs").fields( + let ty = Type::builder().path(Path::new("Skippy", "derive")).variant( + Variants::new() + .variant("Bajs", |v| { + v.fields( Fields::named().field(|f| f.ty::().name("b").type_name("bool")), - )) - .variant(Variant::builder("Coo").fields( - Fields::unnamed().field(|f| f.ty::().type_name("bool")), - )), - ); + ) + }) + .variant("Coo", |v| { + v.fields(Fields::unnamed().field(|f| f.ty::().type_name("bool"))) + }), + ); assert_type!(Skippy, ty); } From 59ff44cb2b90f12edda5cdb01e75b9a027f27f30 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 26 May 2021 16:50:57 +0100 Subject: [PATCH 62/72] Update README --- README.md | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index c71543a3..bc2a0f46 100644 --- a/README.md +++ b/README.md @@ -106,8 +106,8 @@ where .path(Path::new("Foo", module_path!())) .type_params(vec![MetaType::new::()]) .composite(Fields::named() - .field_of::("bar", "T") - .field_of::("data", "u64") + .field(|f| f.ty::().name("bar").type_name("T")) + .field(|f| f.ty::().name("data").type_name("u64")) ) } } @@ -125,8 +125,8 @@ impl TypeInfo for Foo { Type::builder() .path(Path::new("Foo", module_path!())) .composite(Fields::unnamed() - .field_of::("u32") - .field_of::("bool") + .field(|f| f.ty::().type_name("u32")) + .field(|f| f.ty::().type_name("bool")) ) } } @@ -156,13 +156,9 @@ where .type_params(vec![MetaType::new::()]) .variant( Variants::new() - .variant( - Variant::builder("A").fields(Fields::unnamed().field_of::("T", &[])) - ) - .variant( - Variant::builder("B").fields(Fields::named().field_of::("f", "u32", &[])) - ) - .variant(Variant::builder("C").fields(Fields::unit())) + .variant("A", |v| v.fields(Fields::unnamed().field(|f| f.ty::()))) + .variant("B", |v| v.fields(Fields::named().field(|f| f.ty::().name("f").type_name("u32")))) + .variant_unit("C") ) } } @@ -186,9 +182,9 @@ impl TypeInfo for Foo { .path(Path::new("Foo", module_path!())) .variant( Variants::new() - .variant(Variant::builder("A").index(1)) - .variant(Variant::builder("B").index(2)) - .variant(Variant::builder("C").index(33)) + .variant("A", |v| v.index(1)) + .variant("B", |v| v.index(2)) + .variant("C", |v| v.index(33)) ) } } From e8ea40b9010212129277586fe2000d9d9b86625e Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 26 May 2021 17:44:30 +0100 Subject: [PATCH 63/72] Remove leading space in doc comments --- derive/src/lib.rs | 2 -- derive/src/utils.rs | 13 +++++++++++-- test_suite/tests/derive.rs | 37 ++++++++++++++++++------------------- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 915f62e2..2619b6f7 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#![cfg_attr(not(feature = "std"), no_std)] - extern crate alloc; extern crate proc_macro; diff --git a/derive/src/utils.rs b/derive/src/utils.rs index f7ab6120..4228fa8e 100644 --- a/derive/src/utils.rs +++ b/derive/src/utils.rs @@ -16,10 +16,14 @@ //! //! NOTE: The code here is copied verbatim from `parity-scale-codec-derive`. -use alloc::vec::Vec; +use alloc::{ + string::ToString, + vec::Vec, +}; use proc_macro2::TokenStream; use quote::quote; use syn::{ + parse_quote, spanned::Spanned, AttrStyle, Attribute, @@ -36,7 +40,12 @@ pub fn get_doc_literals(attrs: &[syn::Attribute]) -> Vec { .filter_map(|attr| { if let Ok(syn::Meta::NameValue(meta)) = attr.parse_meta() { if meta.path.get_ident().map_or(false, |ident| ident == "doc") { - Some(meta.lit) + let lit = &meta.lit; + let doc_lit = quote!(#lit).to_string(); + let trimmed_doc_lit = + doc_lit.trim_start_matches(r#"" "#).trim_end_matches(r#"""#); + println!("{}", trimmed_doc_lit); + Some(parse_quote!(#trimmed_doc_lit)) } else { None } diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index 4198b3b9..ad64c20e 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -58,14 +58,14 @@ fn struct_derive() { let struct_type = Type::builder() .path(Path::new("S", "derive")) .type_params(tuple_meta_type!(bool, u8)) - .docs(&[" Type docs.", " Multiline."]) + .docs(&["Type docs.", "Multiline."]) .composite( Fields::named() .field(|f| { f.ty::() .name("t") .type_name("T") - .docs(&[" Field docs."]) + .docs(&["Field docs."]) }) .field(|f| f.ty::().name("u").type_name("U")), ); @@ -79,14 +79,14 @@ fn struct_derive() { let self_typed_type = Type::builder() .path(Path::new("S", "derive")) .type_params(tuple_meta_type!(Box>, bool)) - .docs(&[" Type docs.", " Multiline."]) + .docs(&["Type docs.", "Multiline."]) .composite( Fields::named() .field(|f| { f.ty::>>() .name("t") .type_name("T") - .docs(&[" Field docs."]) + .docs(&["Field docs."]) }) .field(|f| f.ty::().name("u").type_name("U")), ); @@ -131,12 +131,11 @@ fn tuple_struct_derive() { let ty = Type::builder() .path(Path::new("S", "derive")) .type_params(tuple_meta_type!(bool)) - .docs(&[" Type docs."]) - .composite(Fields::unnamed().field(|f| { - f.ty::() - .type_name("T") - .docs(&[" Unnamed field docs."]) - })); + .docs(&["Type docs."]) + .composite( + Fields::unnamed() + .field(|f| f.ty::().type_name("T").docs(&["Unnamed field docs."])), + ); assert_type!(S, ty); } @@ -168,11 +167,11 @@ fn c_like_enum_derive() { let ty = Type::builder() .path(Path::new("E", "derive")) - .docs(&[" Enum docs."]) + .docs(&["Enum docs."]) .variant( Variants::new() - .variant("A", |v| v.index(0).docs(&[" Unit variant."])) - .variant("B", |v| v.index(10).docs(&[" Variant with discriminant."])), + .variant("A", |v| v.index(0).docs(&["Unit variant."])) + .variant("B", |v| v.index(10).docs(&["Variant with discriminant."])), ); assert_type!(E, ty); @@ -227,25 +226,25 @@ fn enum_derive() { let ty = Type::builder() .path(Path::new("E", "derive")) .type_params(tuple_meta_type!(bool)) - .docs(&[" Enum docs."]) + .docs(&["Enum docs."]) .variant( Variants::new() .variant("A", |v| { v.fields(Fields::unnamed().field(|f| { - f.ty::().type_name("T").docs(&[" Unnamed field."]) + f.ty::().type_name("T").docs(&["Unnamed field."]) })) - .docs(&[" Unnamed fields variant."]) + .docs(&["Unnamed fields variant."]) }) .variant("B", |v| { v.fields(Fields::named().field(|f| { f.ty::() .name("b") .type_name("T") - .docs(&[" Named field."]) + .docs(&["Named field."]) })) - .docs(&[" Named fields variant."]) + .docs(&["Named fields variant."]) }) - .variant("C", |v| v.docs(&[" Unit variant."])), + .variant("C", |v| v.docs(&["Unit variant."])), ); assert_type!(E, ty); From 1c01b9466f4b0852c38f83398ea16ed02e3cf5ad Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 26 May 2021 17:48:17 +0100 Subject: [PATCH 64/72] Satisfy clippy --- derive/src/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/derive/src/utils.rs b/derive/src/utils.rs index 4228fa8e..f64366f7 100644 --- a/derive/src/utils.rs +++ b/derive/src/utils.rs @@ -43,7 +43,7 @@ pub fn get_doc_literals(attrs: &[syn::Attribute]) -> Vec { let lit = &meta.lit; let doc_lit = quote!(#lit).to_string(); let trimmed_doc_lit = - doc_lit.trim_start_matches(r#"" "#).trim_end_matches(r#"""#); + doc_lit.trim_start_matches(r#"" "#).trim_end_matches('"'); println!("{}", trimmed_doc_lit); Some(parse_quote!(#trimmed_doc_lit)) } else { From 0edec05bf1b7c70b81469244cddb82c7448c395e Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 27 May 2021 09:25:24 +0100 Subject: [PATCH 65/72] Add test for doc capture --- derive/src/utils.rs | 1 - test_suite/tests/derive.rs | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/derive/src/utils.rs b/derive/src/utils.rs index f64366f7..47d3d404 100644 --- a/derive/src/utils.rs +++ b/derive/src/utils.rs @@ -44,7 +44,6 @@ pub fn get_doc_literals(attrs: &[syn::Attribute]) -> Vec { let doc_lit = quote!(#lit).to_string(); let trimmed_doc_lit = doc_lit.trim_start_matches(r#"" "#).trim_end_matches('"'); - println!("{}", trimmed_doc_lit); Some(parse_quote!(#trimmed_doc_lit)) } else { None diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index ad64c20e..4f9c5050 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -537,6 +537,41 @@ fn whitespace_scrubbing_works() { assert_type!(A, ty); } +#[test] +fn doc_capture_works() { + //! Que pasa + #[allow(unused)] + #[derive(TypeInfo)] + #[doc(hidden)] + struct S { + #[doc = " Field a"] + a: bool, + #[doc(primitive)] + b: u8, + /// Indented + c: u16, + } + + let ty = Type::builder().path(Path::new("S", "derive")).composite( + Fields::named() + .field(|f| { + f.ty::() + .name("a") + .type_name("bool") + .docs(&["Field a"]) + }) + .field(|f| f.ty::().name("b").type_name("u8").docs(&[])) + .field(|f| { + f.ty::() + .name("c") + .type_name("u16") + .docs(&[" Indented"]) + }), + ); + + assert_type!(S, ty); +} + #[rustversion::nightly] #[test] fn ui_tests() { From fcc89857e599b41b2ac74bf89d55dbe602e318bc Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 27 May 2021 10:05:31 +0100 Subject: [PATCH 66/72] Rename index back to discriminant, changes for this will be in https://github.com/paritytech/scale-info/pull/80 --- derive/src/lib.rs | 2 +- src/build.rs | 18 +++++++++--------- src/ty/variant.rs | 21 ++++++++++----------- test_suite/tests/derive.rs | 18 +++++++++--------- test_suite/tests/json.rs | 12 ++++++------ 5 files changed, 35 insertions(+), 36 deletions(-) diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 2619b6f7..71ab562f 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -228,7 +228,7 @@ fn generate_c_like_enum_def(variants: &VariantList, scale_info: &Ident) -> Token quote! { .variant(::core::stringify!(#name), |v| v - .index(#discriminant as ::core::primitive::u64) + .discriminant(#discriminant as ::core::primitive::u64) .docs(&[ #( #docs ),* ]) ) } diff --git a/src/build.rs b/src/build.rs index 506fcb31..a74eb696 100644 --- a/src/build.rs +++ b/src/build.rs @@ -108,9 +108,9 @@ //! .path(Path::new("Foo", module_path!())) //! .variant( //! Variants::new() -//! .variant("A", |v| v.index(1)) -//! .variant("B", |v| v.index(2)) -//! .variant("C", |v| v.index(33)) +//! .variant("A", |v| v.discriminant(1)) +//! .variant("B", |v| v.discriminant(2)) +//! .variant("C", |v| v.discriminant(33)) //! ) //! } //! } @@ -453,7 +453,7 @@ impl Variants { pub struct VariantBuilder { name: &'static str, fields: Vec>, - index: Option, + discriminant: Option, docs: Vec<&'static str>, } @@ -463,14 +463,14 @@ impl VariantBuilder { Self { name, fields: Vec::new(), - index: None, + discriminant: None, docs: Vec::new(), } } - /// Initialize the variant's index. - pub fn index(mut self, index: u64) -> Self { - self.index = Some(index); + /// Initialize the variant's discriminant. + pub fn discriminant(mut self, discriminant: u64) -> Self { + self.discriminant = Some(discriminant); self } @@ -488,6 +488,6 @@ impl VariantBuilder { /// Complete building and create final [`Variant`] instance. pub fn finalize(self) -> Variant { - Variant::new(self.name, self.fields, self.index, self.docs) + Variant::new(self.name, self.fields, self.discriminant, self.docs) } } diff --git a/src/ty/variant.rs b/src/ty/variant.rs index d2ca6846..99763eaa 100644 --- a/src/ty/variant.rs +++ b/src/ty/variant.rs @@ -157,19 +157,18 @@ pub struct Variant { serde(skip_serializing_if = "Vec::is_empty", default) )] fields: Vec>, - /// The index of the variant. + /// The discriminant of the variant. /// /// # Note /// - /// In order of precedence: - /// - The index specified by the `#[codec(index = $int)]` attribute. - /// - The explicit discriminant in a "C-like" enum.l - /// - The position the variant appears in an enum definition. + /// Even though setting the discriminant is optional + /// every C-like enum variant has a discriminant specified + /// upon compile-time. #[cfg_attr( feature = "serde", serde(skip_serializing_if = "Option::is_none", default) )] - index: Option, + discriminant: Option, /// Documentation #[cfg_attr( feature = "serde", @@ -185,7 +184,7 @@ impl IntoPortable for Variant { Variant { name: self.name.into_portable(registry), fields: registry.map_into_portable(self.fields), - index: self.index, + discriminant: self.discriminant, docs: registry.map_into_portable(self.docs), } } @@ -202,7 +201,7 @@ impl Variant { Self { name, fields, - index, + discriminant: index, docs, } } @@ -222,9 +221,9 @@ where &self.fields } - /// Returns the index of the variant. - pub fn index(&self) -> Option { - self.index + /// Returns the discriminant of the variant. + pub fn discriminant(&self) -> Option { + self.discriminant } /// Returns the documentation of the variant. diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index 4f9c5050..e88e4dce 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -170,8 +170,8 @@ fn c_like_enum_derive() { .docs(&["Enum docs."]) .variant( Variants::new() - .variant("A", |v| v.index(0).docs(&["Unit variant."])) - .variant("B", |v| v.index(10).docs(&["Variant with discriminant."])), + .variant("A", |v| v.discriminant(0).docs(&["Unit variant."])) + .variant("B", |v| v.discriminant(10).docs(&["Variant with discriminant."])), ); assert_type!(E, ty); @@ -193,11 +193,11 @@ fn c_like_enum_derive_with_scale_index_set() { let ty = Type::builder().path(Path::new("E", "derive")).variant( Variants::new() - .variant("A", |v| v.index(0)) - .variant("B", |v| v.index(10)) - .variant("C", |v| v.index(13)) - .variant("D", |v| v.index(3)) - .variant("E", |v| v.index(14)), + .variant("A", |v| v.discriminant(0)) + .variant("B", |v| v.discriminant(10)) + .variant("C", |v| v.discriminant(13)) + .variant("D", |v| v.discriminant(3)) + .variant("E", |v| v.discriminant(14)), ); assert_type!(E, ty); @@ -455,8 +455,8 @@ fn enum_variants_marked_scale_skip_are_skipped() { let ty = Type::builder().path(Path::new("Skippy", "derive")).variant( Variants::new() - .variant("A", |v| v.index(0)) - .variant("C", |v| v.index(2)), + .variant("A", |v| v.discriminant(0)) + .variant("C", |v| v.discriminant(2)), ); assert_type!(Skippy, ty); } diff --git a/test_suite/tests/json.rs b/test_suite/tests/json.rs index 9777569f..89ef93a8 100644 --- a/test_suite/tests/json.rs +++ b/test_suite/tests/json.rs @@ -281,9 +281,9 @@ fn test_clike_enum() { "def": { "variant": { "variants": [ - { "name": "A", "index": 0, }, - { "name": "B", "index": 42, }, - { "name": "C", "index": 2, }, + { "name": "A", "discriminant": 0, }, + { "name": "B", "discriminant": 42, }, + { "name": "C", "discriminant": 2, }, ], }, } @@ -564,15 +564,15 @@ fn test_registry() { "variants": [ { "name": "A", - "index": 0, + "discriminant": 0, }, { "name": "B", - "index": 1, + "discriminant": 1, }, { "name": "C", - "index": 2, + "discriminant": 2, }, ] } From 6fb804255a24c9f5101ebb1455c64d62a09a9444 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 27 May 2021 10:05:48 +0100 Subject: [PATCH 67/72] Rename index back to discriminant, changes for this will be in https://github.com/paritytech/scale-info/pull/80 --- test_suite/tests/derive.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index e88e4dce..dd3c763c 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -171,7 +171,9 @@ fn c_like_enum_derive() { .variant( Variants::new() .variant("A", |v| v.discriminant(0).docs(&["Unit variant."])) - .variant("B", |v| v.discriminant(10).docs(&["Variant with discriminant."])), + .variant("B", |v| { + v.discriminant(10).docs(&["Variant with discriminant."]) + }), ); assert_type!(E, ty); From 8e611188136a485b36018f7a764e72fd895671c6 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 27 May 2021 11:26:19 +0100 Subject: [PATCH 68/72] Update builders and fix tests --- derive/src/lib.rs | 29 +++++------------ src/build.rs | 28 +++++++++-------- src/tests.rs | 64 ++++++++++++++++++++++---------------- src/ty/variant.rs | 6 ++-- test_suite/tests/derive.rs | 17 +++++++--- test_suite/tests/json.rs | 10 +++--- 6 files changed, 83 insertions(+), 71 deletions(-) diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 1d4ed9ee..ca313f2c 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -262,7 +262,7 @@ fn generate_variant_type(data_enum: &DataEnum, scale_info: &Ident) -> TokenStrea let ident = &v.ident; let v_name = quote! {::core::stringify!(#ident) }; let docs = utils::get_doc_literals(&v.attrs); - let index = utils::maybe_index(v); + let index = utils::maybe_index(v).map(|i| quote!(.index(#i))); let fields = match v.fields { Fields::Named(ref fs) => { @@ -272,30 +272,14 @@ fn generate_variant_type(data_enum: &DataEnum, scale_info: &Ident) -> TokenStrea #( #fields )* } } - (Fields::Unnamed(ref fs), Some(index)) => { - let fields = generate_fields(&fs.unnamed); - quote! { - .indexed_variant( - #v_name, - #index, - :: #scale_info::build::Fields::unnamed() - #( #fields)* - ) - } - } - (Fields::Unnamed(ref fs), None) => { + Fields::Unnamed(ref fs) => { let fields = generate_fields(&fs.unnamed); quote! { :: #scale_info::build::Fields::unnamed() - #( #fields )* + #( #fields)* } } - (Fields::Unit, Some(index)) => { - quote! { - .indexed_variant_unit(#v_name, #index) - } - } - (Fields::Unit, None) => { + Fields::Unit => { quote! { :: #scale_info::build::Fields::unit() } @@ -304,7 +288,10 @@ fn generate_variant_type(data_enum: &DataEnum, scale_info: &Ident) -> TokenStrea quote! { .variant(#v_name, |v| - v.fields(#fields).docs(&[ #( #docs ),* ]) + v + .fields(#fields) + .docs(&[ #( #docs ),* ]) + #index ) } }); diff --git a/src/build.rs b/src/build.rs index 64652191..fd54a37f 100644 --- a/src/build.rs +++ b/src/build.rs @@ -436,18 +436,6 @@ impl Variants { self } - /// Add an indexed variant with fields constructed by the supplied [`FieldsBuilder`](`crate::build::FieldsBuilder`) - pub fn indexed_variant( - mut self, - name: &'static str, - index: u8, - fields: FieldsBuilder, - ) -> Self { - self.variants - .push(Variant::indexed_with_fields(name, index, fields)); - self - } - /// Add a variant no fields. pub fn variant_unit(mut self, name: &'static str) -> Self { let builder = VariantBuilder::new(name); @@ -466,6 +454,7 @@ pub struct VariantBuilder { name: &'static str, fields: Vec>, discriminant: Option, + index: Option, docs: Vec<&'static str>, } @@ -476,6 +465,7 @@ impl VariantBuilder { name, fields: Vec::new(), discriminant: None, + index: None, docs: Vec::new(), } } @@ -486,6 +476,12 @@ impl VariantBuilder { self } + /// Initialize the variant's index. + pub fn index(mut self, index: u8) -> Self { + self.index = Some(index); + self + } + /// Initialize the variant's fields. pub fn fields(mut self, fields_builder: FieldsBuilder) -> Self { self.fields = fields_builder.finalize(); @@ -500,6 +496,12 @@ impl VariantBuilder { /// Complete building and create final [`Variant`] instance. pub fn finalize(self) -> Variant { - Variant::new(self.name, self.fields, self.discriminant, self.docs) + Variant::new( + self.name, + self.fields, + self.index, + self.discriminant, + self.docs, + ) } } diff --git a/src/tests.rs b/src/tests.rs index aeb99b5f..d35c63fd 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -247,23 +247,26 @@ fn basic_enum_with_index() { Type::builder() .path(Path::new("IndexedRustEnum", module_path!())) .variant( - Variants::with_fields() - .indexed_variant( - "A", - 3, - Fields::unnamed().field_of::("bool"), - ) - .indexed_variant( - "B", - 0, - Fields::named().field_of::("b", "bool"), - ) - .variant( - "C", - Fields::unnamed() - .field_of::("u16") - .field_of::("u32"), - ) + Variants::new() + .variant("A", |v| { + v.index(3).fields( + Fields::unnamed() + .field(|f| f.ty::().type_name("bool")), + ) + }) + .variant("B", |v| { + v.index(0).fields( + Fields::named() + .field(|f| f.ty::().name("b").type_name("u8")), + ) + }) + .variant("C", |v| { + v.fields( + Fields::unnamed() + .field(|f| f.ty::().type_name("u16")) + .field(|f| f.ty::().type_name("u32")), + ) + }) .variant_unit("D"), ) } @@ -272,15 +275,24 @@ fn basic_enum_with_index() { let ty = Type::builder() .path(Path::new("IndexedRustEnum", module_path!())) .variant( - Variants::with_fields() - .indexed_variant("A", 3, Fields::unnamed().field_of::("bool")) - .indexed_variant("B", 0, Fields::named().field_of::("b", "bool")) - .variant( - "C", - Fields::unnamed() - .field_of::("u16") - .field_of::("u32"), - ) + Variants::new() + .variant("A", |v| { + v.index(3).fields( + Fields::unnamed().field(|f| f.ty::().type_name("bool")), + ) + }) + .variant("B", |v| { + v.index(0).fields( + Fields::named().field(|f| f.ty::().name("b").type_name("u8")), + ) + }) + .variant("C", |v| { + v.fields( + Fields::unnamed() + .field(|f| f.ty::().type_name("u16")) + .field(|f| f.ty::().type_name("u32")), + ) + }) .variant_unit("D"), ); diff --git a/src/ty/variant.rs b/src/ty/variant.rs index 8c2c92bc..1c92c2b6 100644 --- a/src/ty/variant.rs +++ b/src/ty/variant.rs @@ -202,13 +202,15 @@ impl Variant { pub(crate) fn new( name: &'static str, fields: Vec>, - index: Option, + index: Option, + discriminant: Option, docs: Vec<&'static str>, ) -> Self { Self { name, fields, - discriminant: index, + index, + discriminant, docs, } } diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index 37bf2277..81836ba0 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -269,10 +269,19 @@ fn enum_derive_with_codec_index() { .path(Path::new("E", "derive")) .type_params(tuple_meta_type!(bool)) .variant( - Variants::with_fields() - .indexed_variant("A", 5, Fields::unnamed().field_of::("T")) - .indexed_variant("B", 0, Fields::named().field_of::("b", "T")) - .indexed_variant_unit("C", 13), + Variants::new() + .variant("A", |v| { + v.index(5).fields( + Fields::unnamed().field(|f| f.ty::().type_name("T")), + ) + }) + .variant("B", |v| { + v.index(0).fields( + Fields::named() + .field(|f| f.ty::().name("b").type_name("T")), + ) + }) + .variant("C", |v| v.index(13)), ); assert_type!(E, ty); diff --git a/test_suite/tests/json.rs b/test_suite/tests/json.rs index 6cc5da36..60dd8959 100644 --- a/test_suite/tests/json.rs +++ b/test_suite/tests/json.rs @@ -349,15 +349,15 @@ fn enums_with_scale_indexed_variants() { "name": "Ape", "index": 123, "fields": [ - { "type": 1, "typeName": "u8" } + { "type": 0, "typeName": "u8" } ] }, { "name": "Boar", "index": 12, "fields": [ - { "name": "a", "type": 2, "typeName": "u16" }, - { "name": "b", "type": 3, "typeName": "u32" } + { "name": "a", "type": 1, "typeName": "u16" }, + { "name": "b", "type": 2, "typeName": "u32" } ] }, { @@ -368,8 +368,8 @@ fn enums_with_scale_indexed_variants() { "name": "Dog", "index": 0, "fields": [ - { "type": 4, "typeName": "u64" }, - { "type": 5, "typeName": "u128" } + { "type": 3, "typeName": "u64" }, + { "type": 4, "typeName": "u128" } ] } ] From b8ee0a74961ba1be3bdc01dc1b876c534ab8fa9c Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Sun, 6 Jun 2021 16:44:20 +0100 Subject: [PATCH 69/72] Restore index on variant builder and fix tests --- src/build.rs | 10 +++++++++- test_suite/tests/derive.rs | 1 - 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/build.rs b/src/build.rs index 4965e43a..989d5388 100644 --- a/src/build.rs +++ b/src/build.rs @@ -453,6 +453,7 @@ impl Variants { pub struct VariantBuilder { name: &'static str, fields: Vec>, + index: Option, discriminant: Option, docs: Vec<&'static str>, } @@ -464,6 +465,7 @@ impl VariantBuilder { name, fields: Vec::new(), discriminant: None, + index: None, docs: Vec::new(), } } @@ -474,6 +476,12 @@ impl VariantBuilder { self } + /// Set the variant's codec index. + pub fn index(mut self, index: u8) -> Self { + self.index = Some(index); + self + } + /// Initialize the variant's fields. pub fn fields(mut self, fields_builder: FieldsBuilder) -> Self { self.fields = fields_builder.finalize(); @@ -488,6 +496,6 @@ impl VariantBuilder { /// Complete building and create final [`Variant`] instance. pub fn finalize(self) -> Variant { - Variant::new(self.name, self.fields, self.discriminant, self.docs) + Variant::new(self.name, self.fields, self.index, self.discriminant, self.docs) } } diff --git a/test_suite/tests/derive.rs b/test_suite/tests/derive.rs index 269f6bb8..81836ba0 100644 --- a/test_suite/tests/derive.rs +++ b/test_suite/tests/derive.rs @@ -268,7 +268,6 @@ fn enum_derive_with_codec_index() { let ty = Type::builder() .path(Path::new("E", "derive")) .type_params(tuple_meta_type!(bool)) - .docs(&["Enum docs."]) .variant( Variants::new() .variant("A", |v| { From 2ebcd0c00c785f5c5d366363da5dd145306991ca Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Sun, 6 Jun 2021 16:44:58 +0100 Subject: [PATCH 70/72] Fmt --- src/build.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/build.rs b/src/build.rs index 989d5388..f0cb5380 100644 --- a/src/build.rs +++ b/src/build.rs @@ -496,6 +496,12 @@ impl VariantBuilder { /// Complete building and create final [`Variant`] instance. pub fn finalize(self) -> Variant { - Variant::new(self.name, self.fields, self.index, self.discriminant, self.docs) + Variant::new( + self.name, + self.fields, + self.index, + self.discriminant, + self.docs, + ) } } From e016e9e32a39dcba9bcabf08664f925d8cd6bd7d Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Sun, 6 Jun 2021 16:46:29 +0100 Subject: [PATCH 71/72] Clippy --- src/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/build.rs b/src/build.rs index f0cb5380..3aeec990 100644 --- a/src/build.rs +++ b/src/build.rs @@ -407,7 +407,7 @@ impl FieldBuilder { self.name, self.ty.expect("Type should be set by builder"), self.type_name, - &self.docs, + self.docs, ) } } From 0a61395ccfa69775c0a60e8bf3b00c0ff9a6bc07 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Sun, 6 Jun 2021 16:48:28 +0100 Subject: [PATCH 72/72] Clippy --- derive/src/lib.rs | 2 +- derive/src/trait_bounds.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/derive/src/lib.rs b/derive/src/lib.rs index bec5e5ce..99af3f5b 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -251,7 +251,7 @@ fn is_c_like_enum(variants: &VariantList) -> bool { fn generate_variant_type(data_enum: &DataEnum, scale_info: &Ident) -> TokenStream2 { let variants = &data_enum.variants; - if is_c_like_enum(&variants) { + if is_c_like_enum(variants) { return generate_c_like_enum_def(variants, scale_info) } diff --git a/derive/src/trait_bounds.rs b/derive/src/trait_bounds.rs index 65da4257..41e5e6cb 100644 --- a/derive/src/trait_bounds.rs +++ b/derive/src/trait_bounds.rs @@ -160,11 +160,11 @@ fn collect_types_to_bind( .iter() .filter(|field| { // Only add a bound if the type uses a generic. - type_contains_idents(&field.ty, &ty_params) + type_contains_idents(&field.ty, ty_params) && // Remove all remaining types that start/contain the input ident // to not have them in the where clause. - !type_or_sub_type_path_starts_with_ident(&field.ty, &input_ident) + !type_or_sub_type_path_starts_with_ident(&field.ty, input_ident) }) .map(|f| (f.ty.clone(), utils::is_compact(f))) .collect()