diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c91cb5..161c0d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +#### 🐞 Fixes + +- More serde optimizations and fixes. + ## 0.17.2 #### 🚀 Updates diff --git a/crates/types/src/arrays.rs b/crates/types/src/arrays.rs index 90d7e71..0d45439 100644 --- a/crates/types/src/arrays.rs +++ b/crates/types/src/arrays.rs @@ -4,24 +4,42 @@ use std::collections::{BTreeSet, HashSet}; #[derive(Clone, Debug, Default, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct ArrayType { - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub contains: Option, pub items_type: Box, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub max_contains: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub max_length: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub min_contains: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub min_length: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub unique: Option, } diff --git a/crates/types/src/bools.rs b/crates/types/src/bools.rs index 888046b..392deb9 100644 --- a/crates/types/src/bools.rs +++ b/crates/types/src/bools.rs @@ -3,7 +3,10 @@ use crate::*; #[derive(Clone, Debug, Default, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct BooleanType { - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub default: Option, } diff --git a/crates/types/src/enums.rs b/crates/types/src/enums.rs index 76d6014..720bc72 100644 --- a/crates/types/src/enums.rs +++ b/crates/types/src/enums.rs @@ -4,12 +4,18 @@ pub use indexmap::IndexMap; #[derive(Clone, Debug, Default, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct EnumType { - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub default_index: Option, pub values: Vec, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub variants: Option>>, } diff --git a/crates/types/src/literals.rs b/crates/types/src/literals.rs index 6192652..2ffa831 100644 --- a/crates/types/src/literals.rs +++ b/crates/types/src/literals.rs @@ -13,7 +13,10 @@ pub enum LiteralValue { #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct LiteralType { - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub format: Option, pub value: LiteralValue, diff --git a/crates/types/src/numbers.rs b/crates/types/src/numbers.rs index 6cd6294..a96aaa9 100644 --- a/crates/types/src/numbers.rs +++ b/crates/types/src/numbers.rs @@ -30,30 +30,54 @@ impl IntegerKind { #[derive(Clone, Debug, Default, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct IntegerType { - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub default: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub enum_values: Option>, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub format: Option, pub kind: IntegerKind, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub max: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub max_exclusive: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub min: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub min_exclusive: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub multiple_of: Option, } @@ -124,33 +148,60 @@ pub enum FloatKind { #[derive(Clone, Debug, Default, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct FloatType { - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub default: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub enum_values: Option>, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub format: Option, pub kind: FloatKind, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub max: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub max_exclusive: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub min: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub min_exclusive: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub multiple_of: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub name: Option, } diff --git a/crates/types/src/objects.rs b/crates/types/src/objects.rs index 532a43c..90d0162 100644 --- a/crates/types/src/objects.rs +++ b/crates/types/src/objects.rs @@ -6,13 +6,22 @@ use std::collections::{BTreeMap, HashMap}; pub struct ObjectType { pub key_type: Box, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub max_length: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub min_length: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub required: Option>, pub value_type: Box, diff --git a/crates/types/src/schema.rs b/crates/types/src/schema.rs index 0a6e576..b96e304 100644 --- a/crates/types/src/schema.rs +++ b/crates/types/src/schema.rs @@ -5,16 +5,25 @@ use std::ops::{Deref, DerefMut}; #[derive(Clone, Debug, Default, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct Schema { - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub deprecated: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub description: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub name: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing, default))] + #[cfg_attr(feature = "serde", serde(default, skip_serializing))] pub nullable: bool, pub ty: SchemaType, @@ -181,25 +190,47 @@ impl From for SchemaType { impl Schematic for Schema {} +fn is_false(value: &bool) -> bool { + !value +} + /// Describes the metadata and shape of a field within a struct or enum. #[derive(Clone, Debug, Default, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct SchemaField { - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub comment: Option, pub schema: Schema, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub deprecated: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub env_var: Option, + #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "is_false"))] pub hidden: bool, + + #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "is_false"))] pub nullable: bool, + + #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "is_false"))] pub optional: bool, + + #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "is_false"))] pub read_only: bool, + + #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "is_false"))] pub write_only: bool, } diff --git a/crates/types/src/schema_builder.rs b/crates/types/src/schema_builder.rs index c9d6be0..e8d41f7 100644 --- a/crates/types/src/schema_builder.rs +++ b/crates/types/src/schema_builder.rs @@ -16,6 +16,11 @@ pub struct SchemaBuilder { } impl SchemaBuilder { + /// Generate a schema from the provided type. + pub fn generate() -> Schema { + Self::build_root::() + } + /// Generate a schema from the provided type. pub fn build_root() -> Schema { let mut builder = SchemaBuilder::default(); diff --git a/crates/types/src/strings.rs b/crates/types/src/strings.rs index ed3a292..83f31bf 100644 --- a/crates/types/src/strings.rs +++ b/crates/types/src/strings.rs @@ -6,22 +6,40 @@ use std::time::{Duration, SystemTime}; #[derive(Clone, Debug, Default, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct StringType { - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub default: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub enum_values: Option>, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub format: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub max_length: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub min_length: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub pattern: Option, } diff --git a/crates/types/src/structs.rs b/crates/types/src/structs.rs index dfc8413..107a593 100644 --- a/crates/types/src/structs.rs +++ b/crates/types/src/structs.rs @@ -10,7 +10,10 @@ pub struct StructType { // This doesn't mean it's been partialized. pub partial: bool, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub required: Option>, } diff --git a/crates/types/src/unions.rs b/crates/types/src/unions.rs index 69b2f49..fd5c9b0 100644 --- a/crates/types/src/unions.rs +++ b/crates/types/src/unions.rs @@ -11,7 +11,10 @@ pub enum UnionOperator { #[derive(Clone, Debug, Default, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct UnionType { - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(default, skip_serializing_if = "Option::is_none") + )] pub default_index: Option, pub partial: bool, diff --git a/crates/types/tests/builder_test.rs b/crates/types/tests/builder_test.rs index 5f49d0a..e09b8e5 100644 --- a/crates/types/tests/builder_test.rs +++ b/crates/types/tests/builder_test.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] + use schematic_types::*; use starbase_sandbox::assert_snapshot; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; @@ -194,6 +196,43 @@ fn strings() { ); } +struct TestStruct { + str: String, + num: usize, +} + +impl Schematic for TestStruct { + fn schema_name() -> Option { + Some("TestStruct".into()) + } + + fn build_schema(mut schema: SchemaBuilder) -> Schema { + schema.structure(StructType::new([ + ("str".into(), schema.infer::()), + ("num".into(), schema.infer::()), + ])) + } +} + +#[test] +fn structs() { + assert_build!( + TestStruct, + SchemaType::Struct(Box::new(StructType::new([ + ( + "str".into(), + Schema::new(SchemaType::String(Box::default())) + ), + ( + "num".into(), + Schema::new(SchemaType::Integer(Box::new(IntegerType::new_kind( + IntegerKind::Usize + )))) + ), + ]))) + ); +} + #[test] fn tuples() { assert_build!( diff --git a/crates/types/tests/snapshots/builder_test__objects-2.snap b/crates/types/tests/snapshots/builder_test__objects-2.snap index 1e7968f..15b673c 100644 --- a/crates/types/tests/snapshots/builder_test__objects-2.snap +++ b/crates/types/tests/snapshots/builder_test__objects-2.snap @@ -21,12 +21,7 @@ expression: "& input" "ty": { "type": "Boolean" } - }, - "hidden": false, - "nullable": false, - "optional": false, - "read_only": false, - "write_only": false + } } }, "partial": false diff --git a/crates/types/tests/snapshots/builder_test__objects.snap b/crates/types/tests/snapshots/builder_test__objects.snap index 85ad91b..70ac7f1 100644 --- a/crates/types/tests/snapshots/builder_test__objects.snap +++ b/crates/types/tests/snapshots/builder_test__objects.snap @@ -20,12 +20,7 @@ expression: "& input" "ty": { "type": "Boolean" } - }, - "hidden": false, - "nullable": false, - "optional": false, - "read_only": false, - "write_only": false + } } }, "partial": false diff --git a/crates/types/tests/snapshots/builder_test__structs.snap b/crates/types/tests/snapshots/builder_test__structs.snap new file mode 100644 index 0000000..713cdaa --- /dev/null +++ b/crates/types/tests/snapshots/builder_test__structs.snap @@ -0,0 +1,28 @@ +--- +source: crates/types/tests/builder_test.rs +expression: "& input" +--- +{ + "name": "TestStruct", + "ty": { + "type": "Struct", + "fields": { + "num": { + "schema": { + "ty": { + "type": "Integer", + "kind": "Usize" + } + } + }, + "str": { + "schema": { + "ty": { + "type": "String" + } + } + } + }, + "partial": false + } +}