From 781f40b0616aa65a626b81de828b4a3cf30ce0fd Mon Sep 17 00:00:00 2001 From: Graham Esau Date: Fri, 27 Dec 2019 15:37:59 +0000 Subject: [PATCH] Improve schema naming for deriving on remote types --- docs/_includes/examples/remote_derive.rs | 1 + .../examples/remote_derive.schema.json | 4 +-- schemars/examples/remote_derive.rs | 1 + schemars/examples/remote_derive.schema.json | 4 +-- schemars/tests/expected/remote_derive.json | 8 +++--- .../tests/expected/remote_derive_generic.json | 12 ++++---- schemars_derive/src/attr/schemars_to_serde.rs | 1 + schemars_derive/src/lib.rs | 28 +++++++++++++------ 8 files changed, 36 insertions(+), 23 deletions(-) diff --git a/docs/_includes/examples/remote_derive.rs b/docs/_includes/examples/remote_derive.rs index bded4ea..a97db01 100644 --- a/docs/_includes/examples/remote_derive.rs +++ b/docs/_includes/examples/remote_derive.rs @@ -16,6 +16,7 @@ use schemars::{schema_for, JsonSchema}; // This is just a copy of the remote data structure that Schemars can use to // create a suitable JsonSchema impl. #[derive(JsonSchema)] +#[serde(remote = "Duration")] pub struct DurationDef { pub secs: i64, pub nanos: i32, diff --git a/docs/_includes/examples/remote_derive.schema.json b/docs/_includes/examples/remote_derive.schema.json index 9708ad6..cd4934b 100644 --- a/docs/_includes/examples/remote_derive.schema.json +++ b/docs/_includes/examples/remote_derive.schema.json @@ -11,11 +11,11 @@ "type": "string" }, "wall_time": { - "$ref": "#/definitions/DurationDef" + "$ref": "#/definitions/Duration" } }, "definitions": { - "DurationDef": { + "Duration": { "type": "object", "required": [ "nanos", diff --git a/schemars/examples/remote_derive.rs b/schemars/examples/remote_derive.rs index bded4ea..a97db01 100644 --- a/schemars/examples/remote_derive.rs +++ b/schemars/examples/remote_derive.rs @@ -16,6 +16,7 @@ use schemars::{schema_for, JsonSchema}; // This is just a copy of the remote data structure that Schemars can use to // create a suitable JsonSchema impl. #[derive(JsonSchema)] +#[serde(remote = "Duration")] pub struct DurationDef { pub secs: i64, pub nanos: i32, diff --git a/schemars/examples/remote_derive.schema.json b/schemars/examples/remote_derive.schema.json index 9708ad6..cd4934b 100644 --- a/schemars/examples/remote_derive.schema.json +++ b/schemars/examples/remote_derive.schema.json @@ -11,11 +11,11 @@ "type": "string" }, "wall_time": { - "$ref": "#/definitions/DurationDef" + "$ref": "#/definitions/Duration" } }, "definitions": { - "DurationDef": { + "Duration": { "type": "object", "required": [ "nanos", diff --git a/schemars/tests/expected/remote_derive.json b/schemars/tests/expected/remote_derive.json index 65de9ad..da5191f 100644 --- a/schemars/tests/expected/remote_derive.json +++ b/schemars/tests/expected/remote_derive.json @@ -14,7 +14,7 @@ "default": "0.000000000s", "allOf": [ { - "$ref": "#/definitions/DurationDef" + "$ref": "#/definitions/Duration" } ] }, @@ -25,16 +25,16 @@ }, "allOf": [ { - "$ref": "#/definitions/DurationDef" + "$ref": "#/definitions/Duration" } ] }, "wall_time": { - "$ref": "#/definitions/DurationDef" + "$ref": "#/definitions/Duration" } }, "definitions": { - "DurationDef": { + "Duration": { "type": "object", "required": [ "nanos", diff --git a/schemars/tests/expected/remote_derive_generic.json b/schemars/tests/expected/remote_derive_generic.json index d15bc97..c9d6f0e 100644 --- a/schemars/tests/expected/remote_derive_generic.json +++ b/schemars/tests/expected/remote_derive_generic.json @@ -10,7 +10,7 @@ ], "properties": { "byte_or_bool2": { - "$ref": "#/definitions/OrDef_for_uint8_and_Boolean" + "$ref": "#/definitions/Or_for_uint8_and_Boolean" }, "fake_map": { "type": "object", @@ -22,14 +22,14 @@ } }, "s": { - "$ref": "#/definitions/StrDef" + "$ref": "#/definitions/Str" }, "unit_or_t2": { - "$ref": "#/definitions/OrDef_for_Null_and_int32" + "$ref": "#/definitions/Or_for_Null_and_int32" } }, "definitions": { - "OrDef_for_Null_and_int32": { + "Or_for_Null_and_int32": { "anyOf": [ { "type": "null" @@ -40,7 +40,7 @@ } ] }, - "OrDef_for_uint8_and_Boolean": { + "Or_for_uint8_and_Boolean": { "anyOf": [ { "type": "integer", @@ -52,7 +52,7 @@ } ] }, - "StrDef": { + "Str": { "type": "string" } } diff --git a/schemars_derive/src/attr/schemars_to_serde.rs b/schemars_derive/src/attr/schemars_to_serde.rs index b27f6e9..28a6672 100644 --- a/schemars_derive/src/attr/schemars_to_serde.rs +++ b/schemars_derive/src/attr/schemars_to_serde.rs @@ -20,6 +20,7 @@ static SERDE_KEYWORDS: &[&str] = &[ "skip_serializing_if", "skip_deserializing", "flatten", + "remote", // Special cases - `with`/`serialize_with` are passed to serde but not copied from schemars attrs to serde attrs. // This is because we want to preserve any serde attribute's `serialize_with` value to determine whether the field's // default value should be serialized. We also check the `with` value on schemars/serde attrs e.g. to support deriving diff --git a/schemars_derive/src/lib.rs b/schemars_derive/src/lib.rs index 0ac5e6d..2e9c199 100644 --- a/schemars_derive/src/lib.rs +++ b/schemars_derive/src/lib.rs @@ -43,19 +43,22 @@ pub fn derive_json_schema(input: proc_macro::TokenStream) -> proc_macro::TokenSt let type_name = cont.ident; let type_params: Vec<_> = cont.generics.type_params().map(|ty| &ty.ident).collect(); - let schema_base_name = cont.attrs.name().deserialize_name(); + let mut schema_base_name = cont.attrs.name().deserialize_name(); + let schema_is_renamed = type_name != schema_base_name; + + if !schema_is_renamed { + if let Some(path) = cont.attrs.remote() { + if let Some(segment) = path.segments.last() { + schema_base_name = segment.ident.to_string(); + } + } + } + let schema_name = if type_params.is_empty() { quote! { #schema_base_name.to_owned() } - } else if type_name == schema_base_name { - 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())*) - } - } else { + } else if schema_is_renamed { let mut schema_name_fmt = schema_base_name; for tp in &type_params { schema_name_fmt.push_str(&format!("{{{}:.0}}", tp)); @@ -63,6 +66,13 @@ pub fn derive_json_schema(input: proc_macro::TokenStream) -> proc_macro::TokenSt 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 (impl_generics, ty_generics, where_clause) = cont.generics.split_for_impl();