Repository: GREsau/schemars (rust)

Issue:
type annotations needed cannot infer type
## version

schemars = "1.0.3"


## reproduce

```rs
use {schemars::JsonSchema, serde::Deserialize, std::path::PathBuf};

#[derive(Debug, Deserialize, JsonSchema)]
pub enum Version {
    V1(),
}
```

## error

```
error[E0282]: type annotations needed
 --> path/to/config.rs:3:30
  |
3 | #[derive(Debug, Deserialize, JsonSchema)]
  |                              ^^^^^^^^^^ cannot infer type
  |
  = note: this error originates in the derive macro `JsonSchema` (in Nightly builds, run with -Z macro-backtrace for more info)


```


Pull request:
Fix derive for empty tuple variants
Fixes #455

Patch:
diff --git a/schemars_derive/src/schema_exprs.rs b/schemars_derive/src/schema_exprs.rs
index 65d4701..384affb 100644
--- a/schemars_derive/src/schema_exprs.rs
+++ b/schemars_derive/src/schema_exprs.rs
@@ -649,16 +649,22 @@ fn expr_for_tuple_struct(cont: &Container, fields: &[Field]) -> SchemaExpr {
         })
         .collect();
 
+    let max_len = fields.len();
+
+    // The length check must be done at runtime because it can vary based on the contract if any
+    // items have `skip_serializing` or `skip_deserializing` attributes.
     quote!({
-        let mut prefix_items = schemars::_private::alloc::vec::Vec::new();
+        let mut prefix_items = schemars::_private::alloc::vec::Vec::<schemars::_private::serde_json::Value>::with_capacity(#max_len);
         #(#fields)*
-        let len = schemars::_private::serde_json::Value::from(prefix_items.len());
+        let len = prefix_items.len();
 
         let mut map = schemars::_private::serde_json::Map::new();
         map.insert("type".into(), "array".into());
-        map.insert("prefixItems".into(), prefix_items.into());
-        map.insert("minItems".into(), len.clone());
-        map.insert("maxItems".into(), len);
+        if !prefix_items.is_empty() {
+            map.insert("prefixItems".into(), prefix_items.into());
+            map.insert("minItems".into(), len.into());
+        }
+        map.insert("maxItems".into(), len.into());
 
         schemars::Schema::from(map)
     })


Test patch:
diff --git a/schemars/tests/integration/enums.rs b/schemars/tests/integration/enums.rs
index e3c06bc..f24c96c 100644
--- a/schemars/tests/integration/enums.rs
+++ b/schemars/tests/integration/enums.rs
@@ -23,6 +23,7 @@ enum External {
         foo: i32,
         bar: bool,
     },
+    EmptyTuple(),
     Tuple(i32, bool),
     UnitTwo,
     #[serde(with = "unit_variant_as_u64")]
@@ -51,6 +52,8 @@ impl External {
                 foo: 123,
                 bar: true,
             },
+            // Ignored due to https://github.com/serde-rs/json/issues/1084
+            // Self::EmptyTuple(),
             Self::Tuple(456, false),
             Self::UnitTwo,
             Self::UnitAsInt,
@@ -68,6 +71,7 @@ enum Internal {
     StructNewType(Struct),
     Struct { foo: i32, bar: bool },
     // Internally-tagged enums don't support tuple variants
+    //  EmptyTuple(),
     //  Tuple(i32, bool),
     UnitTwo,
     // Internally-tagged enum variants don't support non-object "payloads"
@@ -98,6 +102,7 @@ impl Internal {
                 foo: 123,
                 bar: true,
             },
+            // Self::EmptyTuple(),
             // Self::Tuple(456, false),
             Self::UnitTwo,
             // Self::UnitAsInt,
@@ -117,6 +122,7 @@ enum Adjacent {
         foo: i32,
         bar: bool,
     },
+    EmptyTuple(),
     Tuple(i32, bool),
     UnitTwo,
     #[serde(with = "unit_variant_as_u64")]
@@ -145,6 +151,7 @@ impl Adjacent {
                 foo: 123,
                 bar: true,
             },
+            Self::EmptyTuple(),
             Self::Tuple(456, false),
             Self::UnitTwo,
             Self::UnitAsInt,
@@ -164,6 +171,7 @@ enum Untagged {
         foo: i32,
         bar: bool,
     },
+    EmptyTuple(),
     Tuple(i32, bool),
     UnitTwo,
     #[serde(with = "unit_variant_as_u64")]
@@ -192,6 +200,7 @@ impl Untagged {
                 foo: 123,
                 bar: true,
             },
+            Self::EmptyTuple(),
             Self::Tuple(456, false),
             Self::UnitTwo,
             Self::UnitAsInt,
diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~adjacently_tagged_enum.json b/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~adjacently_tagged_enum.json
index e75faf2..92b0d75 100644
--- a/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~adjacently_tagged_enum.json
+++ b/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~adjacently_tagged_enum.json
@@ -94,6 +94,23 @@
         "content"
       ]
     },
+    {
+      "type": "object",
+      "properties": {
+        "tag": {
+          "type": "string",
+          "const": "EmptyTuple"
+        },
+        "content": {
+          "type": "array",
+          "maxItems": 0
+        }
+      },
+      "required": [
+        "tag",
+        "content"
+      ]
+    },
     {
       "type": "object",
       "properties": {
diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~externally_tagged_enum.json b/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~externally_tagged_enum.json
index c5e19aa..93210d1 100644
--- a/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~externally_tagged_enum.json
+++ b/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~externally_tagged_enum.json
@@ -73,6 +73,19 @@
       ],
       "additionalProperties": false
     },
+    {
+      "type": "object",
+      "properties": {
+        "emptyTuple": {
+          "type": "array",
+          "maxItems": 0
+        }
+      },
+      "required": [
+        "emptyTuple"
+      ],
+      "additionalProperties": false
+    },
     {
       "type": "object",
       "properties": {
diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~untagged_enum.json b/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~untagged_enum.json
index e744d55..71e7150 100644
--- a/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~untagged_enum.json
+++ b/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~untagged_enum.json
@@ -33,6 +33,10 @@
         "bar"
       ]
     },
+    {
+      "type": "array",
+      "maxItems": 0
+    },
     {
       "type": "array",
       "prefixItems": [
diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~untagged_enum_with_titles.json b/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~untagged_enum_with_titles.json
index 51a0b4c..f15201b 100644
--- a/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~untagged_enum_with_titles.json
+++ b/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~untagged_enum_with_titles.json
@@ -38,6 +38,11 @@
         "bar"
       ]
     },
+    {
+      "title": "EmptyTuple",
+      "type": "array",
+      "maxItems": 0
+    },
     {
       "title": "Tuple",
       "type": "array",