Repository: oxidecomputer/typify
Pull request #545 (2024-04-01 13:53:01)

Bump chrono from 0.4.35 to 0.4.37
Bumps [chrono](https://github.com/chronotope/chrono) from 0.4.35 to 0.4.37.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/chronotope/chrono/releases">chrono's releases</a>.</em></p>
<blockquote>
<h2>v0.4.37</h2>
<p>Version 0.4.36 introduced an unexpected breaking change and was yanked. In it <code>LocalResult</code> was renamed to <code>MappedLocalTime</code> to avoid the impression that it is a <code>Result</code> type were some of the results are errors. For backwards compatibility a type alias with the old name was added.</p>
<p>As it turns out there is one case where a type alias behaves differently from the regular enum: you can't import enum variants from a type alias with <code>use chrono::LocalResult::*</code>. With 0.4.37 we make the new name <code>MappedLocalTime</code> the alias, but keep using it in function signatures and the documentation as much as possible.</p>
<p>See also the release notes of <a href="https://github.com/chronotope/chrono/releases/tag/v0.4.36">chrono 0.4.36</a> from yesterday for the yanked release.</p>
<h2>v0.4.36</h2>
<p>This release un-deprecates the methods on <code>TimeDelta</code> that were deprecated with the 0.4.35 release because of the churn they are causing for the ecosystem.</p>
<p>New is the <code>DateTime::with_time()</code> method. As an example of when it is useful:</p>
<pre lang="rust"><code>use chrono::{Local, NaiveTime};
// Today at 12:00:00
let today_noon = Local::now().with_time(NaiveTime::from_hms_opt(12, 0, 0).unwrap());
</code></pre>
<h1>Additions</h1>
<ul>
<li>Add <code>DateTime::with_time()</code> (<a href="https://redirect.github.com/chronotope/chrono/issues/1510">#1510</a>)</li>
</ul>
<h1>Deprecations</h1>
<ul>
<li>Revert <code>TimeDelta</code> deprecations (<a href="https://redirect.github.com/chronotope/chrono/issues/1543">#1543</a>)</li>
<li>Deprecate <code>TimeStamp::timestamp_subsec_nanos</code>, which was missed in the 0.4.35 release (<a href="https://redirect.github.com/chronotope/chrono/issues/1486">#1486</a>)</li>
</ul>
<h1>Documentation</h1>
<ul>
<li>Correct version number of deprecation notices (<a href="https://redirect.github.com/chronotope/chrono/issues/1486">#1486</a>)</li>
<li>Fix some typos (<a href="https://redirect.github.com/chronotope/chrono/issues/1505">#1505</a>)</li>
<li>Slightly improve serde documentation (<a href="https://redirect.github.com/chronotope/chrono/issues/1519">#1519</a>)</li>
<li>Main documentation: simplify links and reflow text (<a href="https://redirect.github.com/chronotope/chrono/issues/1535">#1535</a>)</li>
</ul>
<h1>Internal</h1>
<ul>
<li>CI: Lint benchmarks (<a href="https://redirect.github.com/chronotope/chrono/issues/1489">#1489</a>)</li>
<li>Remove unnessary <code>Copy</code> and <code>Send</code> impls (<a href="https://redirect.github.com/chronotope/chrono/issues/1492">#1492</a>, thanks <a href="https://github.com/erickt"><code>@​erickt</code></a>)</li>
<li>Backport streamlined <code>NaiveDate</code> unit tests (<a href="https://redirect.github.com/chronotope/chrono/issues/1500">#1500</a>, thanks <a href="https://github.com/Zomtir"><code>@​Zomtir</code></a>)</li>
<li>Rename <code>LocalResult</code> to <code>TzResolution</code>, add alias (<a href="https://redirect.github.com/chronotope/chrono/issues/1501">#1501</a>)</li>
<li>Update windows-bindgen to 0.55 (<a href="https://redirect.github.com/chronotope/chrono/issues/1504">#1504</a>)</li>
<li>Avoid duplicate imports, which generate warnings on nightly (<a href="https://redirect.github.com/chronotope/chrono/issues/1507">#1507</a>)</li>
<li>Add extra debug assertions to <code>NaiveDate::from_yof</code> (<a href="https://redirect.github.com/chronotope/chrono/issues/1518">#1518</a>)</li>
<li>Some small simplifications to <code>DateTime::date_naive</code> and <code>NaiveDate::diff_months</code> (<a href="https://redirect.github.com/chronotope/chrono/issues/1530">#1530</a>)</li>
<li>Remove <code>unwrap</code> in Unix <code>Local</code> type (<a href="https://redirect.github.com/chronotope/chrono/issues/1533">#1533</a>)</li>
<li>Use different method to ignore feature-dependent doctests (<a href="https://redirect.github.com/chronotope/chrono/issues/1534">#1534</a>)</li>
</ul>
<p>Thanks to all contributors on behalf of the chrono team, <a href="https://github.com/djc"><code>@​djc</code></a> and <a href="https://github.com/pitdicker"><code>@​pitdicker</code></a>!</p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/chronotope/chrono/commit/7d62045ec4cd667e240fde899a99458bf8eae1f1"><code>7d62045</code></a> Prepare 0.4.37</li>
<li><a href="https://github.com/chronotope/chrono/commit/6857d00070378037392fd9f029ccbf78a19ef2c3"><code>6857d00</code></a> Hide re-export of <code>LocalResult</code> in docs</li>
<li><a href="https://github.com/chronotope/chrono/commit/9e22e48d156d4c581e4f3d54cd8b2dcf77b5ae0a"><code>9e22e48</code></a> Swap <code>MappedLocalTime</code> and <code>LocalResult</code> type alias</li>
<li><a href="https://github.com/chronotope/chrono/commit/ca3c3b6293c20284405b1fa6c6895c7f2a33caf9"><code>ca3c3b6</code></a> Prepare 0.4.36</li>
<li><a href="https://github.com/chronotope/chrono/commit/1850198da9f91fb0f4181e30947cbecb944cde74"><code>1850198</code></a> Revert <code>TimeDelta</code> deprecations</li>
<li><a href="https://github.com/chronotope/chrono/commit/e05ba8b9c2a98943d129e664c7615bd3724e069e"><code>e05ba8b</code></a> Add <code>MappedLocalTime::and_then</code></li>
<li><a href="https://github.com/chronotope/chrono/commit/3adfd88ce05756e3bd0baa7e008abbe6d5b61076"><code>3adfd88</code></a> Main documentation: simplify links and reflow text</li>
<li><a href="https://github.com/chronotope/chrono/commit/1e8df65f47577c0db3e2790660b00d728145cde2"><code>1e8df65</code></a> Rustfmt doc comments</li>
<li><a href="https://github.com/chronotope/chrono/commit/1b578597827d0a850acb81b9cbbd1835b2141a8d"><code>1b57859</code></a> Run doctests with <code>alloc</code> feature if possible</li>
<li><a href="https://github.com/chronotope/chrono/commit/6f2c7ccabd94e78f4bbf585085b54e21eb6e99fe"><code>6f2c7cc</code></a> Use different method to run feature-dependent doctests</li>
<li>Additional commits viewable in <a href="https://github.com/chronotope/chrono/compare/v0.4.35...v0.4.37">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=chrono&package-manager=cargo&previous-version=0.4.35&new-version=0.4.37)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 13b5f90..81b1fbb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -206,9 +206,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chrono"
-version = "0.4.35"
+version = "0.4.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a"
+checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e"
 dependencies = [
  "android-tzdata",
  "iana-time-zone",
@@ -221,9 +221,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.5.3"
+version = "4.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813"
+checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -243,11 +243,11 @@ dependencies = [
 
 [[package]]
 name = "clap_derive"
-version = "4.5.3"
+version = "4.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f"
+checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
 dependencies = [
- "heck 0.5.0",
+ "heck",
  "proc-macro2",
  "quote",
  "syn 2.0.55",
@@ -446,12 +446,6 @@ dependencies = [
  "allocator-api2",
 ]
 
-[[package]]
-name = "heck"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
-
 [[package]]
 name = "heck"
 version = "0.5.0"
@@ -1208,7 +1202,7 @@ version = "0.0.16"
 dependencies = [
  "env_logger",
  "expectorate",
- "heck 0.4.1",
+ "heck",
  "log",
  "paste",
  "proc-macro2",
diff --git a/cargo-typify/Cargo.toml b/cargo-typify/Cargo.toml
index 4aef1ed..5da943a 100644
--- a/cargo-typify/Cargo.toml
+++ b/cargo-typify/Cargo.toml
@@ -14,7 +14,7 @@ default-run = "cargo-typify"
 [dependencies]
 typify = { version = "0.0.16", path = "../typify" }
 
-clap = { version = "4.5.3", features = ["derive"] }
+clap = { version = "4.5.4", features = ["derive"] }
 color-eyre = "0.6"
 env_logger = "0.10"
 rustfmt-wrapper = "0.2.1"
diff --git a/typify-impl/Cargo.toml b/typify-impl/Cargo.toml
index de55253..aa56966 100644
--- a/typify-impl/Cargo.toml
+++ b/typify-impl/Cargo.toml
@@ -8,7 +8,7 @@ repository = "https://github.com/oxidecomputer/typify"
 readme = "../README.md"
 
 [dependencies]
-heck = "0.4.1"
+heck = "0.5.0"
 log = "0.4.21"
 proc-macro2 = "1.0.79"
 quote = "1.0.35"
diff --git a/typify-impl/src/value.rs b/typify-impl/src/value.rs
index 3e20f10..2c38ef2 100644
--- a/typify-impl/src/value.rs
+++ b/typify-impl/src/value.rs
@@ -377,6 +377,25 @@ fn value_for_struct_props(
 ) -> Option<Vec<TokenStream>> {
     let map = value.as_object()?;
 
+    let direct_props = properties.iter().filter_map(|prop| {
+        let name = match &prop.rename {
+            StructPropertyRename::None => &prop.name,
+            StructPropertyRename::Rename(rename) => rename,
+            StructPropertyRename::Flatten => return None,
+        };
+
+        let name_ident = format_ident!("{}", &prop.name);
+
+        if let Some(value) = map.get(name) {
+            let type_entry = type_space.id_to_entry.get(&prop.type_id).unwrap();
+            let prop_value = type_entry.output_value(type_space, value, scope)?;
+
+            Some(quote! { #name_ident: #prop_value })
+        } else {
+            Some(quote! { #name_ident: Default::default() })
+        }
+    });
+
     let prop_map = properties
         .iter()
         .filter_map(|prop| {
@@ -390,17 +409,6 @@ fn value_for_struct_props(
         })
         .collect::<BTreeMap<_, _>>();
 
-    let direct_props = map.iter().filter_map(|(name, value)| {
-        // It's okay if the property isn't in the prop_map... it must be part
-        // of one of the flattened properties.
-        let prop = prop_map.get(name)?;
-        let type_entry = type_space.id_to_entry.get(&prop.type_id).unwrap();
-        let prop_value = type_entry.output_value(type_space, value, scope)?;
-        let name_ident = format_ident!("{}", name);
-
-        Some(quote! { #name_ident: #prop_value })
-    });
-
     let extra_value = serde_json::Value::Object(
         map.clone()
             .into_iter()
@@ -622,7 +630,8 @@ mod tests {
                     super::Test {
                         a: "aaaa".to_string(),
                         b: 7_u32,
-                        c: Some("cccc".to_string())
+                        c: Some("cccc".to_string()),
+                        d: Default::default()
                     }
                 }
                 .to_string()
@@ -663,7 +672,8 @@ mod tests {
                     Test {
                         a: "aaaa".to_string(),
                         b: 7_u32,
-                        c: Some("cccc".to_string())
+                        c: Some("cccc".to_string()),
+                        d: Default::default()
                     }
                 }
                 .to_string()
diff --git a/typify/Cargo.toml b/typify/Cargo.toml
index 50c7845..5c3d9d4 100644
--- a/typify/Cargo.toml
+++ b/typify/Cargo.toml
@@ -18,7 +18,7 @@ typify-macro = { version = "0.0.16", path = "../typify-macro", optional = true }
 typify-impl = { version = "0.0.16", path = "../typify-impl" }
 
 [dev-dependencies]
-chrono = { version = "0.4.35", features = ["serde"] }
+chrono = { version = "0.4.37", features = ["serde"] }
 env_logger = "0.10.2"
 expectorate = "1.1.0"
 glob = "0.3.1"


Test patch:
diff --git a/typify/tests/schemas/types-with-defaults.json b/typify/tests/schemas/types-with-defaults.json
index c230306..7b7d18f 100644
--- a/typify/tests/schemas/types-with-defaults.json
+++ b/typify/tests/schemas/types-with-defaults.json
@@ -29,6 +29,27 @@
         }
       }
     },
+    "OuterThing": {
+      "type": "object",
+      "properties": {
+        "thing": {
+          "type": "object",
+          "title": "ThingWithDefaults",
+          "properties": {
+            "a": {
+              "type": "string"
+            },
+            "type": {
+              "type": "string"
+            }
+          },
+          "additionalProperties": false,
+          "default": {
+            "type": "bee"
+          }
+        }
+      }
+    },
     "Doodad": {
       "type": "object",
       "properties": {
diff --git a/typify/tests/schemas/types-with-defaults.rs b/typify/tests/schemas/types-with-defaults.rs
index 471fe0d..17d1749 100644
--- a/typify/tests/schemas/types-with-defaults.rs
+++ b/typify/tests/schemas/types-with-defaults.rs
@@ -53,6 +53,44 @@ impl From<&Doodad> for Doodad {
         value.clone()
     }
 }
+#[doc = "OuterThing"]
+#[doc = r""]
+#[doc = r" <details><summary>JSON schema</summary>"]
+#[doc = r""]
+#[doc = r" ```json"]
+#[doc = "{"]
+#[doc = "  \"type\": \"object\","]
+#[doc = "  \"properties\": {"]
+#[doc = "    \"thing\": {"]
+#[doc = "      \"title\": \"ThingWithDefaults\","]
+#[doc = "      \"default\": {"]
+#[doc = "        \"type\": \"bee\""]
+#[doc = "      },"]
+#[doc = "      \"type\": \"object\","]
+#[doc = "      \"properties\": {"]
+#[doc = "        \"a\": {"]
+#[doc = "          \"type\": \"string\""]
+#[doc = "        },"]
+#[doc = "        \"type\": {"]
+#[doc = "          \"type\": \"string\""]
+#[doc = "        }"]
+#[doc = "      },"]
+#[doc = "      \"additionalProperties\": false"]
+#[doc = "    }"]
+#[doc = "  }"]
+#[doc = "}"]
+#[doc = r" ```"]
+#[doc = r" </details>"]
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct OuterThing {
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub thing: Option<ThingWithDefaults>,
+}
+impl From<&OuterThing> for OuterThing {
+    fn from(value: &OuterThing) -> Self {
+        value.clone()
+    }
+}
 #[doc = "TestBed"]
 #[doc = r""]
 #[doc = r" <details><summary>JSON schema</summary>"]
@@ -99,6 +137,50 @@ impl From<&TestBed> for TestBed {
         value.clone()
     }
 }
+#[doc = "ThingWithDefaults"]
+#[doc = r""]
+#[doc = r" <details><summary>JSON schema</summary>"]
+#[doc = r""]
+#[doc = r" ```json"]
+#[doc = "{"]
+#[doc = "  \"title\": \"ThingWithDefaults\","]
+#[doc = "  \"default\": {"]
+#[doc = "    \"type\": \"bee\""]
+#[doc = "  },"]
+#[doc = "  \"type\": \"object\","]
+#[doc = "  \"properties\": {"]
+#[doc = "    \"a\": {"]
+#[doc = "      \"type\": \"string\""]
+#[doc = "    },"]
+#[doc = "    \"type\": {"]
+#[doc = "      \"type\": \"string\""]
+#[doc = "    }"]
+#[doc = "  },"]
+#[doc = "  \"additionalProperties\": false"]
+#[doc = "}"]
+#[doc = r" ```"]
+#[doc = r" </details>"]
+#[derive(Clone, Debug, Deserialize, Serialize)]
+#[serde(deny_unknown_fields)]
+pub struct ThingWithDefaults {
+    #[serde(default, skip_serializing_if = "Option::is_none")]
+    pub a: Option<String>,
+    #[serde(rename = "type", default, skip_serializing_if = "Option::is_none")]
+    pub type_: Option<String>,
+}
+impl From<&ThingWithDefaults> for ThingWithDefaults {
+    fn from(value: &ThingWithDefaults) -> Self {
+        value.clone()
+    }
+}
+impl Default for ThingWithDefaults {
+    fn default() -> Self {
+        ThingWithDefaults {
+            a: Default::default(),
+            type_: Some("bee".to_string()),
+        }
+    }
+}
 #[doc = r" Generation of default values for serde."]
 pub mod defaults {
     pub(super) fn doodad_when() -> chrono::DateTime<chrono::offset::Utc> {