feat(codegen): Detect repeated struct field when deserializing

This commit is contained in:
David Tolnay
2016-05-10 09:52:51 -07:00
parent 7aa0b6ce27
commit eeb4efc19c
4 changed files with 49 additions and 0 deletions
+6
View File
@@ -46,6 +46,12 @@ pub trait Error: Sized + error::Error {
fn missing_field(field: &'static str) -> Self { fn missing_field(field: &'static str) -> Self {
Error::custom(format!("Missing field `{}`", field)) 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 /// `Type` represents all the primitive types that can be deserialized. This is used by
+6
View File
@@ -1156,6 +1156,9 @@ fn deserialize_map(
let value_arms = fields_attrs_names.iter() let value_arms = fields_attrs_names.iter()
.filter(|&&(_, ref attrs, _)| !attrs.skip_deserializing_field()) .filter(|&&(_, ref attrs, _)| !attrs.skip_deserializing_field())
.map(|&(field, ref attrs, name)| { .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() { let visit = match attrs.deserialize_with() {
None => { None => {
let field_ty = &field.ty; let field_ty = &field.ty;
@@ -1173,6 +1176,9 @@ fn deserialize_map(
}; };
quote_arm!(cx, quote_arm!(cx,
__Field::$name => { __Field::$name => {
if $name.is_some() {
return Err(<__V::Error as _serde::de::Error>::duplicate_field($name_str));
}
$name = Some($visit); $name = Some($visit);
} }
) )
+28
View File
@@ -725,4 +725,32 @@ declare_error_tests! {
], ],
Error::UnexpectedToken(Token::SeqSep), Error::UnexpectedToken(Token::SeqSep),
} }
test_duplicate_field_struct<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<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"),
}
} }
+9
View File
@@ -410,6 +410,7 @@ pub enum Error {
UnknownFieldError(String), UnknownFieldError(String),
UnknownVariantError(String), UnknownVariantError(String),
MissingFieldError(&'static str), MissingFieldError(&'static str),
DuplicateFieldError(&'static str),
InvalidName(&'static str), InvalidName(&'static str),
InvalidValue(String), InvalidValue(String),
UnexpectedToken(Token<'static>), UnexpectedToken(Token<'static>),
@@ -429,6 +430,10 @@ impl de::Error for Error {
fn end_of_stream() -> Error { Error::EndOfStreamError } fn end_of_stream() -> Error { Error::EndOfStreamError }
fn invalid_value(msg: &str) -> Error {
Error::InvalidValue(msg.to_owned())
}
fn unknown_field(field: &str) -> Error { fn unknown_field(field: &str) -> Error {
Error::UnknownFieldError(field.to_owned()) Error::UnknownFieldError(field.to_owned())
} }
@@ -440,6 +445,10 @@ impl de::Error for Error {
fn missing_field(field: &'static str) -> Error { fn missing_field(field: &'static str) -> Error {
Error::MissingFieldError(field) Error::MissingFieldError(field)
} }
fn duplicate_field(field: &'static str) -> Error {
Error::DuplicateFieldError(field)
}
} }
impl fmt::Display for Error { impl fmt::Display for Error {