use crate::prelude::*; #[derive(JsonSchema, Deserialize, Serialize, Default)] #[serde(default)] struct MyStruct { integer: u32, boolean: bool, option_string: Option, #[serde(skip_serializing_if = "str::is_empty")] string_skip_empty: String, #[serde(with = "struct_2_as_str")] #[schemars(with = "str", pattern(r"^\d+ (true|false)$"))] struct2: MyStruct2, #[serde(skip_serializing)] not_serialize: NotSerialize, } #[derive(JsonSchema, Deserialize, Serialize, Default)] #[serde(default = "ten_and_true")] struct MyStruct2 { #[serde(default = "six")] integer: u32, boolean: bool, } #[allow(dead_code)] #[derive(JsonSchema, Deserialize, Default)] struct NotSerialize(i8); mod struct_2_as_str { use super::MyStruct2; pub(super) fn serialize(value: &MyStruct2, ser: S) -> Result where S: serde::Serializer, { ser.collect_str(&format_args!("{} {}", value.integer, value.boolean)) } pub(super) fn deserialize<'de, D>(deser: D) -> Result where D: serde::Deserializer<'de>, { use serde::de::{Deserialize, Error}; let error = || Error::custom("invalid string"); let (i, b) = <&str>::deserialize(deser)? .split_once(' ') .ok_or_else(error)?; Ok(MyStruct2 { integer: i.parse().map_err(|_| error())?, boolean: b.parse().map_err(|_| error())?, }) } } fn ten_and_true() -> MyStruct2 { MyStruct2 { integer: 10, boolean: true, } } fn six() -> u32 { 6 } #[test] fn default_fields() { test!(MyStruct) .assert_snapshot() .assert_allows_ser_roundtrip([ MyStruct::default(), MyStruct { integer: 123, boolean: true, option_string: Some("test".into()), string_skip_empty: "test".into(), struct2: ten_and_true(), not_serialize: NotSerialize(42), }, ]) .assert_allows_de_roundtrip([ json!({}), json!({ "not_serialize": 127 }) ]) .assert_rejects_de([ json!({ "not_serialize": "a string" }) ]) .assert_matches_de_roundtrip(arbitrary_values_except( Value::is_array, "structs with `#derive(Deserialize)` can technically be deserialized from sequences, but that's not intended to be used via JSON, so schemars ignores it", )); }