Repository: GREsau/schemars
Pull request #64 (2020-12-02 01:53:19)

Make HashSet and BTreeSet use the uniqueItems keyword in their schema


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cf633b8..b60f0d8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@
 ### Changed:
 - Minimum supported rust version is now 1.37.0
 - Deriving JsonSchema on enums now sets `additionalProperties` to false on generated schemas wherever serde doesn't accept unknown properties. This includes non-unit variants of externally tagged enums, and struct-style variants of all enums that have the `deny_unknown_fields` attribute.
+- Schemas for HashSet and BTreeSet now have `uniqueItems` set to true (https://github.com/GREsau/schemars/pull/64)
 
 ### Fixed
 - Fix use of `#[serde(transparent)]` in combination with `#[schemars(with = ...)]` (https://github.com/GREsau/schemars/pull/67)
diff --git a/schemars/src/json_schema_impls/sequences.rs b/schemars/src/json_schema_impls/sequences.rs
index 1e79210..632a01e 100644
--- a/schemars/src/json_schema_impls/sequences.rs
+++ b/schemars/src/json_schema_impls/sequences.rs
@@ -29,9 +29,38 @@ macro_rules! seq_impl {
     };
 }
 
+macro_rules! set_impl {
+    ($($desc:tt)+) => {
+        impl $($desc)+
+        where
+            T: JsonSchema,
+        {
+            no_ref_schema!();
+
+            fn schema_name() -> String {
+                format!("Set_of_{}", T::schema_name())
+            }
+
+            fn json_schema(gen: &mut SchemaGenerator) -> Schema {
+                SchemaObject {
+                    instance_type: Some(InstanceType::Array.into()),
+                    array: Some(Box::new(ArrayValidation {
+                        unique_items: Some(true),
+                        items: Some(gen.subschema_for::<T>().into()),
+                        ..Default::default()
+                    })),
+                    ..Default::default()
+                }
+                .into()
+            }
+        }
+    };
+}
+
+
 seq_impl!(<T> JsonSchema for std::collections::BinaryHeap<T>);
-seq_impl!(<T> JsonSchema for std::collections::BTreeSet<T>);
-seq_impl!(<T, H> JsonSchema for std::collections::HashSet<T, H>);
+set_impl!(<T> JsonSchema for std::collections::BTreeSet<T>);
+set_impl!(<T, H> JsonSchema for std::collections::HashSet<T, H>);
 seq_impl!(<T> JsonSchema for std::collections::LinkedList<T>);
 seq_impl!(<T> JsonSchema for Vec<T>);
 seq_impl!(<T> JsonSchema for std::collections::VecDeque<T>);


Test patch:
diff --git a/schemars/tests/expected/indexmap.json b/schemars/tests/expected/indexmap.json
index e9d4df4..98065d9 100644
--- a/schemars/tests/expected/indexmap.json
+++ b/schemars/tests/expected/indexmap.json
@@ -18,7 +18,8 @@
       "items": {
         "type": "integer",
         "format": "int"
-      }
+      },
+      "uniqueItems": true
     }
   }
 }
\ No newline at end of file
diff --git a/schemars/tests/expected/remote_derive_generic.json b/schemars/tests/expected/remote_derive_generic.json
index c76610c..2fea80a 100644
--- a/schemars/tests/expected/remote_derive_generic.json
+++ b/schemars/tests/expected/remote_derive_generic.json
@@ -24,7 +24,8 @@
         "type": "array",
         "items": {
           "type": "string"
-        }
+        },
+        "uniqueItems": true
       }
     }
   },
diff --git a/schemars/tests/expected/schema-2019_09.json b/schemars/tests/expected/schema-2019_09.json
index 33a063b..cf11d35 100644
--- a/schemars/tests/expected/schema-2019_09.json
+++ b/schemars/tests/expected/schema-2019_09.json
@@ -315,7 +315,8 @@
       "type": "array",
       "items": {
         "type": "string"
-      }
+      },
+      "uniqueItems": true
     },
     "properties": {
       "description": "The `properties` keyword.\n\nSee [JSON Schema 9.3.2.1. \"properties\"](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.3.2.1).",
@@ -670,7 +671,8 @@
           "type": "array",
           "items": {
             "type": "string"
-          }
+          },
+          "uniqueItems": true
         },
         "properties": {
           "description": "The `properties` keyword.\n\nSee [JSON Schema 9.3.2.1. \"properties\"](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.3.2.1).",
diff --git a/schemars/tests/expected/schema-openapi3.json b/schemars/tests/expected/schema-openapi3.json
index 78deb95..0548828 100644
--- a/schemars/tests/expected/schema-openapi3.json
+++ b/schemars/tests/expected/schema-openapi3.json
@@ -255,7 +255,8 @@
       "type": "array",
       "items": {
         "type": "string"
-      }
+      },
+      "uniqueItems": true
     },
     "properties": {
       "description": "The `properties` keyword.\n\nSee [JSON Schema 9.3.2.1. \"properties\"](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.3.2.1).",
@@ -552,7 +553,8 @@
           "type": "array",
           "items": {
             "type": "string"
-          }
+          },
+          "uniqueItems": true
         },
         "properties": {
           "description": "The `properties` keyword.\n\nSee [JSON Schema 9.3.2.1. \"properties\"](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.3.2.1).",
diff --git a/schemars/tests/expected/schema.json b/schemars/tests/expected/schema.json
index b54d0a2..6cf840b 100644
--- a/schemars/tests/expected/schema.json
+++ b/schemars/tests/expected/schema.json
@@ -315,7 +315,8 @@
       "type": "array",
       "items": {
         "type": "string"
-      }
+      },
+      "uniqueItems": true
     },
     "properties": {
       "description": "The `properties` keyword.\n\nSee [JSON Schema 9.3.2.1. \"properties\"](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.3.2.1).",
@@ -674,7 +675,8 @@
           "type": "array",
           "items": {
             "type": "string"
-          }
+          },
+          "uniqueItems": true
         },
         "properties": {
           "description": "The `properties` keyword.\n\nSee [JSON Schema 9.3.2.1. \"properties\"](https://tools.ietf.org/html/draft-handrews-json-schema-02#section-9.3.2.1).",