Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optional serde feature #34

Merged
merged 13 commits into from
Dec 8, 2020
5 changes: 2 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,14 @@ include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE"]
[dependencies]
cfg-if = "1.0"
scale-info-derive = { version = "0.2.1", path = "derive", default-features = false, optional = true }
serde = { version = "1", default-features = false, features = ["derive", "alloc"] }
serde = { version = "1", default-features = false, optional = true, features = ["derive", "alloc"] }
derive_more = { version = "0.99.1", default-features = false, features = ["from"] }
scale = { package = "parity-scale-codec", version = "1.3", default-features = false, features = ["derive"] }

[features]
default = ["std"]
std = [
"serde/std",
"scale/std"
"scale/std",
]
derive = [
"scale-info-derive"
Expand Down
36 changes: 25 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,15 @@ impl<T> TypeInfo for Foo<T>
where
T: TypeInfo + 'static,
{
type Identity = Self;

fn type_info() -> Type {
Type::builder()
.path(Path::new("Foo", module_path!()))
.type_params(vec![MetaType::new::<T>()])
.composite(Fields::named()
.field_of::<T>("bar")
.field_of::<u64>("data")
.field_of::<T>("bar", "T")
.field_of::<u64>("data", "u64")
)
}
}
Expand All @@ -117,12 +119,14 @@ where
struct Foo(u32, bool);

impl TypeInfo for Foo {
type Identity = Self;

fn type_info() -> Type {
Type::builder()
.path(Path::new("Foo", module_path!()))
.composite(Fields::unnamed()
.field_of::<u32>()
.field_of::<bool>()
.field_of::<u32>("u32")
.field_of::<bool>("bool")
)
}
}
Expand All @@ -144,14 +148,16 @@ impl<T> TypeInfo for Foo<T>
where
T: TypeInfo + 'static,
{
type Identity = Self;

fn type_info() -> Type {
Type::builder()
.path(Path::new("Foo", module_path!()))
.type_params(vec![MetaType::new::<T>()])
.variant(
Variants::with_fields()
.variant("A", Fields::unnamed().field_of::<T>())
.variant("B", Fields::named().field_of::<u32>("f"))
.variant("A", Fields::unnamed().field_of::<T>("T"))
.variant("B", Fields::named().field_of::<u32>("f", "u32"))
.variant("C", Fields::unit())
)
}
Expand All @@ -169,6 +175,8 @@ enum Foo {
}

impl TypeInfo for Foo {
type Identity = Self;

fn type_info() -> Type {
Type::builder()
.path(Path::new("Foo", module_path!()))
Expand Down Expand Up @@ -201,13 +209,19 @@ After compactification 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.

## Serialization
## Encoding

The type registry can be encoded as:

- JSON (with the "serde" feature enabled).
- SCALE itself (using `parity-scale-codec`).

## Features

Currently the only supported serialization format is JSON, an example of which can be found
[here](https://github.com/paritytech/scale-info/blob/master/test_suite/tests/json.rs).
The following optional `cargo` features are available:

Future support for binary formats is planned, either SCALE itself or a more compressed format where
the monomorphization of Rust generic types could potentially result in very large files.
- **serde** includes support for json serialization/deserialization of the type registry. See example [here](https://github.com/paritytech/scale-info/blob/master/test_suite/tests/json.rs).
- **derive** reexports the [`scale-info-derive`](https://crates.io/crates/scale-info-derive) crate.

## Resources

Expand Down
10 changes: 7 additions & 3 deletions src/form.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ use crate::{
interner::UntrackedSymbol,
meta_type::MetaType,
};

#[cfg(feature = "serde")]
use serde::Serialize;

/// Trait to control the internal structures of type definitions.
Expand All @@ -51,14 +53,15 @@ 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.
///
/// Allows to be converted into other forms such as compact form
/// through the registry and `IntoCompact`.
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Serialize, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize))]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
pub enum MetaForm {}

impl Form for MetaForm {
Expand All @@ -75,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)]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub enum CompactForm {}

impl Form for CompactForm {
Expand Down
22 changes: 13 additions & 9 deletions src/interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use crate::prelude::{
vec::Vec,
};

#[cfg(feature = "serde")]
use serde::{
Deserialize,
Serialize,
Expand All @@ -40,12 +41,13 @@ use serde::{
///
/// This can be used by self-referential types but
/// can no longer be used to resolve instances.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(transparent)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct UntrackedSymbol<T> {
/// The index to the symbol in the interner table.
id: NonZeroU32,
#[serde(skip)]
#[cfg_attr(feature = "serde", serde(skip))]
marker: PhantomData<fn() -> T>,
}

Expand Down Expand Up @@ -79,11 +81,12 @@ impl<T> UntrackedSymbol<T> {
/// A symbol from an interner.
///
/// Can be used to resolve to the associated instance.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize)]
#[serde(transparent)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(Serialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct Symbol<'a, T> {
id: NonZeroU32,
#[serde(skip)]
#[cfg_attr(feature = "serde", serde(skip))]
marker: PhantomData<fn() -> &'a T>,
}

Expand Down Expand Up @@ -120,15 +123,16 @@ impl<T> Symbol<'_, T> {
///
/// This is used in order to quite efficiently cache strings and type
/// definitions uniquely identified by their associated type identifiers.
#[derive(Debug, PartialEq, Eq, Serialize)]
#[serde(transparent)]
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct Interner<T> {
/// A mapping from the interned elements to their respective compact
/// identifiers.
///
/// The idenfitiers can be used to retrieve information about the original
/// element from the interner.
#[serde(skip)]
#[cfg_attr(feature = "serde", serde(skip))]
map: BTreeMap<T, usize>,
/// The ordered sequence of cached elements.
///
Expand Down
12 changes: 8 additions & 4 deletions src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ use scale::{
Decode,
Encode,
};
#[cfg(feature = "serde")]
use serde::{
Deserialize,
Serialize,
Expand Down Expand Up @@ -83,23 +84,25 @@ impl IntoCompact for &'static str {
///
/// 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.
#[derive(Debug, PartialEq, Eq, Serialize)]
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
pub struct Registry {
/// The cache for already registered types.
///
/// This is just an accessor to the actual database
/// for all types found in the `types` field.
#[serde(skip)]
#[cfg_attr(feature = "serde", serde(skip))]
type_table: Interner<TypeId>,
/// The database where registered types actually reside.
///
/// This is going to be serialized upon serlialization.
#[serde(serialize_with = "serialize_registry_types")]
#[cfg_attr(feature = "serde", serde(serialize_with = "serialize_registry_types"))]
types: BTreeMap<UntrackedSymbol<core::any::TypeId>, Type<CompactForm>>,
}

/// 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<S>(
types: &BTreeMap<UntrackedSymbol<core::any::TypeId>, Type<CompactForm>>,
serializer: S,
Expand Down Expand Up @@ -200,7 +203,8 @@ impl Registry {
}

/// A read-only registry, to be used for decoding/deserializing
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Decode)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq, Eq, Decode)]
pub struct RegistryReadOnly {
types: Vec<Type<CompactForm>>,
}
Expand Down
32 changes: 14 additions & 18 deletions src/ty/composite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use scale::{
Decode,
Encode,
};
#[cfg(feature = "serde")]
use serde::{
de::DeserializeOwned,
Deserialize,
Expand Down Expand Up @@ -61,27 +62,22 @@ use serde::{
/// ```
/// struct JustAMarker;
/// ```
#[derive(
PartialEq,
Eq,
PartialOrd,
Ord,
Clone,
Debug,
From,
Serialize,
Deserialize,
Encode,
Decode,
#[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",
))
)]
#[serde(bound(
serialize = "T::Type: Serialize, T::String: Serialize",
deserialize = "T::Type: DeserializeOwned, T::String: DeserializeOwned"
))]
#[serde(rename_all = "lowercase")]
#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug, From, Encode, Decode)]
pub struct TypeDefComposite<T: Form = MetaForm> {
/// The fields of the composite type.
#[serde(skip_serializing_if = "Vec::is_empty", default)]
#[cfg_attr(
feature = "serde",
serde(skip_serializing_if = "Vec::is_empty", default)
)]
fields: Vec<Field<T>>,
}

