Skip to content

Commit

Permalink
Support types with const generics (#239)
Browse files Browse the repository at this point in the history
Co-authored-by: Spencer Sharkey <[email protected]>
  • Loading branch information
GREsau and SpencerSharkey authored Aug 27, 2023
1 parent 0303f03 commit 37478d7
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 21 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
14 changes: 14 additions & 0 deletions schemars/tests/expected/schema-name-const-generics.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
}
63 changes: 63 additions & 0 deletions schemars/tests/expected/schema-name-mixed-generics.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
}
}
}
}
26 changes: 26 additions & 0 deletions schemars/tests/schema_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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",
)
}
46 changes: 25 additions & 21 deletions schemars_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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])?
Expand Down

0 comments on commit 37478d7

Please sign in to comment.