Repository: oxidecomputer/typify
Pull request #419 (2023-10-06 05:31:02)

Handle unsatisfiable schemas by generating an empty enum
```rust
enum Never {}
```

... why? because some schemas are jerks.


Patch:
diff --git a/typify-impl/src/convert.rs b/typify-impl/src/convert.rs
index 2d85b85..f3cb022 100644
--- a/typify-impl/src/convert.rs
+++ b/typify-impl/src/convert.rs
@@ -39,8 +39,7 @@ impl TypeSpace {
             }
 
             Schema::Bool(true) => self.convert_permissive(&None),
-            // TODO Not sure what to do here... need to return something toxic?
-            Schema::Bool(false) => todo!(),
+            Schema::Bool(false) => self.convert_never(type_name),
         }
     }
 
@@ -1537,6 +1536,21 @@ impl TypeSpace {
         Ok((TypeEntryDetails::JsonValue.into(), metadata))
     }
 
+    fn convert_never<'a>(
+        &mut self,
+        type_name: Name,
+    ) -> Result<(TypeEntry, &'a Option<Box<Metadata>>)> {
+        let ty = TypeEntryEnum::from_metadata(
+            self,
+            type_name,
+            &None,
+            EnumTagType::External,
+            vec![],
+            true,
+        );
+        Ok((ty, &None))
+    }
+
     fn convert_typed_enum<'a>(
         &mut self,
         type_name: Name,
diff --git a/typify-impl/src/type_entry.rs b/typify-impl/src/type_entry.rs
index 690c0a0..3aaf77e 100644
--- a/typify-impl/src/type_entry.rs
+++ b/typify-impl/src/type_entry.rs
@@ -227,6 +227,7 @@ impl TypeEntryEnum {
         self.bespoke_impls = [
             // Not untagged with all simple variants.
             (self.tag_type != EnumTagType::Untagged
+                && !self.variants.is_empty()
                 && self
                     .variants
                     .iter()


Test patch:
diff --git a/typify/tests/schemas/various-enums.json b/typify/tests/schemas/various-enums.json
index 5e088fd..be8c7db 100644
--- a/typify/tests/schemas/various-enums.json
+++ b/typify/tests/schemas/various-enums.json
@@ -100,7 +100,9 @@
       "properties": {
         "prop": {
           "type": "object",
-          "enum": [{}]
+          "enum": [
+            {}
+          ]
         }
       }
     },
@@ -159,6 +161,10 @@
     },
     "ReferenceDef": {
       "type": "string"
+    },
+    "Never": false,
+    "NeverEver": {
+      "not": true
     }
   }
-}
+}
\ No newline at end of file
diff --git a/typify/tests/schemas/various-enums.rs b/typify/tests/schemas/various-enums.rs
index 293e49d..8098dcd 100644
--- a/typify/tests/schemas/various-enums.rs
+++ b/typify/tests/schemas/various-enums.rs
@@ -316,6 +316,22 @@ impl From<std::collections::HashMap<String, i64>> for JankNames {
         Self::Variant2(value)
     }
 }
+#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
+#[serde(deny_unknown_fields)]
+pub enum Never {}
+impl From<&Never> for Never {
+    fn from(value: &Never) -> Self {
+        value.clone()
+    }
+}
+#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
+#[serde(deny_unknown_fields)]
+pub enum NeverEver {}
+impl From<&NeverEver> for NeverEver {
+    fn from(value: &NeverEver) -> Self {
+        value.clone()
+    }
+}
 #[derive(Clone, Debug, Deserialize, Serialize)]
 pub struct NullStringEnumWithUnknownFormat(pub Option<NullStringEnumWithUnknownFormatInner>);
 impl std::ops::Deref for NullStringEnumWithUnknownFormat {