Expand Down
24 changes: 15 additions & 9 deletions src/ty/fields.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use scale::{
Decode,
Encode,
};
#[cfg(feature = "serde")]
use serde::{
de::DeserializeOwned,
Deserialize,
Expand Down Expand Up @@ -61,20 +62,25 @@ use serde::{
/// This is intended for informational and diagnostic purposes only. Although it
/// is possible to infer certain properties e.g. whether a type name is a type alias,
/// there are no guarantees provided, and the type name representation may change.
#[derive(
PartialEq, Eq, PartialOrd, Ord, Clone, Debug, Serialize, Deserialize, Encode, Decode,
#[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",
))
)]
#[serde(bound(
serialize = "T::Type: Serialize, T::String: Serialize",
deserialize = "T::Type: DeserializeOwned, T::String: DeserializeOwned"
))]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug, Encode, Decode)]
pub struct Field<T: Form = MetaForm> {
/// The name of the field. None for unnamed fields.
#[serde(skip_serializing_if = "Option::is_none", default)]
#[cfg_attr(
feature = "serde",
serde(skip_serializing_if = "Option::is_none", default)
)]
name: Option<T::String>,
/// The type of the field.
#[serde(rename = "type")]
#[cfg_attr(feature = "serde", serde(rename = "type"))]
ty: T::Type,
/// The name of the type of the field as it appears in the source code.
type_name: T::String,
Expand Down
Loading