diff --git a/serde/src/de/mod.rs b/serde/src/de/mod.rs index a251e715..608c6580 100644 --- a/serde/src/de/mod.rs +++ b/serde/src/de/mod.rs @@ -46,6 +46,12 @@ pub trait Error: Sized + error::Error { fn missing_field(field: &'static str) -> Self { Error::custom(format!("Missing field `{}`", field)) } + + /// Raised when a `Deserialize` struct type received more than one of the + /// same struct field. + fn duplicate_field(field: &'static str) -> Self { + Error::custom(format!("Duplicate field `{}`", field)) + } } /// `Type` represents all the primitive types that can be deserialized. This is used by diff --git a/serde_codegen/src/de.rs b/serde_codegen/src/de.rs index f98fe765..2d92aa39 100644 --- a/serde_codegen/src/de.rs +++ b/serde_codegen/src/de.rs @@ -1156,6 +1156,9 @@ fn deserialize_map( let value_arms = fields_attrs_names.iter() .filter(|&&(_, ref attrs, _)| !attrs.skip_deserializing_field()) .map(|&(field, ref attrs, name)| { + let deser_name = attrs.name().deserialize_name(); + let name_str = builder.expr().lit().str(deser_name); + let visit = match attrs.deserialize_with() { None => { let field_ty = &field.ty; @@ -1173,6 +1176,9 @@ fn deserialize_map( }; quote_arm!(cx, __Field::$name => { + if $name.is_some() { + return Err(<__V::Error as _serde::de::Error>::duplicate_field($name_str)); + } $name = Some($visit); } ) diff --git a/serde_tests/tests/test_de.rs b/serde_tests/tests/test_de.rs index 601710ad..27794aeb 100644 --- a/serde_tests/tests/test_de.rs +++ b/serde_tests/tests/test_de.rs @@ -725,4 +725,32 @@ declare_error_tests! { ], Error::UnexpectedToken(Token::SeqSep), } + test_duplicate_field_struct { + vec![ + Token::MapStart(Some(3)), + Token::MapSep, + Token::Str("a"), + Token::I32(1), + + Token::MapSep, + Token::Str("a"), + Token::I32(3), + Token::MapEnd, + ], + Error::DuplicateFieldError("a"), + } + test_duplicate_field_enum { + vec![ + Token::EnumMapStart("Enum", "Map", Some(3)), + Token::EnumMapSep, + Token::Str("a"), + Token::I32(1), + + Token::EnumMapSep, + Token::Str("a"), + Token::I32(3), + Token::EnumMapEnd, + ], + Error::DuplicateFieldError("a"), + } } diff --git a/serde_tests/tests/token.rs b/serde_tests/tests/token.rs index f61800bd..bd20a982 100644 --- a/serde_tests/tests/token.rs +++ b/serde_tests/tests/token.rs @@ -410,6 +410,7 @@ pub enum Error { UnknownFieldError(String), UnknownVariantError(String), MissingFieldError(&'static str), + DuplicateFieldError(&'static str), InvalidName(&'static str), InvalidValue(String), UnexpectedToken(Token<'static>), @@ -429,6 +430,10 @@ impl de::Error for Error { fn end_of_stream() -> Error { Error::EndOfStreamError } + fn invalid_value(msg: &str) -> Error { + Error::InvalidValue(msg.to_owned()) + } + fn unknown_field(field: &str) -> Error { Error::UnknownFieldError(field.to_owned()) } @@ -440,6 +445,10 @@ impl de::Error for Error { fn missing_field(field: &'static str) -> Error { Error::MissingFieldError(field) } + + fn duplicate_field(field: &'static str) -> Error { + Error::DuplicateFieldError(field) + } } impl fmt::Display for Error {