diff --git a/typify-impl/src/defaults.rs b/typify-impl/src/defaults.rs index 658b2185..6a343575 100644 --- a/typify-impl/src/defaults.rs +++ b/typify-impl/src/defaults.rs @@ -137,7 +137,8 @@ impl TypeEntry { /// The return value indicates whether the default is the "intrinsic", /// typical default for the given type, can be handled by generic function, /// or requires a bespoke function to generate the value. This contains - /// additional validation logic compared with [`value()`] but is able to skip the parts where we actually emit code. + /// additional validation logic compared with [`value()`] but is able to + /// skip the parts where we actually emit code. /// /// [`Value`]: serde_json::Value pub(crate) fn validate_value( @@ -172,7 +173,11 @@ impl TypeEntry { } TypeEntryDetails::Newtype(TypeEntryNewtype { type_id, .. }) => { - validate_type_id(type_id, type_space, default) + // Validate the inner type, but irrespective of the result, + // we'll need a custom function to make a default of the outer + // newtype. + let _ = validate_type_id(type_id, type_space, default)?; + Ok(DefaultKind::Specific) } TypeEntryDetails::Option(type_id) => { if let serde_json::Value::Null = default { diff --git a/typify-impl/src/lib.rs b/typify-impl/src/lib.rs index a10b2afe..a9cf8c24 100644 --- a/typify-impl/src/lib.rs +++ b/typify-impl/src/lib.rs @@ -7,7 +7,7 @@ use std::collections::{BTreeMap, BTreeSet}; use conversions::SchemaCache; -use log::info; +use log::{debug, info}; use output::OutputSpace; use proc_macro2::TokenStream; use quote::{format_ident, quote, ToTokens}; @@ -696,6 +696,7 @@ impl TypeSpace { for index in base_id..self.next_id { let type_id = TypeId(index); let mut type_entry = self.id_to_entry.get(&type_id).unwrap().clone(); + debug!("finalizing type entry: {} {:#?}", index, &type_entry); type_entry.finalize(self)?; self.id_to_entry.insert(type_id, type_entry); } diff --git a/typify/tests/schemas/types-with-defaults.json b/typify/tests/schemas/types-with-defaults.json index fb7c714e..f3666710 100644 --- a/typify/tests/schemas/types-with-defaults.json +++ b/typify/tests/schemas/types-with-defaults.json @@ -85,6 +85,22 @@ "default": 1 } } + }, + "UInt": { + "type": "integer" + }, + "UIntContainer": { + "type": "object", + "properties": { + "max_path": { + "default": 1, + "allOf": [ + { + "$ref": "#/$definitions/UInt" + } + ] + } + } } } } diff --git a/typify/tests/schemas/types-with-defaults.rs b/typify/tests/schemas/types-with-defaults.rs index 8e5b0843..383ece76 100644 --- a/typify/tests/schemas/types-with-defaults.rs +++ b/typify/tests/schemas/types-with-defaults.rs @@ -262,6 +262,95 @@ impl ThingWithDefaults { Default::default() } } +#[doc = "`UInt`"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"type\": \"integer\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +#[serde(transparent)] +pub struct UInt(pub i64); +impl ::std::ops::Deref for UInt { + type Target = i64; + fn deref(&self) -> &i64 { + &self.0 + } +} +impl ::std::convert::From for i64 { + fn from(value: UInt) -> Self { + value.0 + } +} +impl ::std::convert::From for UInt { + fn from(value: i64) -> Self { + Self(value) + } +} +impl ::std::str::FromStr for UInt { + type Err = ::Err; + fn from_str(value: &str) -> ::std::result::Result { + Ok(Self(value.parse()?)) + } +} +impl ::std::convert::TryFrom<&str> for UInt { + type Error = ::Err; + fn try_from(value: &str) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom for UInt { + type Error = ::Err; + fn try_from(value: String) -> ::std::result::Result { + value.parse() + } +} +impl ::std::fmt::Display for UInt { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + self.0.fmt(f) + } +} +#[doc = "`UIntContainer`"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"max_path\": {"] +#[doc = " \"default\": 1,"] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$definitions/UInt\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct UIntContainer { + #[serde(default = "defaults::u_int_container_max_path")] + pub max_path: UInt, +} +impl ::std::default::Default for UIntContainer { + fn default() -> Self { + Self { + max_path: defaults::u_int_container_max_path(), + } + } +} +impl UIntContainer { + pub fn builder() -> builder::UIntContainer { + Default::default() + } +} #[doc = r" Types for composing complex structures."] pub mod builder { #[derive(Clone, Debug)] @@ -527,6 +616,46 @@ pub mod builder { } } } + #[derive(Clone, Debug)] + pub struct UIntContainer { + max_path: ::std::result::Result, + } + impl ::std::default::Default for UIntContainer { + fn default() -> Self { + Self { + max_path: Ok(super::defaults::u_int_container_max_path()), + } + } + } + impl UIntContainer { + pub fn max_path(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.max_path = value + .try_into() + .map_err(|e| format!("error converting supplied value for max_path: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::UIntContainer { + type Error = super::error::ConversionError; + fn try_from( + value: UIntContainer, + ) -> ::std::result::Result { + Ok(Self { + max_path: value.max_path?, + }) + } + } + impl ::std::convert::From for UIntContainer { + fn from(value: super::UIntContainer) -> Self { + Self { + max_path: Ok(value.max_path), + } + } + } } #[doc = r" Generation of default values for serde."] pub mod defaults { @@ -556,5 +685,8 @@ pub mod defaults { pub(super) fn test_bed_id() -> ::uuid::Uuid { ::serde_json::from_str::<::uuid::Uuid>("\"abc123-is-this-a-uuid\"").unwrap() } + pub(super) fn u_int_container_max_path() -> super::UInt { + super::UInt(1_i64) + } } fn main() {}