diff options
Diffstat (limited to 'vendor/serde_derive/src/internals/check.rs')
-rw-r--r-- | vendor/serde_derive/src/internals/check.rs | 46 |
1 files changed, 41 insertions, 5 deletions
diff --git a/vendor/serde_derive/src/internals/check.rs b/vendor/serde_derive/src/internals/check.rs index 4a7f52c6c..b01a8ca4d 100644 --- a/vendor/serde_derive/src/internals/check.rs +++ b/vendor/serde_derive/src/internals/check.rs @@ -1,11 +1,12 @@ -use internals::ast::{Container, Data, Field, Style}; -use internals::attr::{Identifier, TagType}; -use internals::{ungroup, Ctxt, Derive}; +use crate::internals::ast::{Container, Data, Field, Style}; +use crate::internals::attr::{Default, Identifier, TagType}; +use crate::internals::{ungroup, Ctxt, Derive}; use syn::{Member, Type}; // Cross-cutting checks that require looking at more than a single attrs object. // Simpler checks should happen when parsing and building the attrs. pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) { + check_default_on_tuple(cx, cont); check_remote_generic(cx, cont); check_getter(cx, cont); check_flatten(cx, cont); @@ -17,6 +18,39 @@ pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) { check_from_and_try_from(cx, cont); } +// If some field of a tuple struct is marked #[serde(default)] then all fields +// after it must also be marked with that attribute, or the struct must have a +// container-level serde(default) attribute. A field's default value is only +// used for tuple fields if the sequence is exhausted at that point; that means +// all subsequent fields will fail to deserialize if they don't have their own +// default. +fn check_default_on_tuple(cx: &Ctxt, cont: &Container) { + if let Default::None = cont.attrs.default() { + if let Data::Struct(Style::Tuple, fields) = &cont.data { + let mut first_default_index = None; + for (i, field) in fields.iter().enumerate() { + // Skipped fields automatically get the #[serde(default)] + // attribute. We are interested only on non-skipped fields here. + if field.attrs.skip_deserializing() { + continue; + } + if let Default::None = field.attrs.default() { + if let Some(first) = first_default_index { + cx.error_spanned_by( + field.ty, + format!("field must have #[serde(default)] because previous field {} has #[serde(default)]", first), + ); + } + continue; + } + if first_default_index.is_none() { + first_default_index = Some(i); + } + } + } + } +} + // Remote derive definition type must have either all of the generics of the // remote type: // @@ -285,8 +319,10 @@ fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) { match variant.style { Style::Struct => { for field in &variant.fields { - let check_ser = !field.attrs.skip_serializing(); - let check_de = !field.attrs.skip_deserializing(); + let check_ser = + !(field.attrs.skip_serializing() || variant.attrs.skip_serializing()); + let check_de = + !(field.attrs.skip_deserializing() || variant.attrs.skip_deserializing()); let name = field.attrs.name(); let ser_name = name.serialize_name(); |