Enable renaming schemas using attribute on struct
This commit is contained in:
parent
67d44533d6
commit
1d0fd18c9e
6 changed files with 78 additions and 60 deletions
|
@ -4,7 +4,7 @@
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"inner": {
|
"inner": {
|
||||||
"$ref": "#/definitions/MySimpleStruct"
|
"$ref": "#/definitions/another-new-name"
|
||||||
},
|
},
|
||||||
"t": {
|
"t": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
|
mod util;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use schemars::{schema::*, schema_for, MakeSchema};
|
use schemars::{schema_for, MakeSchema};
|
||||||
use serde::{Deserialize, Serialize};
|
use util::*;
|
||||||
use std::error::Error;
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, MakeSchema)]
|
#[derive(Debug, MakeSchema)]
|
||||||
struct Flat {
|
struct Flat {
|
||||||
foo: f32,
|
foo: f32,
|
||||||
bar: bool,
|
bar: bool,
|
||||||
|
@ -11,7 +11,8 @@ struct Flat {
|
||||||
foobar: Vec<i32>,
|
foobar: Vec<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, MakeSchema)]
|
#[derive(Debug, MakeSchema)]
|
||||||
|
#[serde(rename = "Flat")]
|
||||||
struct Deep1 {
|
struct Deep1 {
|
||||||
foo: f32,
|
foo: f32,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
|
@ -19,26 +20,22 @@ struct Deep1 {
|
||||||
foobar: Vec<i32>,
|
foobar: Vec<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, MakeSchema)]
|
#[derive(Debug, MakeSchema)]
|
||||||
struct Deep2 {
|
struct Deep2 {
|
||||||
bar: bool,
|
bar: bool,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
deep3: Deep3,
|
deep3: Deep3,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, MakeSchema)]
|
#[derive(Debug, MakeSchema)]
|
||||||
struct Deep3 {
|
struct Deep3 {
|
||||||
baz: String,
|
baz: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn flatten_schema() -> Result<(), Box<dyn Error>> {
|
fn flatten_schema() -> TestResult {
|
||||||
let flat = schema_for!(Flat)?;
|
let flat = schema_for!(Flat)?;
|
||||||
let mut deep = schema_for!(Deep1)?;
|
let deep = schema_for!(Deep1)?;
|
||||||
match deep {
|
|
||||||
Schema::Object(ref mut o) => o.title = Some("Flat".to_owned()),
|
|
||||||
_ => assert!(false, "Schema was not object: {:?}", deep),
|
|
||||||
};
|
|
||||||
assert_eq!(flat, deep);
|
assert_eq!(flat, deep);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,41 +1,39 @@
|
||||||
use schemars::MakeSchema;
|
|
||||||
|
|
||||||
mod util;
|
mod util;
|
||||||
|
use schemars::MakeSchema;
|
||||||
use util::*;
|
use util::*;
|
||||||
|
|
||||||
#[derive(MakeSchema)]
|
#[derive(Debug, MakeSchema)]
|
||||||
pub struct MyStruct<T, U, V, W> {
|
struct MyStruct<T, U, V, W> {
|
||||||
pub t: T,
|
t: T,
|
||||||
pub u: U,
|
u: U,
|
||||||
pub v: V,
|
v: V,
|
||||||
pub w: W,
|
w: W,
|
||||||
pub inner: MySimpleStruct,
|
inner: MySimpleStruct,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(MakeSchema)]
|
#[derive(Debug, MakeSchema)]
|
||||||
pub struct MySimpleStruct {}
|
struct MySimpleStruct {}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn default_name_multiple_type_params() -> TestResult {
|
fn default_name_multiple_type_params() -> TestResult {
|
||||||
test_default_generated_schema::<MyStruct<i32, (), bool, Vec<String>>>("naming-default")
|
test_default_generated_schema::<MyStruct<i32, (), bool, Vec<String>>>("naming-default")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(MakeSchema)]
|
#[derive(Debug, MakeSchema)]
|
||||||
#[serde(rename = "a-new-name-<W>-<T>-<T>")]
|
#[serde(rename = "a-new-name-{W}-{T}-{T}")]
|
||||||
pub struct MyRenamedStruct<T, U, V, W> {
|
struct MyRenamedStruct<T, U, V, W> {
|
||||||
pub t: T,
|
t: T,
|
||||||
pub u: U,
|
u: U,
|
||||||
pub v: V,
|
v: V,
|
||||||
pub w: W,
|
w: W,
|
||||||
pub inner: MySimpleRenamedStruct,
|
inner: MySimpleRenamedStruct,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(MakeSchema)]
|
#[derive(Debug, MakeSchema)]
|
||||||
#[serde(rename = "another-new-name")]
|
#[serde(rename = "another-new-name")]
|
||||||
pub struct MySimpleRenamedStruct {}
|
struct MySimpleRenamedStruct {}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore] // not yet implemented
|
fn overriden_with_rename_multiple_type_params() -> TestResult {
|
||||||
fn overriden_with_rename_name_multiple_type_params() -> TestResult {
|
|
||||||
test_default_generated_schema::<MyRenamedStruct<i32, (), bool, Vec<String>>>("naming-custom")
|
test_default_generated_schema::<MyRenamedStruct<i32, (), bool, Vec<String>>>("naming-custom")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
mod util;
|
||||||
use schemars::gen::SchemaSettings;
|
use schemars::gen::SchemaSettings;
|
||||||
use schemars::schema::Schema;
|
use schemars::schema::Schema;
|
||||||
|
|
||||||
mod util;
|
|
||||||
use util::*;
|
use util::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -6,21 +6,7 @@ use std::panic;
|
||||||
|
|
||||||
pub type TestResult = Result<(), Box<dyn Error>>;
|
pub type TestResult = Result<(), Box<dyn Error>>;
|
||||||
|
|
||||||
pub fn test_default_generated_schema<T: MakeSchema>(file: &str) -> TestResult {
|
#[allow(dead_code)] // https://github.com/rust-lang/rust/issues/46379
|
||||||
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(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn test_generated_schema<T: MakeSchema>(file: &str, settings: SchemaSettings) -> TestResult {
|
pub fn test_generated_schema<T: MakeSchema>(file: &str, settings: SchemaSettings) -> TestResult {
|
||||||
let expected_json = fs::read_to_string(format!("tests/expected/{}.json", file))?;
|
let expected_json = fs::read_to_string(format!("tests/expected/{}.json", file))?;
|
||||||
let expected = serde_json::from_str(&expected_json)?;
|
let expected = serde_json::from_str(&expected_json)?;
|
||||||
|
@ -35,3 +21,19 @@ pub fn test_generated_schema<T: MakeSchema>(file: &str, settings: SchemaSettings
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)] // https://github.com/rust-lang/rust/issues/46379
|
||||||
|
pub fn test_default_generated_schema<T: MakeSchema>(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(())
|
||||||
|
}
|
|
@ -15,8 +15,10 @@ use syn::{DeriveInput, GenericParam, Generics};
|
||||||
#[proc_macro_derive(MakeSchema, attributes(schemars, serde))]
|
#[proc_macro_derive(MakeSchema, attributes(schemars, serde))]
|
||||||
pub fn derive_make_schema(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
pub fn derive_make_schema(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
let mut input = parse_macro_input!(input as DeriveInput);
|
let mut input = parse_macro_input!(input as DeriveInput);
|
||||||
|
|
||||||
// TODO is mutating the input really the best way to do this?
|
// TODO is mutating the input really the best way to do this?
|
||||||
add_trait_bounds(&mut input.generics);
|
add_trait_bounds(&mut input.generics);
|
||||||
|
|
||||||
let ctxt = Ctxt::new();
|
let ctxt = Ctxt::new();
|
||||||
let cont = Container::from_ast(&ctxt, &input, Derive::Deserialize);
|
let cont = Container::from_ast(&ctxt, &input, Derive::Deserialize);
|
||||||
if let Err(e) = ctxt.check() {
|
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!"),
|
_ => 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_params: Vec<_> = cont.generics.type_params().map(|ty| &ty.ident).collect();
|
||||||
let type_param_fmt = match type_params.len() {
|
|
||||||
0 => "{}".to_owned(),
|
let schema_base_name = cont.attrs.name().deserialize_name();
|
||||||
n => format!("{{}}_For_{{}}{}", "_And_{}".repeat(n - 1)),
|
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_generics, ty_generics, where_clause) = cont.generics.split_for_impl();
|
||||||
|
|
||||||
let impl_block = quote! {
|
let impl_block = quote! {
|
||||||
#[automatically_derived]
|
#[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 {
|
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 {
|
fn make_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::Result {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue