Support types with const generics (#239)

Co-authored-by: Spencer Sharkey <spsharkey@tesla.com>
This commit is contained in:
Graham Esau 2023-08-27 20:50:20 +01:00 committed by GitHub
parent 0303f0334e
commit 37478d764e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 129 additions and 21 deletions

View file

@ -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:

View file

@ -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"
}
}
}

View file

@ -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"
}
}
}
}
}
}

View file

@ -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<const FOO: usize, const BAR: char> {
foo: i32,
}
#[test]
fn overriden_with_rename_const_generics() -> TestResult {
test_default_generated_schema::<ConstGenericStruct<42, 'z'>>("schema-name-const-generics")
}
#[allow(dead_code)]
#[derive(JsonSchema)]
struct MixedGenericStruct<T, const FOO: usize, const BAR: char> {
generic: T,
foo: i32,
}
#[test]
fn default_name_mixed_generics() -> TestResult {
test_default_generated_schema::<MixedGenericStruct<MyStruct<i32, (), bool, Vec<String>>, 42, 'z'>>(
"schema-name-mixed-generics",
)
}

View file

@ -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 &params {
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])?