Do not pass container attributes through enums/variants

When deriving JsonSchema over a struct-style enum variant, do not apply the enum's container attributes to the variant. This couldn't cause any problems in practice because the only container attribute we explicitly set is "default", which cannot be set on an enum.
This commit is contained in:
Graham Esau 2019-12-23 20:50:26 +00:00
parent fc592e5dd7
commit d30238c981

View file

@ -35,7 +35,7 @@ pub fn derive_json_schema(input: proc_macro::TokenStream) -> proc_macro::TokenSt
Data::Struct(Style::Unit, _) => schema_for_unit_struct(), Data::Struct(Style::Unit, _) => schema_for_unit_struct(),
Data::Struct(Style::Newtype, ref fields) => schema_for_newtype_struct(&fields[0]), Data::Struct(Style::Newtype, ref fields) => schema_for_newtype_struct(&fields[0]),
Data::Struct(Style::Tuple, ref fields) => schema_for_tuple_struct(fields), Data::Struct(Style::Tuple, ref fields) => schema_for_tuple_struct(fields),
Data::Struct(Style::Struct, ref fields) => schema_for_struct(fields, &cont.attrs), Data::Struct(Style::Struct, ref fields) => schema_for_struct(fields, Some(&cont.attrs)),
Data::Enum(ref variants) => schema_for_enum(variants, &cont.attrs), Data::Enum(ref variants) => schema_for_enum(variants, &cont.attrs),
}; };
let schema_expr = set_metadata_on_schema_from_docs(schema_expr, &cont.original.attrs); let schema_expr = set_metadata_on_schema_from_docs(schema_expr, &cont.original.attrs);
@ -117,16 +117,15 @@ fn is_unit_variant(v: &Variant) -> bool {
fn schema_for_enum(variants: &[Variant], cattrs: &serde_attr::Container) -> TokenStream { fn schema_for_enum(variants: &[Variant], cattrs: &serde_attr::Container) -> TokenStream {
let variants = variants.iter().filter(|v| !v.attrs.skip_deserializing()); let variants = variants.iter().filter(|v| !v.attrs.skip_deserializing());
match cattrs.tag() { match cattrs.tag() {
TagType::External => schema_for_external_tagged_enum(variants, cattrs), TagType::External => schema_for_external_tagged_enum(variants),
TagType::None => schema_for_untagged_enum(variants, cattrs), TagType::None => schema_for_untagged_enum(variants),
TagType::Internal { tag } => schema_for_internal_tagged_enum(variants, cattrs, tag), TagType::Internal { tag } => schema_for_internal_tagged_enum(variants, tag),
TagType::Adjacent { .. } => unimplemented!("Adjacent tagged enums not yet supported."), TagType::Adjacent { .. } => unimplemented!("Adjacent tagged enums not yet supported."),
} }
} }
fn schema_for_external_tagged_enum<'a>( fn schema_for_external_tagged_enum<'a>(
variants: impl Iterator<Item = &'a Variant<'a>>, variants: impl Iterator<Item = &'a Variant<'a>>
cattrs: &serde_attr::Container,
) -> TokenStream { ) -> TokenStream {
let (unit_variants, complex_variants): (Vec<_>, Vec<_>) = let (unit_variants, complex_variants): (Vec<_>, Vec<_>) =
variants.partition(|v| is_unit_variant(v)); variants.partition(|v| is_unit_variant(v));
@ -150,7 +149,7 @@ fn schema_for_external_tagged_enum<'a>(
schemas.extend(complex_variants.into_iter().map(|variant| { schemas.extend(complex_variants.into_iter().map(|variant| {
let name = variant.attrs.name().deserialize_name(); let name = variant.attrs.name().deserialize_name();
let sub_schema = schema_for_untagged_enum_variant(variant, cattrs); let sub_schema = schema_for_untagged_enum_variant(variant);
let schema_expr = wrap_schema_fields(quote! { let schema_expr = wrap_schema_fields(quote! {
instance_type: Some(schemars::schema::InstanceType::Object.into()), instance_type: Some(schemars::schema::InstanceType::Object.into()),
object: Some(Box::new(schemars::schema::ObjectValidation { object: Some(Box::new(schemars::schema::ObjectValidation {
@ -180,7 +179,6 @@ fn schema_for_external_tagged_enum<'a>(
fn schema_for_internal_tagged_enum<'a>( fn schema_for_internal_tagged_enum<'a>(
variants: impl Iterator<Item = &'a Variant<'a>>, variants: impl Iterator<Item = &'a Variant<'a>>,
cattrs: &serde_attr::Container,
tag_name: &str, tag_name: &str,
) -> TokenStream { ) -> TokenStream {
let schemas = variants.map(|variant| { let schemas = variants.map(|variant| {
@ -217,7 +215,7 @@ fn schema_for_internal_tagged_enum<'a>(
<#ty>::json_schema(gen) <#ty>::json_schema(gen)
} }
} }
Style::Struct => schema_for_struct(&variant.fields, cattrs), Style::Struct => schema_for_struct(&variant.fields, None),
Style::Tuple => unreachable!("Internal tagged enum tuple variants will have caused serde_derive_internals to output a compile error already."), Style::Tuple => unreachable!("Internal tagged enum tuple variants will have caused serde_derive_internals to output a compile error already."),
}; };
quote! { quote! {
@ -234,11 +232,10 @@ fn schema_for_internal_tagged_enum<'a>(
} }
fn schema_for_untagged_enum<'a>( fn schema_for_untagged_enum<'a>(
variants: impl Iterator<Item = &'a Variant<'a>>, variants: impl Iterator<Item = &'a Variant<'a>>
cattrs: &serde_attr::Container,
) -> TokenStream { ) -> TokenStream {
let schemas = variants.map(|variant| { let schemas = variants.map(|variant| {
let schema_expr = schema_for_untagged_enum_variant(variant, cattrs); let schema_expr = schema_for_untagged_enum_variant(variant);
set_metadata_on_schema_from_docs(schema_expr, &variant.original.attrs) set_metadata_on_schema_from_docs(schema_expr, &variant.original.attrs)
}); });
@ -251,14 +248,13 @@ fn schema_for_untagged_enum<'a>(
} }
fn schema_for_untagged_enum_variant( fn schema_for_untagged_enum_variant(
variant: &Variant, variant: &Variant
cattrs: &serde_attr::Container,
) -> TokenStream { ) -> TokenStream {
match variant.style { match variant.style {
Style::Unit => schema_for_unit_struct(), Style::Unit => schema_for_unit_struct(),
Style::Newtype => schema_for_newtype_struct(&variant.fields[0]), Style::Newtype => schema_for_newtype_struct(&variant.fields[0]),
Style::Tuple => schema_for_tuple_struct(&variant.fields), Style::Tuple => schema_for_tuple_struct(&variant.fields),
Style::Struct => schema_for_struct(&variant.fields, cattrs), Style::Struct => schema_for_struct(&variant.fields, None),
} }
} }
@ -285,13 +281,13 @@ fn schema_for_tuple_struct(fields: &[Field]) -> TokenStream {
} }
} }
fn schema_for_struct(fields: &[Field], cattrs: &serde_attr::Container) -> TokenStream { fn schema_for_struct(fields: &[Field], cattrs: Option<&serde_attr::Container>) -> TokenStream {
let (flat, nested): (Vec<_>, Vec<_>) = fields let (flat, nested): (Vec<_>, Vec<_>) = fields
.iter() .iter()
.filter(|f| !f.attrs.skip_deserializing() || !f.attrs.skip_serializing()) .filter(|f| !f.attrs.skip_deserializing() || !f.attrs.skip_serializing())
.partition(|f| f.attrs.flatten()); .partition(|f| f.attrs.flatten());
let set_container_default = match cattrs.default() { let set_container_default = match cattrs.map_or(&SerdeDefault::None, |c| c.default()) {
SerdeDefault::None => None, SerdeDefault::None => None,
SerdeDefault::Default => Some(quote!(let container_default = Self::default();)), SerdeDefault::Default => Some(quote!(let container_default = Self::default();)),
SerdeDefault::Path(path) => Some(quote!(let container_default = #path();)), SerdeDefault::Path(path) => Some(quote!(let container_default = #path();)),