summaryrefslogtreecommitdiffstats
path: root/vendor/serde_derive/src/internals/check.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/serde_derive/src/internals/check.rs')
-rw-r--r--vendor/serde_derive/src/internals/check.rs46
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();