From 1d0fd18c9ed2f4090fc3e86f954d806a2007a695 Mon Sep 17 00:00:00 2001 From: Graham Esau Date: Wed, 7 Aug 2019 23:03:54 +0100 Subject: [PATCH] Enable renaming schemas using attribute on struct --- schemars/tests/expected/naming-custom.json | 2 +- schemars/tests/flatten.rs | 23 +++++------ schemars/tests/naming.rs | 44 +++++++++++----------- schemars/tests/schema_for_schema.rs | 3 +- schemars/tests/{util.rs => util/mod.rs} | 32 ++++++++-------- schemars_derive/src/lib.rs | 34 ++++++++++++++--- 6 files changed, 78 insertions(+), 60 deletions(-) rename schemars/tests/{util.rs => util/mod.rs} (89%) diff --git a/schemars/tests/expected/naming-custom.json b/schemars/tests/expected/naming-custom.json index 0ee1e29..af0af2a 100644 --- a/schemars/tests/expected/naming-custom.json +++ b/schemars/tests/expected/naming-custom.json @@ -4,7 +4,7 @@ "type": "object", "properties": { "inner": { - "$ref": "#/definitions/MySimpleStruct" + "$ref": "#/definitions/another-new-name" }, "t": { "type": "integer" diff --git a/schemars/tests/flatten.rs b/schemars/tests/flatten.rs index a330302..d154582 100644 --- a/schemars/tests/flatten.rs +++ b/schemars/tests/flatten.rs @@ -1,9 +1,9 @@ +mod util; use pretty_assertions::assert_eq; -use schemars::{schema::*, schema_for, MakeSchema}; -use serde::{Deserialize, Serialize}; -use std::error::Error; +use schemars::{schema_for, MakeSchema}; +use util::*; -#[derive(Serialize, Deserialize, Debug, PartialEq, MakeSchema)] +#[derive(Debug, MakeSchema)] struct Flat { foo: f32, bar: bool, @@ -11,7 +11,8 @@ struct Flat { foobar: Vec, } -#[derive(Serialize, Deserialize, Debug, PartialEq, MakeSchema)] +#[derive(Debug, MakeSchema)] +#[serde(rename = "Flat")] struct Deep1 { foo: f32, #[serde(flatten)] @@ -19,26 +20,22 @@ struct Deep1 { foobar: Vec, } -#[derive(Serialize, Deserialize, Debug, PartialEq, MakeSchema)] +#[derive(Debug, MakeSchema)] struct Deep2 { bar: bool, #[serde(flatten)] deep3: Deep3, } -#[derive(Serialize, Deserialize, Debug, PartialEq, MakeSchema)] +#[derive(Debug, MakeSchema)] struct Deep3 { baz: String, } #[test] -fn flatten_schema() -> Result<(), Box> { +fn flatten_schema() -> TestResult { let flat = schema_for!(Flat)?; - let mut deep = schema_for!(Deep1)?; - match deep { - Schema::Object(ref mut o) => o.title = Some("Flat".to_owned()), - _ => assert!(false, "Schema was not object: {:?}", deep), - }; + let deep = schema_for!(Deep1)?; assert_eq!(flat, deep); Ok(()) } diff --git a/schemars/tests/naming.rs b/schemars/tests/naming.rs index f32e358..7f7b1bf 100644 --- a/schemars/tests/naming.rs +++ b/schemars/tests/naming.rs @@ -1,41 +1,39 @@ -use schemars::MakeSchema; - mod util; +use schemars::MakeSchema; use util::*; -#[derive(MakeSchema)] -pub struct MyStruct { - pub t: T, - pub u: U, - pub v: V, - pub w: W, - pub inner: MySimpleStruct, +#[derive(Debug, MakeSchema)] +struct MyStruct { + t: T, + u: U, + v: V, + w: W, + inner: MySimpleStruct, } -#[derive(MakeSchema)] -pub struct MySimpleStruct {} +#[derive(Debug, MakeSchema)] +struct MySimpleStruct {} #[test] fn default_name_multiple_type_params() -> TestResult { test_default_generated_schema::>>("naming-default") } -#[derive(MakeSchema)] -#[serde(rename = "a-new-name---")] -pub struct MyRenamedStruct { - pub t: T, - pub u: U, - pub v: V, - pub w: W, - pub inner: MySimpleRenamedStruct, +#[derive(Debug, MakeSchema)] +#[serde(rename = "a-new-name-{W}-{T}-{T}")] +struct MyRenamedStruct { + t: T, + u: U, + v: V, + w: W, + inner: MySimpleRenamedStruct, } -#[derive(MakeSchema)] +#[derive(Debug, MakeSchema)] #[serde(rename = "another-new-name")] -pub struct MySimpleRenamedStruct {} +struct MySimpleRenamedStruct {} #[test] -#[ignore] // not yet implemented -fn overriden_with_rename_name_multiple_type_params() -> TestResult { +fn overriden_with_rename_multiple_type_params() -> TestResult { test_default_generated_schema::>>("naming-custom") } diff --git a/schemars/tests/schema_for_schema.rs b/schemars/tests/schema_for_schema.rs index 3a7e015..3bc0411 100644 --- a/schemars/tests/schema_for_schema.rs +++ b/schemars/tests/schema_for_schema.rs @@ -1,7 +1,6 @@ +mod util; use schemars::gen::SchemaSettings; use schemars::schema::Schema; - -mod util; use util::*; #[test] diff --git a/schemars/tests/util.rs b/schemars/tests/util/mod.rs similarity index 89% rename from schemars/tests/util.rs rename to schemars/tests/util/mod.rs index 57f3046..c41d6d9 100644 --- a/schemars/tests/util.rs +++ b/schemars/tests/util/mod.rs @@ -6,21 +6,7 @@ use std::panic; pub type TestResult = Result<(), Box>; -pub fn test_default_generated_schema(file: &str) -> TestResult { - let expected_json = fs::read_to_string(format!("tests/expected/{}.json", file))?; - let expected = serde_json::from_str(&expected_json)?; - - let actual = schema_for!(T)?; - - if actual != expected { - let actual_json = serde_json::to_string_pretty(&actual)?; - fs::write(format!("tests/actual/{}.json", file), actual_json)?; - } - - assert_eq!(actual, expected); - Ok(()) -} - +#[allow(dead_code)] // https://github.com/rust-lang/rust/issues/46379 pub fn test_generated_schema(file: &str, settings: SchemaSettings) -> TestResult { let expected_json = fs::read_to_string(format!("tests/expected/{}.json", file))?; let expected = serde_json::from_str(&expected_json)?; @@ -35,3 +21,19 @@ pub fn test_generated_schema(file: &str, settings: SchemaSettings assert_eq!(actual, expected); Ok(()) } + +#[allow(dead_code)] // https://github.com/rust-lang/rust/issues/46379 +pub fn test_default_generated_schema(file: &str) -> TestResult { + let expected_json = fs::read_to_string(format!("tests/expected/{}.json", file))?; + let expected = serde_json::from_str(&expected_json)?; + + let actual = schema_for!(T)?; + + if actual != expected { + let actual_json = serde_json::to_string_pretty(&actual)?; + fs::write(format!("tests/actual/{}.json", file), actual_json)?; + } + + assert_eq!(actual, expected); + Ok(()) +} diff --git a/schemars_derive/src/lib.rs b/schemars_derive/src/lib.rs index e1f2117..d2c4729 100644 --- a/schemars_derive/src/lib.rs +++ b/schemars_derive/src/lib.rs @@ -15,8 +15,10 @@ use syn::{DeriveInput, GenericParam, Generics}; #[proc_macro_derive(MakeSchema, attributes(schemars, serde))] pub fn derive_make_schema(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let mut input = parse_macro_input!(input as DeriveInput); + // TODO is mutating the input really the best way to do this? add_trait_bounds(&mut input.generics); + let ctxt = Ctxt::new(); let cont = Container::from_ast(&ctxt, &input, Derive::Deserialize); if let Err(e) = ctxt.check() { @@ -29,20 +31,40 @@ pub fn derive_make_schema(input: proc_macro::TokenStream) -> proc_macro::TokenSt _ => unimplemented!("work in progress!"), }; - let name = cont.ident; + let type_name = cont.ident; let type_params: Vec<_> = cont.generics.type_params().map(|ty| &ty.ident).collect(); - let type_param_fmt = match type_params.len() { - 0 => "{}".to_owned(), - n => format!("{{}}_For_{{}}{}", "_And_{}".repeat(n - 1)), + + let schema_base_name = cont.attrs.name().deserialize_name(); + let schema_name = if type_params.is_empty() { + quote! { + #schema_base_name.to_owned() + } + } else if schema_base_name == type_name.to_string() { + 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 { + let mut schema_name_fmt = schema_base_name; + for tp in &type_params { + schema_name_fmt.push_str(&format!("{{{}:.0}}", tp)); + } + let fmt_param_names = &type_params; + let type_params = &type_params; + quote! { + format!(#schema_name_fmt #(,#fmt_param_names=#type_params::schema_name())*) + } }; let (impl_generics, ty_generics, where_clause) = cont.generics.split_for_impl(); let impl_block = quote! { #[automatically_derived] - impl #impl_generics schemars::MakeSchema for #name #ty_generics #where_clause { + impl #impl_generics schemars::MakeSchema for #type_name #ty_generics #where_clause { fn schema_name() -> String { - format!(#type_param_fmt, stringify!(#name) #(,#type_params::schema_name())*) + #schema_name } fn make_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::Result {