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

Bump trybuild from 1.0.90 to 1.0.91
Bumps [trybuild](https://github.com/dtolnay/trybuild) from 1.0.90 to 1.0.91.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/dtolnay/trybuild/releases">trybuild's releases</a>.</em></p>
<blockquote>
<h2>1.0.91</h2>
<ul>
<li>Update required Rust version to 1.70 (<a href="https://redirect.github.com/dtolnay/trybuild/issues/262">#262</a>, thanks <a href="https://github.com/csnover"><code>@​csnover</code></a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/dtolnay/trybuild/commit/bad69500066b3d7abfa524ba3ac066fe61851dae"><code>bad6950</code></a> Release 1.0.91</li>
<li><a href="https://github.com/dtolnay/trybuild/commit/7a49c7b00a0db36502a3a172d44036ee52980b1e"><code>7a49c7b</code></a> Merge pull request <a href="https://redirect.github.com/dtolnay/trybuild/issues/262">#262</a> from csnover/fix-msrv</li>
<li><a href="https://github.com/dtolnay/trybuild/commit/4fc90bf70f4744a250dfb8804479f88c188de41b"><code>4fc90bf</code></a> Update MSRV to reflect changes to dependencies</li>
<li><a href="https://github.com/dtolnay/trybuild/commit/3db4c4c4bbec3a19b607f933e2c18c2b0a7f8510"><code>3db4c4c</code></a> Explicitly install a Rust toolchain for cargo-outdated job</li>
<li>See full diff in <a href="https://github.com/dtolnay/trybuild/compare/1.0.90...1.0.91">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=trybuild&package-manager=cargo&previous-version=1.0.90&new-version=1.0.91)](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..b006c64 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"
@@ -1169,9 +1163,9 @@ dependencies = [
 
 [[package]]
 name = "trybuild"
-version = "1.0.90"
+version = "1.0.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2aa6f84ec205ebf87fb7a0abdbcd1467fa5af0e86878eb6d888b78ecbb10b6d5"
+checksum = "8ad7eb6319ebadebca3dacf1f85a93bc54b73dd81b9036795f73de7ddfe27d5a"
 dependencies = [
  "glob",
  "once_cell",
@@ -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..42bac30 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"
@@ -28,5 +28,5 @@ rustfmt-wrapper = "0.2.1"
 schemars = "0.8.16"
 serde = "1.0.197"
 serde_json = "1.0.114"
-trybuild = "1.0.90"
+trybuild = "1.0.91"
 uuid = { version = "1.8.0", features = ["serde"] }


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> {