schema_with
attribute
This commit is contained in:
parent
9d951b34ce
commit
3fd316063a
15 changed files with 538 additions and 51 deletions
|
@ -1,8 +1,12 @@
|
|||
# Changelog
|
||||
|
||||
## In-dev - version TBC
|
||||
### Added:
|
||||
- `#[schemars(schema_with = "...")]` attribute can be set on variants and fields. This allows you to specify another function which returns the schema you want, which is particularly useful on fields of types that don't implement the JsonSchema trait (https://github.com/GREsau/schemars/issues/15)
|
||||
|
||||
### Fixed
|
||||
- `#[serde(with = "...")]`/`#[schemars(with = "...")]` attributes on enum variants are now respected
|
||||
- Some compiler errors generated by schemars_derive should now have more accurate spans
|
||||
|
||||
## [0.7.2] - 2020-04-30
|
||||
### Added:
|
||||
|
|
|
@ -2,6 +2,9 @@ mod util;
|
|||
use schemars::{JsonSchema, Map};
|
||||
use util::*;
|
||||
|
||||
// Ensure that schemars_derive uses the full path to std::string::String
|
||||
pub struct String;
|
||||
|
||||
#[derive(Debug, JsonSchema)]
|
||||
pub struct UnitStruct;
|
||||
|
||||
|
@ -15,7 +18,7 @@ pub struct Struct {
|
|||
#[schemars(rename_all = "camelCase")]
|
||||
pub enum External {
|
||||
UnitOne,
|
||||
StringMap(Map<String, String>),
|
||||
StringMap(Map<&'static str, &'static str>),
|
||||
UnitStructNewType(UnitStruct),
|
||||
StructNewType(Struct),
|
||||
Struct {
|
||||
|
@ -37,7 +40,7 @@ fn enum_external_tag() -> TestResult {
|
|||
#[schemars(tag = "typeProperty")]
|
||||
pub enum Internal {
|
||||
UnitOne,
|
||||
StringMap(Map<String, String>),
|
||||
StringMap(Map<&'static str, &'static str>),
|
||||
UnitStructNewType(UnitStruct),
|
||||
StructNewType(Struct),
|
||||
Struct {
|
||||
|
@ -58,7 +61,7 @@ fn enum_internal_tag() -> TestResult {
|
|||
#[schemars(untagged)]
|
||||
pub enum Untagged {
|
||||
UnitOne,
|
||||
StringMap(Map<String, String>),
|
||||
StringMap(Map<&'static str, &'static str>),
|
||||
UnitStructNewType(UnitStruct),
|
||||
StructNewType(Struct),
|
||||
Struct {
|
||||
|
@ -79,7 +82,7 @@ fn enum_untagged() -> TestResult {
|
|||
#[schemars(tag = "t", content = "c")]
|
||||
pub enum Adjacent {
|
||||
UnitOne,
|
||||
StringMap(Map<String, String>),
|
||||
StringMap(Map<&'static str, &'static str>),
|
||||
UnitStructNewType(UnitStruct),
|
||||
StructNewType(Struct),
|
||||
Struct {
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Adjacent",
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"c",
|
||||
"t"
|
||||
],
|
||||
"properties": {
|
||||
"c": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"foo"
|
||||
],
|
||||
"properties": {
|
||||
"foo": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Struct"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"c",
|
||||
"t"
|
||||
],
|
||||
"properties": {
|
||||
"c": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"t": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"NewType"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"c",
|
||||
"t"
|
||||
],
|
||||
"properties": {
|
||||
"c": {
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
},
|
||||
"t": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Tuple"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
58
schemars/tests/expected/schema_with-enum-external.json
Normal file
58
schemars/tests/expected/schema_with-enum-external.json
Normal file
|
@ -0,0 +1,58 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "External",
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"struct"
|
||||
],
|
||||
"properties": {
|
||||
"struct": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"foo"
|
||||
],
|
||||
"properties": {
|
||||
"foo": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"newType"
|
||||
],
|
||||
"properties": {
|
||||
"newType": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"tuple"
|
||||
],
|
||||
"properties": {
|
||||
"tuple": {
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
41
schemars/tests/expected/schema_with-enum-internal.json
Normal file
41
schemars/tests/expected/schema_with-enum-internal.json
Normal file
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Internal",
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"foo",
|
||||
"typeProperty"
|
||||
],
|
||||
"properties": {
|
||||
"foo": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"typeProperty": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Struct"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": [
|
||||
"boolean",
|
||||
"object"
|
||||
],
|
||||
"required": [
|
||||
"typeProperty"
|
||||
],
|
||||
"properties": {
|
||||
"typeProperty": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"NewType"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
34
schemars/tests/expected/schema_with-enum-untagged.json
Normal file
34
schemars/tests/expected/schema_with-enum-untagged.json
Normal file
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Untagged",
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"foo"
|
||||
],
|
||||
"properties": {
|
||||
"foo": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
],
|
||||
"maxItems": 2,
|
||||
"minItems": 2
|
||||
}
|
||||
]
|
||||
}
|
5
schemars/tests/expected/schema_with-newtype.json
Normal file
5
schemars/tests/expected/schema_with-newtype.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Newtype",
|
||||
"type": "boolean"
|
||||
}
|
22
schemars/tests/expected/schema_with-struct.json
Normal file
22
schemars/tests/expected/schema_with-struct.json
Normal file
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Struct",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"bar",
|
||||
"baz",
|
||||
"foo"
|
||||
],
|
||||
"properties": {
|
||||
"bar": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"baz": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"foo": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
19
schemars/tests/expected/schema_with-tuple.json
Normal file
19
schemars/tests/expected/schema_with-tuple.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Tuple",
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
{
|
||||
"type": "boolean"
|
||||
}
|
||||
],
|
||||
"maxItems": 3,
|
||||
"minItems": 3
|
||||
}
|
92
schemars/tests/schema_with_enum.rs
Normal file
92
schemars/tests/schema_with_enum.rs
Normal file
|
@ -0,0 +1,92 @@
|
|||
mod util;
|
||||
use schemars::JsonSchema;
|
||||
use util::*;
|
||||
|
||||
// FIXME determine whether schema_with should be allowed on unit variants
|
||||
|
||||
fn schema_fn(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
|
||||
<bool>::json_schema(gen)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DoesntImplementJsonSchema;
|
||||
|
||||
#[derive(Debug, JsonSchema)]
|
||||
#[schemars(rename_all = "camelCase")]
|
||||
pub enum External {
|
||||
Struct {
|
||||
#[schemars(schema_with = "schema_fn")]
|
||||
foo: DoesntImplementJsonSchema,
|
||||
},
|
||||
NewType(#[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema),
|
||||
Tuple(
|
||||
#[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema,
|
||||
i32,
|
||||
),
|
||||
// #[schemars(schema_with = "schema_fn")]
|
||||
// Unit,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enum_external_tag() -> TestResult {
|
||||
test_default_generated_schema::<External>("schema_with-enum-external")
|
||||
}
|
||||
|
||||
#[derive(Debug, JsonSchema)]
|
||||
#[schemars(tag = "typeProperty")]
|
||||
pub enum Internal {
|
||||
Struct {
|
||||
#[schemars(schema_with = "schema_fn")]
|
||||
foo: DoesntImplementJsonSchema,
|
||||
},
|
||||
NewType(#[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema),
|
||||
// #[schemars(schema_with = "schema_fn")]
|
||||
// Unit,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enum_internal_tag() -> TestResult {
|
||||
test_default_generated_schema::<Internal>("schema_with-enum-internal")
|
||||
}
|
||||
|
||||
#[derive(Debug, JsonSchema)]
|
||||
#[schemars(untagged)]
|
||||
pub enum Untagged {
|
||||
Struct {
|
||||
#[schemars(schema_with = "schema_fn")]
|
||||
foo: DoesntImplementJsonSchema,
|
||||
},
|
||||
NewType(#[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema),
|
||||
Tuple(
|
||||
#[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema,
|
||||
i32,
|
||||
),
|
||||
// #[schemars(schema_with = "schema_fn")]
|
||||
// Unit,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enum_untagged() -> TestResult {
|
||||
test_default_generated_schema::<Untagged>("schema_with-enum-untagged")
|
||||
}
|
||||
|
||||
#[derive(Debug, JsonSchema)]
|
||||
#[schemars(tag = "t", content = "c")]
|
||||
pub enum Adjacent {
|
||||
Struct {
|
||||
#[schemars(schema_with = "schema_fn")]
|
||||
foo: DoesntImplementJsonSchema,
|
||||
},
|
||||
NewType(#[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema),
|
||||
Tuple(
|
||||
#[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema,
|
||||
i32,
|
||||
),
|
||||
// #[schemars(schema_with = "schema_fn")]
|
||||
// Unit,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enum_adjacent_tagged() -> TestResult {
|
||||
test_default_generated_schema::<Adjacent>("schema_with-enum-adjacent-tagged")
|
||||
}
|
44
schemars/tests/schema_with_struct.rs
Normal file
44
schemars/tests/schema_with_struct.rs
Normal file
|
@ -0,0 +1,44 @@
|
|||
mod util;
|
||||
use schemars::JsonSchema;
|
||||
use util::*;
|
||||
|
||||
fn schema_fn(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
|
||||
<bool>::json_schema(gen)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DoesntImplementJsonSchema;
|
||||
|
||||
#[derive(Debug, JsonSchema)]
|
||||
pub struct Struct {
|
||||
#[schemars(schema_with = "schema_fn")]
|
||||
foo: DoesntImplementJsonSchema,
|
||||
bar: i32,
|
||||
#[schemars(schema_with = "schema_fn")]
|
||||
baz: DoesntImplementJsonSchema,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn struct_normal() -> TestResult {
|
||||
test_default_generated_schema::<Struct>("schema_with-struct")
|
||||
}
|
||||
|
||||
#[derive(Debug, JsonSchema)]
|
||||
pub struct Tuple(
|
||||
#[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema,
|
||||
i32,
|
||||
#[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema,
|
||||
);
|
||||
|
||||
#[test]
|
||||
fn struct_tuple() -> TestResult {
|
||||
test_default_generated_schema::<Tuple>("schema_with-tuple")
|
||||
}
|
||||
|
||||
#[derive(Debug, JsonSchema)]
|
||||
pub struct Newtype(#[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema);
|
||||
|
||||
#[test]
|
||||
fn struct_newtype() -> TestResult {
|
||||
test_default_generated_schema::<Newtype>("schema_with-newtype")
|
||||
}
|
|
@ -2,11 +2,14 @@ mod util;
|
|||
use schemars::JsonSchema;
|
||||
use util::*;
|
||||
|
||||
// Ensure that schemars_derive uses the full path to std::string::String
|
||||
pub struct String;
|
||||
|
||||
#[derive(Debug, JsonSchema)]
|
||||
pub struct Struct {
|
||||
foo: i32,
|
||||
bar: bool,
|
||||
baz: Option<String>,
|
||||
baz: Option<&'static str>,
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -15,7 +18,7 @@ fn struct_normal() -> TestResult {
|
|||
}
|
||||
|
||||
#[derive(Debug, JsonSchema)]
|
||||
pub struct Tuple(i32, bool, Option<String>);
|
||||
pub struct Tuple(i32, bool, Option<&'static str>);
|
||||
|
||||
#[test]
|
||||
fn struct_tuple() -> TestResult {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
mod from_serde;
|
||||
|
||||
use crate::attr::{Attrs, WithAttr};
|
||||
use crate::attr::Attrs;
|
||||
use from_serde::FromSerde;
|
||||
use serde_derive_internals::ast as serde_ast;
|
||||
use serde_derive_internals::{Ctxt, Derive};
|
||||
|
@ -68,12 +68,4 @@ impl<'a> Field<'a> {
|
|||
pub fn name(&self) -> String {
|
||||
self.serde_attrs.name().deserialize_name()
|
||||
}
|
||||
|
||||
pub fn type_for_schema(&self) -> &syn::Type {
|
||||
match &self.attrs.with {
|
||||
None => self.ty,
|
||||
Some(WithAttr::Type(ty)) => ty,
|
||||
Some(WithAttr::_Function(_)) => unimplemented!(), // TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ pub struct Attrs {
|
|||
#[derive(Debug)]
|
||||
pub enum WithAttr {
|
||||
Type(syn::Type),
|
||||
_Function(syn::Path),
|
||||
Function(syn::Path),
|
||||
}
|
||||
|
||||
impl Attrs {
|
||||
|
@ -74,14 +74,22 @@ impl Attrs {
|
|||
if let Ok(ty) = parse_lit_into_ty(errors, attr_type, "with", &m.lit) {
|
||||
match self.with {
|
||||
Some(WithAttr::Type(_)) => duplicate_error(m),
|
||||
Some(WithAttr::_Function(_)) => {
|
||||
mutual_exclusive_error(m, "schema_with")
|
||||
}
|
||||
Some(WithAttr::Function(_)) => mutual_exclusive_error(m, "schema_with"),
|
||||
None => self.with = Some(WithAttr::Type(ty)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Meta(NameValue(m)) if m.path.is_ident("schema_with") => {
|
||||
if let Ok(fun) = parse_lit_into_path(errors, attr_type, "schema_with", &m.lit) {
|
||||
match self.with {
|
||||
Some(WithAttr::Function(_)) => duplicate_error(m),
|
||||
Some(WithAttr::Type(_)) => mutual_exclusive_error(m, "with"),
|
||||
None => self.with = Some(WithAttr::Function(fun)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Meta(_meta_item) => {
|
||||
// TODO uncomment this for 0.8.0 (breaking change)
|
||||
// https://github.com/GREsau/schemars/issues/18
|
||||
|
@ -148,8 +156,8 @@ fn get_lit_str<'a>(
|
|||
cx.error_spanned_by(
|
||||
lit,
|
||||
format!(
|
||||
"expected {} attribute to be a string: `{} = \"...\"`",
|
||||
attr_type, meta_item_name
|
||||
"expected {} {} attribute to be a string: `{} = \"...\"`",
|
||||
attr_type, meta_item_name, meta_item_name
|
||||
),
|
||||
);
|
||||
Err(())
|
||||
|
@ -167,7 +175,31 @@ fn parse_lit_into_ty(
|
|||
parse_lit_str(string).map_err(|_| {
|
||||
cx.error_spanned_by(
|
||||
lit,
|
||||
format!("failed to parse type: {} = {:?}", attr_type, string.value()),
|
||||
format!(
|
||||
"failed to parse type: `{} = {:?}`",
|
||||
meta_item_name,
|
||||
string.value()
|
||||
),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_lit_into_path(
|
||||
cx: &Ctxt,
|
||||
attr_type: &'static str,
|
||||
meta_item_name: &'static str,
|
||||
lit: &syn::Lit,
|
||||
) -> Result<syn::Path, ()> {
|
||||
let string = get_lit_str(cx, attr_type, meta_item_name, lit)?;
|
||||
|
||||
parse_lit_str(string).map_err(|_| {
|
||||
cx.error_spanned_by(
|
||||
lit,
|
||||
format!(
|
||||
"failed to parse path: `{} = {:?}`",
|
||||
meta_item_name,
|
||||
string.value()
|
||||
),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -17,6 +17,58 @@ pub fn expr_for_container(cont: &Container) -> TokenStream {
|
|||
doc_metadata.apply_to_schema(schema_expr)
|
||||
}
|
||||
|
||||
fn expr_for_field(field: &Field, allow_ref: bool) -> TokenStream {
|
||||
let (ty, type_def) = type_for_schema(field, 0);
|
||||
let span = field.original.span();
|
||||
|
||||
if allow_ref {
|
||||
quote_spanned! {span=>
|
||||
{
|
||||
#type_def
|
||||
gen.subschema_for::<#ty>()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote_spanned! {span=>
|
||||
{
|
||||
#type_def
|
||||
<#ty as schemars::JsonSchema>::json_schema(gen)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn type_for_schema(field: &Field, local_id: usize) -> (syn::Type, Option<TokenStream>) {
|
||||
match &field.attrs.with {
|
||||
None => (field.ty.to_owned(), None),
|
||||
Some(WithAttr::Type(ty)) => (ty.to_owned(), None),
|
||||
Some(WithAttr::Function(fun)) => {
|
||||
let ty_name = format_ident!("_SchemarsSchemaWithFunction{}", local_id);
|
||||
let fn_name = fun.segments.last().unwrap().ident.to_string();
|
||||
|
||||
let type_def = quote_spanned! {fun.span()=>
|
||||
struct #ty_name;
|
||||
|
||||
impl schemars::JsonSchema for #ty_name {
|
||||
fn is_referenceable() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn schema_name() -> std::string::String {
|
||||
#fn_name.to_string()
|
||||
}
|
||||
|
||||
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
|
||||
#fun(gen)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(parse_quote!(#ty_name), Some(type_def))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn expr_for_enum(variants: &[Variant], cattrs: &serde_attr::Container) -> TokenStream {
|
||||
let variants = variants
|
||||
.iter()
|
||||
|
@ -208,7 +260,7 @@ fn expr_for_untagged_enum_variant(variant: &Variant) -> TokenStream {
|
|||
|
||||
match variant.style {
|
||||
Style::Unit => expr_for_unit_struct(),
|
||||
Style::Newtype => expr_for_newtype_struct(&variant.fields[0]),
|
||||
Style::Newtype => expr_for_field(&variant.fields[0], true),
|
||||
Style::Tuple => expr_for_tuple_struct(&variant.fields),
|
||||
Style::Struct => expr_for_struct(&variant.fields, None),
|
||||
}
|
||||
|
@ -223,13 +275,7 @@ fn expr_for_untagged_enum_variant_for_flatten(variant: &Variant) -> Option<Token
|
|||
|
||||
Some(match variant.style {
|
||||
Style::Unit => return None,
|
||||
Style::Newtype => {
|
||||
let field = &variant.fields[0];
|
||||
let ty = field.type_for_schema();
|
||||
quote_spanned! {field.original.span()=>
|
||||
<#ty>::json_schema(gen)
|
||||
}
|
||||
}
|
||||
Style::Newtype => expr_for_field(&variant.fields[0], false),
|
||||
Style::Tuple => expr_for_tuple_struct(&variant.fields),
|
||||
Style::Struct => expr_for_struct(&variant.fields, None),
|
||||
})
|
||||
|
@ -242,20 +288,22 @@ fn expr_for_unit_struct() -> TokenStream {
|
|||
}
|
||||
|
||||
fn expr_for_newtype_struct(field: &Field) -> TokenStream {
|
||||
let ty = field.type_for_schema();
|
||||
quote_spanned! {field.original.span()=>
|
||||
gen.subschema_for::<#ty>()
|
||||
}
|
||||
expr_for_field(field, true)
|
||||
}
|
||||
|
||||
fn expr_for_tuple_struct(fields: &[Field]) -> TokenStream {
|
||||
let types = fields
|
||||
let (types, type_defs): (Vec<_>, Vec<_>) = fields
|
||||
.iter()
|
||||
.filter(|f| !f.serde_attrs.skip_deserializing())
|
||||
.map(Field::type_for_schema);
|
||||
.enumerate()
|
||||
.map(|(i, f)| type_for_schema(f, i))
|
||||
.unzip();
|
||||
quote! {
|
||||
{
|
||||
#(#type_defs)*
|
||||
gen.subschema_for::<(#(#types),*)>()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn expr_for_struct(fields: &[Field], cattrs: Option<&serde_attr::Container>) -> TokenStream {
|
||||
|
@ -270,7 +318,9 @@ fn expr_for_struct(fields: &[Field], cattrs: Option<&serde_attr::Container>) ->
|
|||
SerdeDefault::Path(path) => Some(quote!(let container_default = #path();)),
|
||||
});
|
||||
|
||||
let properties = property_fields.iter().map(|field| {
|
||||
let mut type_defs = Vec::new();
|
||||
|
||||
let properties: Vec<_> = property_fields.into_iter().map(|field| {
|
||||
let name = field.name();
|
||||
let default = field_default_expr(field, set_container_default.is_some());
|
||||
|
||||
|
@ -286,25 +336,34 @@ fn expr_for_struct(fields: &[Field], cattrs: Option<&serde_attr::Container>) ->
|
|||
..SchemaMetadata::from_doc_attrs(&field.original.attrs)
|
||||
};
|
||||
|
||||
let ty = field.type_for_schema();
|
||||
let span = field.original.span();
|
||||
|
||||
quote_spanned! {span=>
|
||||
<#ty>::add_schema_as_property(gen, &mut schema_object, #name.to_owned(), #metadata, #required);
|
||||
let (ty, type_def) = type_for_schema(field, type_defs.len());
|
||||
if let Some(type_def) = type_def {
|
||||
type_defs.push(type_def);
|
||||
}
|
||||
});
|
||||
|
||||
let flattens = flattened_fields.iter().map(|field| {
|
||||
let ty = field.type_for_schema();
|
||||
let span = field.original.span();
|
||||
|
||||
quote_spanned! {span=>
|
||||
.flatten(<#ty>::json_schema_for_flatten(gen))
|
||||
quote_spanned! {ty.span()=>
|
||||
<#ty as schemars::JsonSchema>::add_schema_as_property(gen, &mut schema_object, #name.to_owned(), #metadata, #required);
|
||||
}
|
||||
});
|
||||
|
||||
}).collect();
|
||||
|
||||
let flattens: Vec<_> = flattened_fields
|
||||
.into_iter()
|
||||
.map(|field| {
|
||||
let (ty, type_def) = type_for_schema(field, type_defs.len());
|
||||
if let Some(type_def) = type_def {
|
||||
type_defs.push(type_def);
|
||||
}
|
||||
|
||||
quote_spanned! {ty.span()=>
|
||||
.flatten(<#ty as schemars::JsonSchema>::json_schema_for_flatten(gen))
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
quote! {
|
||||
{
|
||||
#(#type_defs)*
|
||||
#set_container_default
|
||||
let mut schema_object = schemars::schema::SchemaObject {
|
||||
instance_type: Some(schemars::schema::InstanceType::Object.into()),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue