api-macro: make skip_serializing_if without default an error

except for Option types, since this causes deserialization issues

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2023-12-06 14:38:04 +01:00
parent 89b29415a4
commit 2435ab29e2
2 changed files with 25 additions and 3 deletions

View File

@ -168,7 +168,7 @@ fn handle_regular_struct(
.as_ref()
.ok_or_else(|| format_err!(field => "field without name?"))?;
if let Some(renamed) = attrs.rename {
if let Some(renamed) = attrs.rename.clone() {
(renamed.value(), ident.span())
} else if let Some(rename_all) = container_attrs.rename_all {
let name = rename_all.apply_to_field(&ident.to_string());
@ -201,7 +201,7 @@ fn handle_regular_struct(
}
}
handle_regular_field(field_def, field, false)?;
handle_regular_field(field_def, field, false, &attrs)?;
if attrs.flatten {
all_of_schemas.extend(quote::quote! {&});
@ -215,7 +215,7 @@ fn handle_regular_struct(
false,
Schema::blank(span),
);
handle_regular_field(&mut field_def, field, true)?;
handle_regular_field(&mut field_def, field, true, &attrs)?;
if attrs.flatten {
all_of_schemas.extend(quote::quote! {&});
@ -373,6 +373,7 @@ fn handle_regular_field(
field_def: &mut ObjectEntry,
field: &syn::Field,
derived: bool, // whether this field was missing in the schema
attrs: &serde::FieldAttrib,
) -> Result<(), Error> {
let schema: &mut Schema = &mut field_def.schema;
@ -389,6 +390,8 @@ fn handle_regular_field(
} else if !field_def.optional.expect_bool() {
error!(&field.ty => "non-optional Option type?");
}
} else {
attrs.check_non_option_type();
}
Ok(())

View File

@ -5,7 +5,9 @@
use std::convert::TryFrom;
use proc_macro2::Span;
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::Token;
/// Serde name types.
@ -171,6 +173,8 @@ impl TryFrom<&[syn::Attribute]> for ContainerAttrib {
pub struct FieldAttrib {
pub rename: Option<syn::LitStr>,
pub flatten: bool,
has_skip_serializing_if: Option<Span>,
has_default: bool,
}
impl FieldAttrib {
@ -200,11 +204,26 @@ impl FieldAttrib {
} else if path.is_ident("flatten") {
arg.require_path_only()?;
self.flatten = true;
} else if path.is_ident("skip_serializing_if") {
self.has_skip_serializing_if = Some(match arg.require_name_value() {
Ok(nv) => nv.span(),
Err(_) => arg.span(),
});
} else if path.is_ident("default") {
self.has_default = true;
}
}
Ok(())
}
pub fn check_non_option_type(&self) {
if let Some(span) = self.has_skip_serializing_if {
if !self.has_default {
error!(span, "`skip_serializing_if` without `default`");
}
}
}
}
impl TryFrom<&[syn::Attribute]> for FieldAttrib {