diff --git a/schemars/src/_private.rs b/schemars/src/_private.rs index 0ba27ce..2510401 100644 --- a/schemars/src/_private.rs +++ b/schemars/src/_private.rs @@ -53,17 +53,16 @@ impl MaybeSerializeWrapper { } } -/// Create a schema for a unit enum -pub fn new_unit_enum(variant: &str) -> Schema { - // TODO switch from single-valued "enum" to "const" +/// Create a schema for a unit enum variant +pub fn new_unit_enum_variant(variant: &str) -> Schema { json_schema!({ "type": "string", - "enum": [variant], + "const": variant, }) } -/// Create a schema for an externally tagged enum -pub fn new_externally_tagged_enum(variant: &str, sub_schema: Schema) -> Schema { +/// Create a schema for an externally tagged enum variant +pub fn new_externally_tagged_enum_variant(variant: &str, sub_schema: Schema) -> Schema { json_schema!({ "type": "object", "properties": { @@ -74,7 +73,8 @@ pub fn new_externally_tagged_enum(variant: &str, sub_schema: Schema) -> Schema { }) } -pub fn apply_internal_enum_tag( +/// Update a schema for an internally tagged enum variant +pub fn apply_internal_enum_variant_tag( schema: &mut Schema, tag_name: &str, variant: &str, @@ -94,8 +94,7 @@ pub fn apply_internal_enum_tag( tag_name.to_string(), json!({ "type": "string", - // TODO switch from single-valued "enum" to "const" - "enum": [variant] + "const": variant }), ); } @@ -113,34 +112,6 @@ pub fn apply_internal_enum_tag( } } -/// Create a schema for an internally tagged enum -pub fn new_internally_tagged_enum( - tag_name: &str, - variant: &str, - deny_unknown_fields: bool, -) -> Schema { - // TODO switch from single-valued "enum" to "const" - let mut schema = json_schema!({ - "type": "object", - "properties": { - tag_name: { - "type": "string", - "enum": [variant], - } - }, - "required": [tag_name], - }); - - if deny_unknown_fields { - schema - .as_object_mut() - .unwrap() - .insert("additionalProperties".into(), false.into()); - } - - schema -} - pub fn insert_object_property( schema: &mut Schema, key: &str, diff --git a/schemars/src/gen.rs b/schemars/src/gen.rs index 8336ecc..c06f85a 100644 --- a/schemars/src/gen.rs +++ b/schemars/src/gen.rs @@ -97,6 +97,7 @@ impl SchemaSettings { skip_additional_properties: true, }), Box::new(SetSingleExample), + Box::new(ReplaceConstValue), ], inline_subschemas: false, } diff --git a/schemars/src/visit.rs b/schemars/src/visit.rs index cfe11df..5fd4273 100644 --- a/schemars/src/visit.rs +++ b/schemars/src/visit.rs @@ -169,3 +169,21 @@ impl Visitor for SetSingleExample { } } } + +/// This visitor will replace the `const` schema property with a single-valued `enum` property. +/// +/// This is useful for dialects of JSON Schema (e.g. OpenAPI 3.0) that do not support the `const` property. +#[derive(Debug, Clone)] +pub struct ReplaceConstValue; + +impl Visitor for ReplaceConstValue { + fn visit_schema(&mut self, schema: &mut Schema) { + visit_schema(self, schema); + + if let Some(obj) = schema.as_object_mut() { + if let Some(value) = obj.remove("const") { + obj.insert("enum".into(), Value::Array(vec![value])); + } + } + } +} diff --git a/schemars/tests/expected/deprecated-enum.json b/schemars/tests/expected/deprecated-enum.json index 55a98ef..dab90ec 100644 --- a/schemars/tests/expected/deprecated-enum.json +++ b/schemars/tests/expected/deprecated-enum.json @@ -11,10 +11,8 @@ }, { "type": "string", - "deprecated": true, - "enum": [ - "DeprecatedUnitVariant" - ] + "const": "DeprecatedUnitVariant", + "deprecated": true }, { "type": "object", diff --git a/schemars/tests/expected/doc_comments_enum.json b/schemars/tests/expected/doc_comments_enum.json index c983c1d..fc38db1 100644 --- a/schemars/tests/expected/doc_comments_enum.json +++ b/schemars/tests/expected/doc_comments_enum.json @@ -13,9 +13,7 @@ { "description": "This comment is included in the generated schema :)", "type": "string", - "enum": [ - "DocumentedUnit" - ] + "const": "DocumentedUnit" }, { "title": "Complex variant", diff --git a/schemars/tests/expected/enum-internal-duf.json b/schemars/tests/expected/enum-internal-duf.json index 6db4d31..758bf9b 100644 --- a/schemars/tests/expected/enum-internal-duf.json +++ b/schemars/tests/expected/enum-internal-duf.json @@ -7,9 +7,7 @@ "properties": { "typeProperty": { "type": "string", - "enum": [ - "UnitOne" - ] + "const": "UnitOne" } }, "additionalProperties": false, @@ -22,9 +20,7 @@ "properties": { "typeProperty": { "type": "string", - "enum": [ - "StringMap" - ] + "const": "StringMap" } }, "additionalProperties": { @@ -39,9 +35,7 @@ "properties": { "typeProperty": { "type": "string", - "enum": [ - "UnitStructNewType" - ] + "const": "UnitStructNewType" } }, "additionalProperties": false, @@ -61,9 +55,7 @@ }, "typeProperty": { "type": "string", - "enum": [ - "StructNewType" - ] + "const": "StructNewType" } }, "required": [ @@ -84,9 +76,7 @@ }, "typeProperty": { "type": "string", - "enum": [ - "Struct" - ] + "const": "Struct" } }, "additionalProperties": false, @@ -101,9 +91,7 @@ "properties": { "typeProperty": { "type": "string", - "enum": [ - "UnitTwo" - ] + "const": "UnitTwo" } }, "additionalProperties": false, @@ -117,9 +105,7 @@ "properties": { "typeProperty": { "type": "string", - "enum": [ - "WithInt" - ] + "const": "WithInt" } }, "required": [ diff --git a/schemars/tests/expected/enum-internal.json b/schemars/tests/expected/enum-internal.json index 2382f2d..765248f 100644 --- a/schemars/tests/expected/enum-internal.json +++ b/schemars/tests/expected/enum-internal.json @@ -7,9 +7,7 @@ "properties": { "typeProperty": { "type": "string", - "enum": [ - "UnitOne" - ] + "const": "UnitOne" } }, "required": [ @@ -21,9 +19,7 @@ "properties": { "typeProperty": { "type": "string", - "enum": [ - "StringMap" - ] + "const": "StringMap" } }, "additionalProperties": { @@ -38,9 +34,7 @@ "properties": { "typeProperty": { "type": "string", - "enum": [ - "UnitStructNewType" - ] + "const": "UnitStructNewType" } }, "required": [ @@ -59,9 +53,7 @@ }, "typeProperty": { "type": "string", - "enum": [ - "StructNewType" - ] + "const": "StructNewType" } }, "required": [ @@ -82,9 +74,7 @@ }, "typeProperty": { "type": "string", - "enum": [ - "Struct" - ] + "const": "Struct" } }, "required": [ @@ -98,9 +88,7 @@ "properties": { "typeProperty": { "type": "string", - "enum": [ - "UnitTwo" - ] + "const": "UnitTwo" } }, "required": [ @@ -113,9 +101,7 @@ "properties": { "typeProperty": { "type": "string", - "enum": [ - "WithInt" - ] + "const": "WithInt" } }, "required": [ diff --git a/schemars/tests/expected/enum-simple-internal-duf.json b/schemars/tests/expected/enum-simple-internal-duf.json index 9e6e5d4..4fdf04e 100644 --- a/schemars/tests/expected/enum-simple-internal-duf.json +++ b/schemars/tests/expected/enum-simple-internal-duf.json @@ -7,9 +7,7 @@ "properties": { "typeProperty": { "type": "string", - "enum": [ - "A" - ] + "const": "A" } }, "additionalProperties": false, @@ -22,9 +20,7 @@ "properties": { "typeProperty": { "type": "string", - "enum": [ - "B" - ] + "const": "B" } }, "additionalProperties": false, @@ -37,9 +33,7 @@ "properties": { "typeProperty": { "type": "string", - "enum": [ - "C" - ] + "const": "C" } }, "additionalProperties": false, diff --git a/schemars/tests/expected/enum-simple-internal.json b/schemars/tests/expected/enum-simple-internal.json index a549c8c..050089c 100644 --- a/schemars/tests/expected/enum-simple-internal.json +++ b/schemars/tests/expected/enum-simple-internal.json @@ -7,9 +7,7 @@ "properties": { "typeProperty": { "type": "string", - "enum": [ - "A" - ] + "const": "A" } }, "required": [ @@ -21,9 +19,7 @@ "properties": { "typeProperty": { "type": "string", - "enum": [ - "B" - ] + "const": "B" } }, "required": [ @@ -35,9 +31,7 @@ "properties": { "typeProperty": { "type": "string", - "enum": [ - "C" - ] + "const": "C" } }, "required": [ diff --git a/schemars/tests/expected/enum-unit-doc.json b/schemars/tests/expected/enum-unit-doc.json index 11a5c2a..86160e8 100644 --- a/schemars/tests/expected/enum-unit-doc.json +++ b/schemars/tests/expected/enum-unit-doc.json @@ -6,23 +6,17 @@ "title": "A deer", "description": "A female deer", "type": "string", - "enum": [ - "Do" - ] + "const": "Do" }, { "description": "A drop of golden sun", "type": "string", - "enum": [ - "Re" - ] + "const": "Re" }, { "description": "A name I call myself", "type": "string", - "enum": [ - "Mi" - ] + "const": "Mi" } ] } \ No newline at end of file diff --git a/schemars/tests/expected/schema_settings-2019_09.json b/schemars/tests/expected/schema_settings-2019_09.json index 4e18426..e51f397 100644 --- a/schemars/tests/expected/schema_settings-2019_09.json +++ b/schemars/tests/expected/schema_settings-2019_09.json @@ -45,9 +45,7 @@ { "description": "This is a documented unit variant", "type": "string", - "enum": [ - "DocumentedUnit" - ] + "const": "DocumentedUnit" }, { "type": "object", diff --git a/schemars/tests/expected/schema_settings.json b/schemars/tests/expected/schema_settings.json index 8e70c7c..07cdb0e 100644 --- a/schemars/tests/expected/schema_settings.json +++ b/schemars/tests/expected/schema_settings.json @@ -45,9 +45,7 @@ { "description": "This is a documented unit variant", "type": "string", - "enum": [ - "DocumentedUnit" - ] + "const": "DocumentedUnit" }, { "type": "object", diff --git a/schemars/tests/expected/schema_with-enum-internal.json b/schemars/tests/expected/schema_with-enum-internal.json index 8b6fbeb..45bc8e9 100644 --- a/schemars/tests/expected/schema_with-enum-internal.json +++ b/schemars/tests/expected/schema_with-enum-internal.json @@ -10,9 +10,7 @@ }, "typeProperty": { "type": "string", - "enum": [ - "Struct" - ] + "const": "Struct" } }, "required": [ @@ -25,9 +23,7 @@ "properties": { "typeProperty": { "type": "string", - "enum": [ - "NewType" - ] + "const": "NewType" } }, "required": [ @@ -39,9 +35,7 @@ "properties": { "typeProperty": { "type": "string", - "enum": [ - "Unit" - ] + "const": "Unit" } }, "required": [ diff --git a/schemars_derive/src/schema_exprs.rs b/schemars_derive/src/schema_exprs.rs index f22831e..7a1de81 100644 --- a/schemars_derive/src/schema_exprs.rs +++ b/schemars_derive/src/schema_exprs.rs @@ -197,12 +197,12 @@ fn expr_for_external_tagged_enum<'a>( let mut schema_expr = if variant.is_unit() && variant.attrs.with.is_none() { quote! { - schemars::_private::new_unit_enum(#name) + schemars::_private::new_unit_enum_variant(#name) } } else { let sub_schema = expr_for_untagged_enum_variant(variant, deny_unknown_fields); quote! { - schemars::_private::new_externally_tagged_enum(#name, #sub_schema) + schemars::_private::new_externally_tagged_enum_variant(#name, #sub_schema) } }; @@ -236,7 +236,7 @@ fn expr_for_internal_tagged_enum<'a>( quote!({ let mut schema = #schema_expr; - schemars::_private::apply_internal_enum_tag(&mut schema, #tag_name, #name, #deny_unknown_fields); + schemars::_private::apply_internal_enum_variant_tag(&mut schema, #tag_name, #name, #deny_unknown_fields); schema }) })