diff --git a/serde/src/de/mod.rs b/serde/src/de/mod.rs index 11050648..142502b7 100644 --- a/serde/src/de/mod.rs +++ b/serde/src/de/mod.rs @@ -32,10 +32,19 @@ pub trait Error: Sized + error::Error { fn end_of_stream() -> Self; /// Raised when a `Deserialize` struct type received an unexpected struct field. - fn unknown_field(field: &str) -> Self; + fn unknown_field(field: &str) -> Self { + Error::syntax(&format!("Unknown field `{}`", field)) + } - /// Raised when a `Deserialize` struct type did not receive a field. - fn missing_field(field: &'static str) -> Self; + /// Raised when a `Deserialize` enum type received an unexpected variant. + fn unknown_variant(field: &str) -> Self { + Error::syntax(&format!("Unknown variant `{}`", field)) + } + + /// raised when a `deserialize` struct type did not receive a field. + fn missing_field(field: &'static str) -> Self { + Error::syntax(&format!("Missing 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 bc53153e..a94fd02b 100644 --- a/serde_codegen/src/de.rs +++ b/serde_codegen/src/de.rs @@ -566,6 +566,7 @@ fn deserialize_item_enum( .collect() ), container_attrs, + true, ); let variants_expr = builder.expr().ref_().slice() @@ -807,6 +808,7 @@ fn deserialize_field_visitor( builder: &aster::AstBuilder, field_names: Vec>, container_attrs: &attr::ContainerAttrs, + is_variant: bool, ) -> Vec> { // Create the field names for the fields. let field_idents: Vec = (0 .. field_names.len()) @@ -838,10 +840,16 @@ fn deserialize_field_visitor( }) .collect(); + let (index_error_msg, unknown_ident) = if is_variant { + (builder.expr().str("expected a variant"), builder.id("unknown_variant")) + } else { + (builder.expr().str("expected a field"), builder.id("unknown_field")) + }; + let index_body = quote_expr!(cx, match value { $index_field_arms - _ => { Err(::serde::de::Error::syntax("expected a field")) } + _ => { Err(::serde::de::Error::syntax($index_error_msg)) } } ); @@ -853,10 +861,10 @@ fn deserialize_field_visitor( }) .collect(); - let fallthrough_arm_expr = if !container_attrs.deny_unknown_fields() { + let fallthrough_arm_expr = if !is_variant && !container_attrs.deny_unknown_fields() { quote_expr!(cx, Ok(__Field::__ignore)) } else { - quote_expr!(cx, Err(::serde::de::Error::unknown_field(value))) + quote_expr!(cx, Err(::serde::de::Error::$unknown_ident(value))) }; let str_body = quote_expr!(cx, @@ -947,7 +955,8 @@ fn deserialize_struct_visitor( cx, builder, try!(field_exprs), - container_attrs + container_attrs, + false, ); let visit_map_expr = try!(deserialize_map( diff --git a/serde_tests/tests/test_de.rs b/serde_tests/tests/test_de.rs index dcc6e8f0..568bfaea 100644 --- a/serde_tests/tests/test_de.rs +++ b/serde_tests/tests/test_de.rs @@ -8,7 +8,13 @@ use num::rational::Ratio; use serde::de::{Deserializer, Visitor}; -use token::{Token, assert_de_tokens, assert_de_tokens_ignore}; +use token::{ + Error, + Token, + assert_de_tokens, + assert_de_tokens_ignore, + assert_de_tokens_error, +}; ////////////////////////////////////////////////////////////////////////// @@ -600,3 +606,13 @@ declare_tests! { ], } } + +#[test] +fn test_enum_error() { + assert_de_tokens_error::( + vec![ + Token::EnumUnit("Enum", "Foo"), + ], + Error::UnknownVariantError("Foo".to_owned()), + ) +} diff --git a/serde_tests/tests/token.rs b/serde_tests/tests/token.rs index 40810d47..30d623be 100644 --- a/serde_tests/tests/token.rs +++ b/serde_tests/tests/token.rs @@ -371,6 +371,7 @@ pub enum Error { SyntaxError, EndOfStreamError, UnknownFieldError(String), + UnknownVariantError(String), MissingFieldError(&'static str), InvalidName(&'static str), InvalidValue(String), @@ -395,6 +396,10 @@ impl de::Error for Error { Error::UnknownFieldError(field.to_owned()) } + fn unknown_variant(variant: &str) -> Error { + Error::UnknownVariantError(variant.to_owned()) + } + fn missing_field(field: &'static str) -> Error { Error::MissingFieldError(field) }