.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());
}
}
- handle_regular_field(field_def, field, false)?;
+ handle_regular_field(field_def, field, false, &attrs)?;
if attrs.flatten {
all_of_schemas.extend(quote::quote! {&});
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! {&});
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;
} else if !field_def.optional.expect_bool() {
error!(&field.ty => "non-optional Option type?");
}
+ } else {
+ attrs.check_non_option_type();
}
Ok(())
use std::convert::TryFrom;
+use proc_macro2::Span;
use syn::punctuated::Punctuated;
+use syn::spanned::Spanned;
use syn::Token;
/// Serde name types.
pub struct FieldAttrib {
pub rename: Option<syn::LitStr>,
pub flatten: bool,
+ has_skip_serializing_if: Option<Span>,
+ has_default: bool,
}
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 {