diff --git a/Cargo.lock b/Cargo.lock index ebe370ac1..1ed03f9af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7248,6 +7248,8 @@ dependencies = [ "insta", "parity-scale-codec", "scale-info", + "serde", + "serde_json", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 545d380ce..72cf24587 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -106,8 +106,8 @@ proc-macro2 = { version = "1", default-features = false } rustdoc-types = "=0.36.0" quote = "1.0" scale-info = { version = "2.11", default-features = false } -serde = "1.0" -serde-json = { package = "serde_json", version = "1.0" } +serde = { version = "1.0", default-features = false } +serde-json = { package = "serde_json", version = "1.0", default-features = false } spin = { version = "0.9", default-features = false, features = ["spin_mutex"] } syn = "2.0" thiserror = { version = "2.0", default-features = false } diff --git a/rs/idl-meta/Cargo.toml b/rs/idl-meta/Cargo.toml index 7f66230e3..420d8e656 100644 --- a/rs/idl-meta/Cargo.toml +++ b/rs/idl-meta/Cargo.toml @@ -11,8 +11,10 @@ rust-version.workspace = true [dependencies] askama = { workspace = true, optional = true } +parity-scale-codec.workspace = true +serde = { workspace = true, features = ["derive"], optional = true } +serde-json = { workspace = true, features = ["alloc"], optional = true } scale-info.workspace = true -parity-scale-codec = { workspace = true, features = ["derive"] } [dev-dependencies] insta.workspace = true @@ -20,8 +22,13 @@ insta.workspace = true [features] default = ["ast"] ast = [] +serde = ["dep:serde", "dep:serde-json", "ast"] templates = ["dep:askama", "ast"] +[[test]] +name = "serde" +required-features = ["serde"] + [[test]] name = "templates" required-features = ["templates"] diff --git a/rs/idl-meta/src/ast.rs b/rs/idl-meta/src/ast.rs index 85f695d8f..7bf5640f4 100644 --- a/rs/idl-meta/src/ast.rs +++ b/rs/idl-meta/src/ast.rs @@ -6,6 +6,8 @@ use alloc::{ vec::Vec, }; use core::fmt::{Display, Write}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; // -------------------------------- IDL model --------------------------------- @@ -21,9 +23,19 @@ use core::fmt::{Display, Write}; derive(askama::Template), template(path = "idl.askama", escape = "none") )] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct IdlDoc { + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub globals: Vec<(String, Option)>, + #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub program: Option, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub services: Vec, } @@ -40,12 +52,33 @@ pub struct IdlDoc { derive(askama::Template), template(path = "program.askama", escape = "none") )] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct ProgramUnit { pub name: String, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub ctors: Vec, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub services: Vec, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub types: Vec, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub docs: Vec, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub annotations: Vec<(String, Option)>, } @@ -56,10 +89,20 @@ pub struct ProgramUnit { /// - an optional low-level `route` (transport / path) used by the runtime, /// - may contain documentation comments and annotations. #[derive(Debug, Default, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct ServiceExpo { pub name: String, + #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub route: Option, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub docs: Vec, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub annotations: Vec<(String, Option)>, } @@ -70,10 +113,20 @@ pub struct ServiceExpo { /// - `params` are the IDL-level arguments, /// - may contain documentation comments and annotations. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct CtorFunc { pub name: String, + #[cfg_attr(feature = "serde", serde(default))] pub params: Vec, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub docs: Vec, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub annotations: Vec<(String, Option)>, } @@ -91,13 +144,38 @@ pub struct CtorFunc { derive(askama::Template), template(path = "service.askama", escape = "none") )] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct ServiceUnit { pub name: String, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub extends: Vec, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub funcs: Vec, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub events: Vec, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub types: Vec, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub docs: Vec, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub annotations: Vec<(String, Option)>, } @@ -109,18 +187,34 @@ pub struct ServiceUnit { /// - `is_query` marks read-only / query functions as defined by the spec; /// - may contain documentation comments and annotations. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct ServiceFunc { pub name: String, + #[cfg_attr(feature = "serde", serde(default))] pub params: Vec, pub output: TypeDecl, + #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub throws: Option, pub kind: FunctionKind, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub docs: Vec, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub annotations: Vec<(String, Option)>, } /// Function kind based on mutability. #[derive(Debug, Default, PartialEq, Eq, Clone, Copy)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(rename_all = "lowercase") +)] pub enum FunctionKind { #[default] Command, @@ -142,8 +236,10 @@ impl ServiceFunc { /// Stores the parameter name as written in IDL and its fully resolved type /// (`TypeDecl`), preserving declaration order. #[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct FuncParam { pub name: String, + #[cfg_attr(feature = "serde", serde(rename = "type"))] pub type_decl: TypeDecl, } @@ -171,6 +267,11 @@ pub type ServiceEvent = EnumVariant; /// - user-defined types with generics (`UserDefined`), /// - bare generic parameters (`T`). #[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(rename_all = "lowercase", tag = "kind") +)] pub enum TypeDecl { /// Slice type `[T]`. Slice { item: Box }, @@ -185,10 +286,15 @@ pub enum TypeDecl { /// - generic type parameter (e.g. `T`) used in type definitions. Named { name: String, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] generics: Vec, }, /// Built-in primitive type from `PrimitiveType`. - Primitive(PrimitiveType), + #[cfg_attr(feature = "serde", serde(untagged))] + Primitive(#[cfg_attr(feature = "serde", serde(with = "serde_str"))] PrimitiveType), } impl TypeDecl { @@ -400,11 +506,25 @@ impl core::str::FromStr for PrimitiveType { derive(askama::Template), template(path = "type.askama", escape = "none") )] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Type { pub name: String, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub type_params: Vec, + #[cfg_attr(feature = "serde", serde(flatten))] pub def: TypeDef, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub docs: Vec, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub annotations: Vec<(String, Option)>, } @@ -414,12 +534,14 @@ pub struct Type { /// - `ty` is an optional concrete type bound / substitution; `None` means that /// the parameter is left generic at this level. #[derive(Debug, PartialEq, Eq, Hash, Clone)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct TypeParameter { /// The name of the generic type parameter e.g. "T". pub name: String, /// The concrete type for the type parameter. /// /// `None` if the type parameter is skipped. + #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub ty: Option, } @@ -436,6 +558,11 @@ impl Display for TypeParameter { /// - `Struct` - record / tuple / unit structs; /// - `Enum` - tagged unions with variants that may carry payloads. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(rename_all = "lowercase", tag = "kind") +)] pub enum TypeDef { Struct(StructDef), Enum(EnumDef), @@ -453,7 +580,9 @@ pub enum TypeDef { derive(askama::Template), template(path = "struct_def.askama", escape = "none") )] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct StructDef { + #[cfg_attr(feature = "serde", serde(default))] pub fields: Vec, } @@ -487,10 +616,21 @@ impl StructDef { derive(askama::Template), template(path = "field.askama", escape = "none") )] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct StructField { + #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub name: Option, + #[cfg_attr(feature = "serde", serde(rename = "type"))] pub type_decl: TypeDecl, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub docs: Vec, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub annotations: Vec<(String, Option)>, } @@ -499,7 +639,9 @@ pub struct StructField { /// Stores the ordered list of `EnumVariant` items that form a tagged union. /// Each variant may be unit-like, classic (named fields) or tuple-like. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct EnumDef { + #[cfg_attr(feature = "serde", serde(default))] pub variants: Vec, } @@ -514,9 +656,44 @@ pub struct EnumDef { derive(askama::Template), template(path = "variant.askama", escape = "none") )] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct EnumVariant { pub name: String, + #[cfg_attr(feature = "serde", serde(flatten))] pub def: StructDef, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub docs: Vec, + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Vec::is_empty") + )] pub annotations: Vec<(String, Option)>, } + +#[cfg(feature = "serde")] +mod serde_str { + use super::*; + use core::str::FromStr; + use serde::{Deserializer, Serializer}; + + pub(super) fn serialize(value: &T, serializer: S) -> Result + where + T: Display, + S: Serializer, + { + serializer.collect_str(value) + } + + pub(super) fn deserialize<'de, T, D>(deserializer: D) -> Result + where + T: FromStr, + ::Err: Display, + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + T::from_str(s.as_str()).map_err(serde::de::Error::custom) + } +} diff --git a/rs/idl-meta/tests/serde.rs b/rs/idl-meta/tests/serde.rs new file mode 100644 index 000000000..1c0ec2463 --- /dev/null +++ b/rs/idl-meta/tests/serde.rs @@ -0,0 +1,48 @@ +use sails_idl_meta::*; + +mod fixture; + +#[test] +fn type_enum() { + let ty = fixture::enum_variants_type(); + let serialized = serde_json::to_string_pretty(&ty).unwrap(); + let value: Type = serde_json::from_str(&serialized).unwrap(); + + assert_eq!(ty, value); + insta::assert_snapshot!(serialized); +} + +#[test] +fn service_unit() { + let service = fixture::this_that_service(); + let serialized = serde_json::to_string_pretty(&service).unwrap(); + let value: ServiceUnit = serde_json::from_str(&serialized).unwrap(); + + assert_eq!(service, value); + insta::assert_snapshot!(serialized); +} + +#[test] +fn program_unit() { + let prg = fixture::program_unit(); + let serialized = serde_json::to_string_pretty(&prg).unwrap(); + let value: ProgramUnit = serde_json::from_str(&serialized).unwrap(); + + assert_eq!(prg, value); + insta::assert_snapshot!(serialized); +} + +#[test] +fn idl_doc() { + let doc = IdlDoc { + globals: fixture::globals(), + program: Some(fixture::program_unit()), + services: vec![fixture::counter_service(), fixture::this_that_service()], + }; + + let serialized = serde_json::to_string_pretty(&doc).unwrap(); + let value: IdlDoc = serde_json::from_str(&serialized).unwrap(); + + assert_eq!(doc, value); + insta::assert_snapshot!(serialized); +} diff --git a/rs/idl-meta/tests/snapshots/serde__idl_doc.snap b/rs/idl-meta/tests/snapshots/serde__idl_doc.snap new file mode 100644 index 000000000..873c65196 --- /dev/null +++ b/rs/idl-meta/tests/snapshots/serde__idl_doc.snap @@ -0,0 +1,369 @@ +--- +source: rs/idl-meta/tests/serde.rs +expression: serialized +--- +{ + "globals": [ + [ + "sails", + "0.1.0" + ], + [ + "include", + "ownable.idl" + ], + [ + "include", + "git://github.com/some_repo/tippable.idl" + ] + ], + "program": { + "name": "Demo", + "ctors": [ + { + "name": "Create", + "params": [ + { + "name": "counter", + "type": { + "kind": "named", + "name": "Option", + "generics": [ + "u32" + ] + } + }, + { + "name": "dog_position", + "type": { + "kind": "named", + "name": "Option", + "generics": [ + { + "kind": "tuple", + "types": [ + "i32", + "i32" + ] + } + ] + } + } + ], + "docs": [ + "Program constructor (called once at the very beginning of the program lifetime)" + ] + }, + { + "name": "Default", + "params": [], + "docs": [ + "Another program constructor", + "(called once at the very beginning of the program lifetime)" + ] + } + ], + "services": [ + { + "name": "Ping" + }, + { + "name": "Counter" + }, + { + "name": "Counter", + "route": "Counter2", + "docs": [ + "Another Counter service" + ] + } + ], + "types": [ + { + "name": "DoThatParam", + "kind": "struct", + "fields": [ + { + "name": "p1", + "type": "u32" + }, + { + "name": "p2", + "type": "ActorId" + }, + { + "name": "p3", + "type": { + "kind": "named", + "name": "ManyVariants" + } + } + ] + }, + { + "name": "TupleStruct", + "kind": "struct", + "fields": [ + { + "type": "u32" + } + ] + }, + { + "name": "UnitStruct", + "kind": "struct", + "fields": [] + } + ], + "docs": [ + "Demo Program" + ] + }, + "services": [ + { + "name": "Counter", + "funcs": [ + { + "name": "Add", + "params": [ + { + "name": "value", + "type": "u32" + } + ], + "output": "u32", + "kind": "command", + "docs": [ + "Add a value to the counter" + ] + }, + { + "name": "Sub", + "params": [ + { + "name": "value", + "type": "u32" + } + ], + "output": "u32", + "throws": "String", + "kind": "command", + "docs": [ + "Substract a value from the counter" + ] + }, + { + "name": "Value", + "params": [], + "output": "u32", + "kind": "query", + "docs": [ + "Get the current value" + ], + "annotations": [ + [ + "query", + null + ] + ] + } + ], + "events": [ + { + "name": "Added", + "fields": [ + { + "type": "u32" + } + ], + "docs": [ + "Emitted when a new value is added to the counter" + ] + }, + { + "name": "Subtracted", + "fields": [ + { + "type": "u32" + } + ], + "docs": [ + "Emitted when a value is subtracted from the counter" + ] + } + ] + }, + { + "name": "ThisThat", + "funcs": [ + { + "name": "DoThis", + "params": [ + { + "name": "p1", + "type": "u32" + }, + { + "name": "p2", + "type": "String" + }, + { + "name": "p3", + "type": { + "kind": "tuple", + "types": [ + { + "kind": "named", + "name": "Option", + "generics": [ + "H160" + ] + }, + { + "kind": "named", + "name": "NonZero", + "generics": [ + "u8" + ] + } + ] + } + }, + { + "name": "p4", + "type": { + "kind": "named", + "name": "TupleStruct" + } + } + ], + "output": { + "kind": "tuple", + "types": [ + "String", + "u32" + ] + }, + "throws": { + "kind": "tuple", + "types": [ + "String" + ] + }, + "kind": "command", + "docs": [ + "Some func", + "With multiline doc" + ] + } + ], + "types": [ + { + "name": "DoThatParam", + "kind": "struct", + "fields": [ + { + "name": "p1", + "type": "u32", + "docs": [ + "Parametr p1: u32" + ] + }, + { + "name": "p2", + "type": "ActorId" + }, + { + "name": "p3", + "type": { + "kind": "named", + "name": "ManyVariants" + } + } + ] + }, + { + "name": "ManyVariants", + "kind": "enum", + "variants": [ + { + "name": "One", + "fields": [] + }, + { + "name": "Two", + "fields": [ + { + "type": "u32" + } + ] + }, + { + "name": "Three", + "fields": [ + { + "type": { + "kind": "named", + "name": "Option", + "generics": [ + "u32" + ] + } + } + ] + }, + { + "name": "Four", + "fields": [ + { + "name": "a", + "type": "u32" + }, + { + "name": "b", + "type": { + "kind": "named", + "name": "Option", + "generics": [ + "u16" + ] + } + } + ] + }, + { + "name": "Five", + "fields": [ + { + "type": "String" + }, + { + "type": "H256", + "annotations": [ + [ + "key", + "value" + ] + ] + } + ] + }, + { + "name": "Six", + "fields": [ + { + "type": { + "kind": "tuple", + "types": [ + "u32" + ] + } + } + ] + } + ] + } + ] + } + ] +} diff --git a/rs/idl-meta/tests/snapshots/serde__program_unit.snap b/rs/idl-meta/tests/snapshots/serde__program_unit.snap new file mode 100644 index 000000000..4dc175343 --- /dev/null +++ b/rs/idl-meta/tests/snapshots/serde__program_unit.snap @@ -0,0 +1,106 @@ +--- +source: rs/idl-meta/tests/serde.rs +expression: serialized +--- +{ + "name": "Demo", + "ctors": [ + { + "name": "Create", + "params": [ + { + "name": "counter", + "type": { + "kind": "named", + "name": "Option", + "generics": [ + "u32" + ] + } + }, + { + "name": "dog_position", + "type": { + "kind": "named", + "name": "Option", + "generics": [ + { + "kind": "tuple", + "types": [ + "i32", + "i32" + ] + } + ] + } + } + ], + "docs": [ + "Program constructor (called once at the very beginning of the program lifetime)" + ] + }, + { + "name": "Default", + "params": [], + "docs": [ + "Another program constructor", + "(called once at the very beginning of the program lifetime)" + ] + } + ], + "services": [ + { + "name": "Ping" + }, + { + "name": "Counter" + }, + { + "name": "Counter", + "route": "Counter2", + "docs": [ + "Another Counter service" + ] + } + ], + "types": [ + { + "name": "DoThatParam", + "kind": "struct", + "fields": [ + { + "name": "p1", + "type": "u32" + }, + { + "name": "p2", + "type": "ActorId" + }, + { + "name": "p3", + "type": { + "kind": "named", + "name": "ManyVariants" + } + } + ] + }, + { + "name": "TupleStruct", + "kind": "struct", + "fields": [ + { + "type": "u32" + } + ] + }, + { + "name": "UnitStruct", + "kind": "struct", + "fields": [] + } + ], + "docs": [ + "Demo Program" + ] +} diff --git a/rs/idl-meta/tests/snapshots/serde__service_unit.snap b/rs/idl-meta/tests/snapshots/serde__service_unit.snap new file mode 100644 index 000000000..9fb8cba55 --- /dev/null +++ b/rs/idl-meta/tests/snapshots/serde__service_unit.snap @@ -0,0 +1,176 @@ +--- +source: rs/idl-meta/tests/serde.rs +expression: serialized +--- +{ + "name": "ThisThat", + "funcs": [ + { + "name": "DoThis", + "params": [ + { + "name": "p1", + "type": "u32" + }, + { + "name": "p2", + "type": "String" + }, + { + "name": "p3", + "type": { + "kind": "tuple", + "types": [ + { + "kind": "named", + "name": "Option", + "generics": [ + "H160" + ] + }, + { + "kind": "named", + "name": "NonZero", + "generics": [ + "u8" + ] + } + ] + } + }, + { + "name": "p4", + "type": { + "kind": "named", + "name": "TupleStruct" + } + } + ], + "output": { + "kind": "tuple", + "types": [ + "String", + "u32" + ] + }, + "throws": { + "kind": "tuple", + "types": [ + "String" + ] + }, + "kind": "command", + "docs": [ + "Some func", + "With multiline doc" + ] + } + ], + "types": [ + { + "name": "DoThatParam", + "kind": "struct", + "fields": [ + { + "name": "p1", + "type": "u32", + "docs": [ + "Parametr p1: u32" + ] + }, + { + "name": "p2", + "type": "ActorId" + }, + { + "name": "p3", + "type": { + "kind": "named", + "name": "ManyVariants" + } + } + ] + }, + { + "name": "ManyVariants", + "kind": "enum", + "variants": [ + { + "name": "One", + "fields": [] + }, + { + "name": "Two", + "fields": [ + { + "type": "u32" + } + ] + }, + { + "name": "Three", + "fields": [ + { + "type": { + "kind": "named", + "name": "Option", + "generics": [ + "u32" + ] + } + } + ] + }, + { + "name": "Four", + "fields": [ + { + "name": "a", + "type": "u32" + }, + { + "name": "b", + "type": { + "kind": "named", + "name": "Option", + "generics": [ + "u16" + ] + } + } + ] + }, + { + "name": "Five", + "fields": [ + { + "type": "String" + }, + { + "type": "H256", + "annotations": [ + [ + "key", + "value" + ] + ] + } + ] + }, + { + "name": "Six", + "fields": [ + { + "type": { + "kind": "tuple", + "types": [ + "u32" + ] + } + } + ] + } + ] + } + ] +} diff --git a/rs/idl-meta/tests/snapshots/serde__type_enum.snap b/rs/idl-meta/tests/snapshots/serde__type_enum.snap new file mode 100644 index 000000000..7bd7fe651 --- /dev/null +++ b/rs/idl-meta/tests/snapshots/serde__type_enum.snap @@ -0,0 +1,142 @@ +--- +source: rs/idl-meta/tests/serde.rs +expression: serialized +--- +{ + "name": "SomeType", + "type_params": [ + { + "name": "T1" + }, + { + "name": "T2" + } + ], + "kind": "enum", + "variants": [ + { + "name": "Unit", + "fields": [], + "docs": [ + "Unit-like Variant" + ] + }, + { + "name": "Tuple", + "fields": [ + { + "type": "u32" + } + ], + "docs": [ + "Tuple-like Variant" + ] + }, + { + "name": "TupleWithDocs", + "fields": [ + { + "type": { + "kind": "named", + "name": "Option", + "generics": [ + "u32" + ] + }, + "docs": [ + "Some docs" + ] + }, + { + "type": { + "kind": "tuple", + "types": [ + "u32", + "u32" + ] + }, + "docs": [ + "Some docs" + ] + } + ], + "docs": [ + "Tuple-like Variant with field docs" + ] + }, + { + "name": "Struct", + "fields": [ + { + "name": "p1", + "type": { + "kind": "named", + "name": "Option", + "generics": [ + "u32" + ] + } + }, + { + "name": "p2", + "type": { + "kind": "tuple", + "types": [ + "u32", + "u32" + ] + } + } + ], + "docs": [ + "Struct-like Variant" + ] + }, + { + "name": "GenericStruct", + "fields": [ + { + "name": "p1", + "type": { + "kind": "named", + "name": "Option", + "generics": [ + { + "kind": "named", + "name": "T1" + } + ] + } + }, + { + "name": "p2", + "type": { + "kind": "tuple", + "types": [ + { + "kind": "named", + "name": "T2" + }, + { + "kind": "named", + "name": "T2" + } + ] + } + } + ], + "docs": [ + "Generic Struct-like Variant" + ] + } + ], + "docs": [ + "SomeType Enum" + ], + "annotations": [ + [ + "rusttype", + "sails-idl-meta::SomeType" + ] + ] +}