Skip to content

Commit

Permalink
Schema generation (#178)
Browse files Browse the repository at this point in the history
  • Loading branch information
SkymanOne committed Apr 25, 2023
1 parent caa38cb commit 62ac3d6
Show file tree
Hide file tree
Showing 12 changed files with 83 additions and 8 deletions.
1 change: 1 addition & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ jobs:
cargo check --no-default-features --features docs
cargo check --no-default-features --features serde
cargo check --no-default-features --features serde,decode
cargo check --no-default-features --features schema
- name: build
run: |
Expand Down
10 changes: 8 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ scale-info-derive = { version = "2.5.0", path = "derive", default-features = fal
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 = "3", default-features = false, features = ["derive"] }
schemars = { version = "0.8", optional = true }

[features]
default = ["std"]
Expand All @@ -35,14 +36,19 @@ derive = [
docs = [
"scale-info-derive/docs"
]
# enables decoding and deserialization of portable scale-info type metadata
# Enables decoding and deserialization of portable scale-info type metadata.
decode = [
"scale/full"
]
# enables type information for bitvec types, matching the name of the parity-scale-codec feature
# Enables type information for bitvec types, matching the name of the parity-scale-codec feature.
bit-vec = [
"bitvec"
]
# Enables JSON Schema generation.
schema = [
"std",
"schemars"
]

[workspace]
members = [
Expand Down
28 changes: 26 additions & 2 deletions src/form.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,25 +39,42 @@ use crate::{
meta_type::MetaType,
};

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

/// Trait to support derivation of `JsonSchema` for schema generation.
#[cfg(feature = "schema")]
pub trait JsonSchemaMaybe: JsonSchema {}
/// Trait to support derivation of `JsonSchema` for schema generation.
#[cfg(not(feature = "schema"))]
pub trait JsonSchemaMaybe {}

/// 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 portable forms that require some sort of
/// interning data structures.
pub trait Form {
/// The type representing the type.
type Type: PartialEq + Eq + PartialOrd + Ord + Clone + Debug;
type Type: PartialEq + Eq + PartialOrd + Ord + Clone + Debug + JsonSchemaMaybe;
/// The string type.
type String: AsRef<str> + PartialEq + Eq + PartialOrd + Ord + Clone + Debug;
type String: AsRef<str>
+ PartialEq
+ Eq
+ PartialOrd
+ Ord
+ Clone
+ Debug
+ JsonSchemaMaybe;
}

/// A meta meta-type.
///
/// Allows to be converted into other forms such as portable form
/// through the registry and `IntoPortable`.
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[cfg_attr(feature = "serde", derive(Serialize))]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
pub enum MetaForm {}
Expand All @@ -74,6 +91,7 @@ impl Form for MetaForm {
/// This resolves some lifetime issues with self-referential structs (such as
/// the registry itself) but can no longer be used to resolve to the original
/// underlying data.
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[cfg_attr(feature = "serde", derive(Serialize))]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
pub enum PortableForm {}
Expand All @@ -92,3 +110,9 @@ cfg_if::cfg_if! {
}
}
}

// Blanket implementations
#[cfg(not(feature = "schema"))]
impl<T> JsonSchemaMaybe for T {}
#[cfg(feature = "schema")]
impl<T> JsonSchemaMaybe for T where T: JsonSchema {}
18 changes: 17 additions & 1 deletion src/interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ use serde::{
Serialize,
};

#[cfg(feature = "schema")]
use schemars::JsonSchema;

/// A symbol that is not lifetime tracked.
///
/// This can be used by self-referential types but
Expand Down Expand Up @@ -74,13 +77,25 @@ impl<T> From<u32> for UntrackedSymbol<T> {
}
}

#[cfg(feature = "schema")]
impl<T> JsonSchema for UntrackedSymbol<T> {
fn schema_name() -> String {
String::from("UntrackedSymbol")
}

fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
gen.subschema_for::<u32>()
}
}

/// A symbol from an interner.
///
/// Can be used to resolve to the associated instance.
#[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> {
#[cfg_attr(feature = "schema", derive(JsonSchema))]
pub struct Symbol<'a, T: 'a> {
id: u32,
#[cfg_attr(feature = "serde", serde(skip))]
marker: PhantomData<fn() -> &'a T>,
Expand Down Expand Up @@ -122,6 +137,7 @@ impl<T> Symbol<'_, T> {
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
pub struct Interner<T> {
/// A mapping from the interned elements to their respective space-efficient
/// identifiers.
Expand Down
6 changes: 3 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,9 +340,6 @@ mod registry;
mod ty;
mod utils;

#[cfg(test)]
mod tests;

#[doc(hidden)]
pub use scale;

Expand Down Expand Up @@ -395,3 +392,6 @@ where
{
MetaType::new::<T>()
}

#[cfg(test)]
mod tests;
12 changes: 12 additions & 0 deletions src/meta_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,15 @@ impl MetaType {
self == &MetaType::new::<crate::impls::PhantomIdentity>()
}
}

#[cfg(feature = "schema")]
impl schemars::JsonSchema for MetaType {
fn schema_name() -> String {
"MetaType".into()
}

fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
// since MetaType does not really get serialized, we don't care about its actual schema
gen.subschema_for::<u64>()
}
}
2 changes: 2 additions & 0 deletions src/portable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ use crate::{
use scale::Encode;

/// A read-only registry containing types in their portable form for serialization.
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(all(feature = "serde", feature = "decode"), derive(serde::Deserialize))]
#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
Expand Down Expand Up @@ -231,6 +232,7 @@ impl PortableRegistry {
}

/// Represent a type in it's portable form.
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(all(feature = "serde", feature = "decode"), derive(serde::Deserialize))]
#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
Expand Down
1 change: 1 addition & 0 deletions src/ty/composite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ use serde::{
)]
#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug, From, Encode)]
pub struct TypeDefComposite<T: Form = MetaForm> {
/// The fields of the composite type.
Expand Down
1 change: 1 addition & 0 deletions src/ty/fields.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ use serde::{
)]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug, Encode)]
pub struct Field<T: Form = MetaForm> {
/// The name of the field. None for unnamed fields.
Expand Down
9 changes: 9 additions & 0 deletions src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ pub use self::{
)]
#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, From, Debug, Encode)]
pub struct Type<T: Form = MetaForm> {
/// The unique path to the type. Can be empty for built-in types
Expand Down Expand Up @@ -207,6 +208,7 @@ where
))
)]
#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, From, Debug, Encode)]
pub struct TypeParameter<T: Form = MetaForm> {
/// The name of the generic type parameter e.g. "T".
Expand Down Expand Up @@ -295,6 +297,7 @@ where
)]
#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug, Encode)]
pub enum TypeDef<T: Form = MetaForm> {
/// A composite type (e.g. a struct or a tuple)
Expand Down Expand Up @@ -369,6 +372,7 @@ impl IntoPortable for TypeDef {
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Debug)]
pub enum TypeDefPrimitive {
/// `bool` type
Expand Down Expand Up @@ -421,6 +425,7 @@ pub enum TypeDefPrimitive {
/// An array type.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Debug)]
pub struct TypeDefArray<T: Form = MetaForm> {
/// The length of the array type.
Expand Down Expand Up @@ -481,6 +486,7 @@ where
)]
#[cfg_attr(feature = "serde", serde(transparent))]
#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Debug)]
pub struct TypeDefTuple<T: Form = MetaForm> {
/// The types of the tuple fields.
Expand Down Expand Up @@ -546,6 +552,7 @@ where
/// A type to refer to a sequence of elements of the same type.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Debug)]
pub struct TypeDefSequence<T: Form = MetaForm> {
/// The element type of the sequence type.
Expand Down Expand Up @@ -600,6 +607,7 @@ where
/// A type wrapped in [`Compact`].
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Debug)]
pub struct TypeDefCompact<T: Form = MetaForm> {
/// The type wrapped in [`Compact`], i.e. the `T` in `Compact<T>`.
Expand Down Expand Up @@ -644,6 +652,7 @@ where
/// enabled, but can be decoded or deserialized into the `PortableForm` without this feature.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Debug)]
pub struct TypeDefBitSequence<T: Form = MetaForm> {
/// The type implementing [`bitvec::store::BitStore`].
Expand Down
1 change: 1 addition & 0 deletions src/ty/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ use serde::{
)]
#[cfg_attr(feature = "serde", serde(transparent))]
#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Encode)]
pub struct Path<T: Form = MetaForm> {
/// The segments of the namespace.
Expand Down
2 changes: 2 additions & 0 deletions src/ty/variant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ use serde::{
)]
#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug, From, Encode)]
pub struct TypeDefVariant<T: Form = MetaForm> {
/// The variants of a variant type
Expand Down Expand Up @@ -154,6 +155,7 @@ where
))
)]
#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug, Encode)]
pub struct Variant<T: Form = MetaForm> {
/// The name of the variant.
Expand Down

0 comments on commit 62ac3d6

Please sign in to comment.