diff --git a/CHANGELOG.md b/CHANGELOG.md index 63cd2f2d..061a4a57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Added: - Implement `JsonSchema` for `semver::Version` (https://github.com/GREsau/schemars/pull/195 / https://github.com/GREsau/schemars/pull/238) +- Include const generics in generated schema names (https://github.com/GREsau/schemars/pull/179 / https://github.com/GREsau/schemars/pull/239) ### Changed: diff --git a/schemars/tests/expected/schema-name-const-generics.json b/schemars/tests/expected/schema-name-const-generics.json new file mode 100644 index 00000000..7505b285 --- /dev/null +++ b/schemars/tests/expected/schema-name-const-generics.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "const-generics-z-42", + "type": "object", + "required": [ + "foo" + ], + "properties": { + "foo": { + "type": "integer", + "format": "int32" + } + } +} \ No newline at end of file diff --git a/schemars/tests/expected/schema-name-mixed-generics.json b/schemars/tests/expected/schema-name-mixed-generics.json new file mode 100644 index 00000000..32ac797e --- /dev/null +++ b/schemars/tests/expected/schema-name-mixed-generics.json @@ -0,0 +1,63 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "MixedGenericStruct_for_MyStruct_for_int32_and_Null_and_Boolean_and_Array_of_String_and_42_and_z", + "type": "object", + "required": [ + "foo", + "generic" + ], + "properties": { + "foo": { + "type": "integer", + "format": "int32" + }, + "generic": { + "$ref": "#/definitions/MyStruct_for_int32_and_Null_and_Boolean_and_Array_of_String" + } + }, + "definitions": { + "MySimpleStruct": { + "type": "object", + "required": [ + "foo" + ], + "properties": { + "foo": { + "type": "integer", + "format": "int32" + } + } + }, + "MyStruct_for_int32_and_Null_and_Boolean_and_Array_of_String": { + "type": "object", + "required": [ + "inner", + "t", + "u", + "v", + "w" + ], + "properties": { + "inner": { + "$ref": "#/definitions/MySimpleStruct" + }, + "t": { + "type": "integer", + "format": "int32" + }, + "u": { + "type": "null" + }, + "v": { + "type": "boolean" + }, + "w": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } +} \ No newline at end of file diff --git a/schemars/tests/schema_name.rs b/schemars/tests/schema_name.rs index 59fe0cff..ebd8a528 100644 --- a/schemars/tests/schema_name.rs +++ b/schemars/tests/schema_name.rs @@ -49,3 +49,29 @@ fn overriden_with_rename_multiple_type_params() -> TestResult { "schema-name-custom", ) } + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars(rename = "const-generics-{BAR}-")] +struct ConstGenericStruct { + foo: i32, +} + +#[test] +fn overriden_with_rename_const_generics() -> TestResult { + test_default_generated_schema::>("schema-name-const-generics") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct MixedGenericStruct { + generic: T, + foo: i32, +} + +#[test] +fn default_name_mixed_generics() -> TestResult { + test_default_generated_schema::>, 42, 'z'>>( + "schema-name-mixed-generics", + ) +} diff --git a/schemars_derive/src/lib.rs b/schemars_derive/src/lib.rs index f8173f42..e3b3a4fb 100644 --- a/schemars_derive/src/lib.rs +++ b/schemars_derive/src/lib.rs @@ -95,27 +95,31 @@ fn derive_json_schema( // FIXME improve handling of generic type params which may not implement JsonSchema let type_params: Vec<_> = cont.generics.type_params().map(|ty| &ty.ident).collect(); - let schema_name = - if type_params.is_empty() || (cont.attrs.is_renamed && !schema_base_name.contains('{')) { - quote! { - #schema_base_name.to_owned() - } - } else if cont.attrs.is_renamed { - let mut schema_name_fmt = schema_base_name; - for tp in &type_params { - schema_name_fmt.push_str(&format!("{{{}:.0}}", tp)); - } - quote! { - format!(#schema_name_fmt #(,#type_params=#type_params::schema_name())*) - } - } else { - let mut schema_name_fmt = schema_base_name; - schema_name_fmt.push_str("_for_{}"); - schema_name_fmt.push_str(&"_and_{}".repeat(type_params.len() - 1)); - quote! { - format!(#schema_name_fmt #(,#type_params::schema_name())*) - } - }; + let const_params: Vec<_> = cont.generics.const_params().map(|c| &c.ident).collect(); + let params: Vec<_> = type_params.iter().chain(const_params.iter()).collect(); + + let schema_name = if params.is_empty() + || (cont.attrs.is_renamed && !schema_base_name.contains('{')) + { + quote! { + #schema_base_name.to_owned() + } + } else if cont.attrs.is_renamed { + let mut schema_name_fmt = schema_base_name; + for tp in ¶ms { + schema_name_fmt.push_str(&format!("{{{}:.0}}", tp)); + } + quote! { + format!(#schema_name_fmt #(,#type_params=#type_params::schema_name())* #(,#const_params=#const_params)*) + } + } else { + let mut schema_name_fmt = schema_base_name; + schema_name_fmt.push_str("_for_{}"); + schema_name_fmt.push_str(&"_and_{}".repeat(params.len() - 1)); + quote! { + format!(#schema_name_fmt #(,#type_params::schema_name())* #(,#const_params)*) + } + }; let schema_expr = if repr { schema_exprs::expr_for_repr(&cont).map_err(|e| vec![e])?