Refactoring

This commit is contained in:
Graham Esau 2021-04-16 16:53:15 +01:00
parent 4be21bd811
commit 5f841f2e5c
4 changed files with 117 additions and 101 deletions

View file

@ -5,6 +5,7 @@ mod validation;
pub use schemars_to_serde::process_serde_attrs;
pub use validation::ValidationAttrs;
use crate::metadata::SchemaMetadata;
use proc_macro2::{Group, Span, TokenStream, TokenTree};
use quote::ToTokens;
use serde_derive_internals::Ctxt;
@ -53,6 +54,27 @@ impl Attrs {
result
}
pub fn as_metadata(&self) -> SchemaMetadata<'_> {
#[allow(clippy::ptr_arg)]
fn none_if_empty(s: &String) -> Option<&str> {
if s.is_empty() {
None
} else {
Some(s)
}
}
SchemaMetadata {
title: self.title.as_ref().and_then(none_if_empty),
description: self.description.as_ref().and_then(none_if_empty),
deprecated: self.deprecated,
examples: &self.examples,
read_only: false,
write_only: false,
default: None,
}
}
fn populate(
mut self,
attrs: &[syn::Attribute],

View file

@ -120,7 +120,7 @@ impl ValidationAttrs {
self
}
pub fn apply_to_schema(&self, schema_expr: TokenStream) -> TokenStream {
pub fn apply_to_schema(&self, schema_expr: &mut TokenStream) {
let mut array_validation = Vec::new();
let mut number_validation = Vec::new();
let mut object_validation = Vec::new();
@ -200,7 +200,7 @@ impl ValidationAttrs {
|| string_validation.is_some()
|| format.is_some()
{
quote! {
*schema_expr = quote! {
{
let mut schema = #schema_expr;
if let schemars::schema::Schema::Object(schema_object) = &mut schema
@ -214,8 +214,6 @@ impl ValidationAttrs {
schema
}
}
} else {
schema_expr
}
}
}

View file

@ -1,5 +1,3 @@
use crate::attr;
use attr::Attrs;
use proc_macro2::TokenStream;
#[derive(Debug, Clone)]
@ -14,24 +12,10 @@ pub struct SchemaMetadata<'a> {
}
impl<'a> SchemaMetadata<'a> {
pub fn from_attrs(attrs: &'a Attrs) -> Self {
SchemaMetadata {
title: attrs.title.as_ref().and_then(none_if_empty),
description: attrs.description.as_ref().and_then(none_if_empty),
deprecated: attrs.deprecated,
examples: &attrs.examples,
read_only: false,
write_only: false,
default: None,
}
}
pub fn apply_to_schema(&self, schema_expr: TokenStream) -> TokenStream {
pub fn apply_to_schema(&self, schema_expr: &mut TokenStream) {
let setters = self.make_setters();
if setters.is_empty() {
schema_expr
} else {
quote! {
if !setters.is_empty() {
*schema_expr = quote! {
schemars::_private::apply_metadata(#schema_expr, schemars::schema::Metadata {
#(#setters)*
..Default::default()
@ -91,12 +75,3 @@ impl<'a> SchemaMetadata<'a> {
setters
}
}
#[allow(clippy::ptr_arg)]
fn none_if_empty(s: &String) -> Option<&str> {
if s.is_empty() {
None
} else {
Some(s)
}
}

View file

@ -5,7 +5,7 @@ use serde_derive_internals::attr::{self as serde_attr, Default as SerdeDefault,
use syn::spanned::Spanned;
pub fn expr_for_container(cont: &Container) -> TokenStream {
let schema_expr = match &cont.data {
let mut schema_expr = match &cont.data {
Data::Struct(Style::Unit, _) => expr_for_unit_struct(),
Data::Struct(Style::Newtype, fields) => expr_for_newtype_struct(&fields[0]),
Data::Struct(Style::Tuple, fields) => expr_for_tuple_struct(fields),
@ -17,8 +17,8 @@ pub fn expr_for_container(cont: &Container) -> TokenStream {
Data::Enum(variants) => expr_for_enum(variants, &cont.serde_attrs),
};
let doc_metadata = SchemaMetadata::from_attrs(&cont.attrs);
doc_metadata.apply_to_schema(schema_expr)
cont.attrs.as_metadata().apply_to_schema(&mut schema_expr);
schema_expr
}
pub fn expr_for_repr(cont: &Container) -> Result<TokenStream, syn::Error> {
@ -47,13 +47,13 @@ pub fn expr_for_repr(cont: &Container) -> Result<TokenStream, syn::Error> {
let enum_ident = &cont.ident;
let variant_idents = variants.iter().map(|v| &v.ident);
let schema_expr = schema_object(quote! {
let mut schema_expr = schema_object(quote! {
instance_type: Some(schemars::schema::InstanceType::Integer.into()),
enum_values: Some(vec![#((#enum_ident::#variant_idents as #repr_type).into()),*]),
});
let doc_metadata = SchemaMetadata::from_attrs(&cont.attrs);
Ok(doc_metadata.apply_to_schema(schema_expr))
cont.attrs.as_metadata().apply_to_schema(&mut schema_expr);
Ok(schema_expr)
}
fn expr_for_field(field: &Field, allow_ref: bool) -> TokenStream {
@ -61,29 +61,24 @@ fn expr_for_field(field: &Field, allow_ref: bool) -> TokenStream {
let span = field.original.span();
let gen = quote!(gen);
let schema_expr = if field.validation_attrs.required {
let mut schema_expr = if field.validation_attrs.required {
quote_spanned! {span=>
{
#type_def
<#ty as schemars::JsonSchema>::_schemars_private_non_optional_json_schema(#gen)
}
<#ty as schemars::JsonSchema>::_schemars_private_non_optional_json_schema(#gen)
}
} else if allow_ref {
quote_spanned! {span=>
{
#type_def
#gen.subschema_for::<#ty>()
}
#gen.subschema_for::<#ty>()
}
} else {
quote_spanned! {span=>
{
#type_def
<#ty as schemars::JsonSchema>::json_schema(#gen)
}
<#ty as schemars::JsonSchema>::json_schema(#gen)
}
};
field.validation_attrs.apply_to_schema(schema_expr)
prepend_type_def(type_def, &mut schema_expr);
field.validation_attrs.apply_to_schema(&mut schema_expr);
schema_expr
}
pub fn type_for_field_schema(field: &Field) -> (syn::Type, Option<TokenStream>) {
@ -167,7 +162,7 @@ fn expr_for_external_tagged_enum<'a>(
let name = variant.name();
let sub_schema = expr_for_untagged_enum_variant(variant, deny_unknown_fields);
let schema_expr = schema_object(quote! {
let mut schema_expr = schema_object(quote! {
instance_type: Some(schemars::schema::InstanceType::Object.into()),
object: Some(Box::new(schemars::schema::ObjectValidation {
properties: {
@ -184,8 +179,13 @@ fn expr_for_external_tagged_enum<'a>(
..Default::default()
})),
});
let doc_metadata = SchemaMetadata::from_attrs(&variant.attrs);
doc_metadata.apply_to_schema(schema_expr)
variant
.attrs
.as_metadata()
.apply_to_schema(&mut schema_expr);
schema_expr
}));
schema_object(quote! {
@ -208,7 +208,7 @@ fn expr_for_internal_tagged_enum<'a>(
enum_values: Some(vec![#name.into()]),
});
let tag_schema = schema_object(quote! {
let mut tag_schema = schema_object(quote! {
instance_type: Some(schemars::schema::InstanceType::Object.into()),
object: Some(Box::new(schemars::schema::ObjectValidation {
properties: {
@ -224,15 +224,16 @@ fn expr_for_internal_tagged_enum<'a>(
..Default::default()
})),
});
let doc_metadata = SchemaMetadata::from_attrs(&variant.attrs);
let tag_schema = doc_metadata.apply_to_schema(tag_schema);
match expr_for_untagged_enum_variant_for_flatten(&variant, deny_unknown_fields) {
Some(variant_schema) => quote! {
#tag_schema.flatten(#variant_schema)
},
None => tag_schema,
variant.attrs.as_metadata().apply_to_schema(&mut tag_schema);
if let Some(variant_schema) =
expr_for_untagged_enum_variant_for_flatten(&variant, deny_unknown_fields)
{
tag_schema.extend(quote!(.flatten(#variant_schema)))
}
tag_schema
});
schema_object(quote! {
@ -248,9 +249,14 @@ fn expr_for_untagged_enum<'a>(
deny_unknown_fields: bool,
) -> TokenStream {
let schemas = variants.map(|variant| {
let schema_expr = expr_for_untagged_enum_variant(variant, deny_unknown_fields);
let doc_metadata = SchemaMetadata::from_attrs(&variant.attrs);
doc_metadata.apply_to_schema(schema_expr)
let mut schema_expr = expr_for_untagged_enum_variant(variant, deny_unknown_fields);
variant
.attrs
.as_metadata()
.apply_to_schema(&mut schema_expr);
schema_expr
});
schema_object(quote! {
@ -297,7 +303,7 @@ fn expr_for_adjacent_tagged_enum<'a>(
TokenStream::new()
};
let outer_schema = schema_object(quote! {
let mut outer_schema = schema_object(quote! {
instance_type: Some(schemars::schema::InstanceType::Object.into()),
object: Some(Box::new(schemars::schema::ObjectValidation {
properties: {
@ -317,8 +323,12 @@ fn expr_for_adjacent_tagged_enum<'a>(
})),
});
let doc_metadata = SchemaMetadata::from_attrs(&variant.attrs);
doc_metadata.apply_to_schema(outer_schema)
variant
.attrs
.as_metadata()
.apply_to_schema(&mut outer_schema);
outer_schema
});
schema_object(quote! {
@ -333,12 +343,12 @@ fn expr_for_untagged_enum_variant(variant: &Variant, deny_unknown_fields: bool)
if let Some(with_attr) = &variant.attrs.with {
let (ty, type_def) = type_for_schema(with_attr);
let gen = quote!(gen);
return quote_spanned! {variant.original.span()=>
{
#type_def
#gen.subschema_for::<#ty>()
}
let mut schema_expr = quote_spanned! {variant.original.span()=>
#gen.subschema_for::<#ty>()
};
prepend_type_def(type_def, &mut schema_expr);
return schema_expr;
}
match variant.style {
@ -356,12 +366,12 @@ fn expr_for_untagged_enum_variant_for_flatten(
if let Some(with_attr) = &variant.attrs.with {
let (ty, type_def) = type_for_schema(with_attr);
let gen = quote!(gen);
return Some(quote_spanned! {variant.original.span()=>
{
#type_def
<#ty as schemars::JsonSchema>::json_schema(#gen)
}
});
let mut schema_expr = quote_spanned! {variant.original.span()=>
<#ty as schemars::JsonSchema>::json_schema(#gen)
};
prepend_type_def(type_def, &mut schema_expr);
return Some(schema_expr);
}
Some(match variant.style {
@ -429,17 +439,6 @@ fn expr_for_struct(
let (ty, type_def) = type_for_field_schema(field);
let gen = quote!(gen);
let schema_expr = if field.validation_attrs.required {
quote_spanned! {ty.span()=>
<#ty as schemars::JsonSchema>::_schemars_private_non_optional_json_schema(#gen)
}
} else {
quote_spanned! {ty.span()=>
#gen.subschema_for::<#ty>()
}
};
let maybe_insert_required = match (&default, field.validation_attrs.required) {
(Some(_), _) => TokenStream::new(),
(None, false) => {
@ -458,11 +457,22 @@ fn expr_for_struct(
read_only: field.serde_attrs.skip_deserializing(),
write_only: field.serde_attrs.skip_serializing(),
default,
..SchemaMetadata::from_attrs(&field.attrs)
..field.attrs.as_metadata()
};
let schema_expr = metadata.apply_to_schema(schema_expr);
let schema_expr = field.validation_attrs.apply_to_schema(schema_expr);
let gen = quote!(gen);
let mut schema_expr = if field.validation_attrs.required {
quote_spanned! {ty.span()=>
<#ty as schemars::JsonSchema>::_schemars_private_non_optional_json_schema(#gen)
}
} else {
quote_spanned! {ty.span()=>
#gen.subschema_for::<#ty>()
}
};
metadata.apply_to_schema(&mut schema_expr);
field.validation_attrs.apply_to_schema(&mut schema_expr);
quote! {
{
@ -486,12 +496,12 @@ fn expr_for_struct(
};
let args = quote!(gen, #required);
quote_spanned! {ty.span()=>
.flatten({
#type_def
schemars::_private::json_schema_for_flatten::<#ty>(#args)
})
}
let mut schema_expr = quote_spanned! {ty.span()=>
schemars::_private::json_schema_for_flatten::<#ty>(#args)
};
prepend_type_def(type_def, &mut schema_expr);
schema_expr
})
.collect();
@ -513,7 +523,7 @@ fn expr_for_struct(
#set_additional_properties
#(#properties)*
schemars::schema::Schema::Object(schema_object)
#(#flattens)*
#(.flatten(#flattens))*
}
}
}
@ -582,3 +592,14 @@ fn schema_object(properties: TokenStream) -> TokenStream {
})
}
}
fn prepend_type_def(type_def: Option<TokenStream>, schema_expr: &mut TokenStream) {
if let Some(type_def) = type_def {
*schema_expr = quote! {
{
#type_def
#schema_expr
}
}
}
}