Repository: oxidecomputer/typify (rust)

Issue:
date-time with default panics
This schema causes a panic:

```json
    {
      "type": "object",
      "properties": {
        "when": {
          "type": "string",
          "format": "date-time",
          "default": "1970-01-01T00:00:00Z"
        }
      }
    }
```

`"DateTime<chrono" is not a valid Ident`

If we remove the `default`, it's fine. Why? This:
https://github.com/oxidecomputer/typify/blob/99ec168e1f4c4dc37bcc79759dd7f4b3d904102f/typify-impl/src/value.rs#L141-L151

Instead we need to do what's done here:
https://github.com/oxidecomputer/typify/blob/99ec168e1f4c4dc37bcc79759dd7f4b3d904102f/typify-impl/src/type_entry.rs#L1617-L1623

Pull request:
Fix panic with date-time and default value
Closes #539

Patch:
diff --git a/typify-impl/src/value.rs b/typify-impl/src/value.rs
index a9b9b7a..3e20f10 100644
--- a/typify-impl/src/value.rs
+++ b/typify-impl/src/value.rs
@@ -1,4 +1,4 @@
-// Copyright 2022 Oxide Computer Company
+// Copyright 2024 Oxide Computer Company
 
 use std::{collections::BTreeMap, str::FromStr};
 
@@ -139,15 +139,13 @@ impl TypeEntry {
             TypeEntryDetails::Native(TypeEntryNative { type_name, .. }) => {
                 // Serialize value to a string... not hard.
                 let text = value.to_string();
-                let type_path = type_name
-                    .split("::")
-                    .map(|component| format_ident!("{}", component));
+                let type_path = syn::parse_str::<syn::TypePath>(type_name).unwrap();
 
                 // Deserialize the string to the type; the unwrap() is
                 // unfortunate, but unavoidable without getting in the
                 // underpants of the serialized form of these built-in types.
                 quote! {
-                    serde_json::from_str::< #( #type_path )::* >(#text).unwrap()
+                    serde_json::from_str::< #type_path >(#text).unwrap()
                 }
             }
             TypeEntryDetails::JsonValue => {


Test patch:
diff --git a/typify/tests/schemas/types-with-defaults.json b/typify/tests/schemas/types-with-defaults.json
index f77a1da..c230306 100644
--- a/typify/tests/schemas/types-with-defaults.json
+++ b/typify/tests/schemas/types-with-defaults.json
@@ -28,6 +28,16 @@
           ]
         }
       }
+    },
+    "Doodad": {
+      "type": "object",
+      "properties": {
+        "when": {
+          "type": "string",
+          "format": "date-time",
+          "default": "1970-01-01T00:00:00Z"
+        }
+      }
     }
   }
 }
\ No newline at end of file
diff --git a/typify/tests/schemas/types-with-defaults.rs b/typify/tests/schemas/types-with-defaults.rs
index 6ea59fa..471fe0d 100644
--- a/typify/tests/schemas/types-with-defaults.rs
+++ b/typify/tests/schemas/types-with-defaults.rs
@@ -26,6 +26,33 @@ pub mod error {
         }
     }
 }
+#[doc = "Doodad"]
+#[doc = r""]
+#[doc = r" <details><summary>JSON schema</summary>"]
+#[doc = r""]
+#[doc = r" ```json"]
+#[doc = "{"]
+#[doc = "  \"type\": \"object\","]
+#[doc = "  \"properties\": {"]
+#[doc = "    \"when\": {"]
+#[doc = "      \"default\": \"1970-01-01T00:00:00Z\","]
+#[doc = "      \"type\": \"string\","]
+#[doc = "      \"format\": \"date-time\""]
+#[doc = "    }"]
+#[doc = "  }"]
+#[doc = "}"]
+#[doc = r" ```"]
+#[doc = r" </details>"]
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub struct Doodad {
+    #[serde(default = "defaults::doodad_when")]
+    pub when: chrono::DateTime<chrono::offset::Utc>,
+}
+impl From<&Doodad> for Doodad {
+    fn from(value: &Doodad) -> Self {
+        value.clone()
+    }
+}
 #[doc = "TestBed"]
 #[doc = r""]
 #[doc = r" <details><summary>JSON schema</summary>"]
@@ -74,6 +101,10 @@ impl From<&TestBed> for TestBed {
 }
 #[doc = r" Generation of default values for serde."]
 pub mod defaults {
+    pub(super) fn doodad_when() -> chrono::DateTime<chrono::offset::Utc> {
+        serde_json::from_str::<chrono::DateTime<chrono::offset::Utc>>("\"1970-01-01T00:00:00Z\"")
+            .unwrap()
+    }
     pub(super) fn test_bed_any() -> Vec<serde_json::Value> {
         vec![
             serde_json::from_str::<serde_json::Value>("[8,6,7]").unwrap(),