diff --git a/serde_macros/src/lib.rs b/serde_macros/src/lib.rs index 23765672..84d6bf3d 100644 --- a/serde_macros/src/lib.rs +++ b/serde_macros/src/lib.rs @@ -1192,9 +1192,7 @@ fn declare_visit_map( quote_stmt!(cx, let $field = match $field { Some($field) => $field, - None => { - return Err(::serde::de::Error::missing_field_error($name_str)); - } + None => try!(visitor.missing_field($name_str)), }; ) }) diff --git a/src/de.rs b/src/de.rs index 2bf7328d..bf99b582 100644 --- a/src/de.rs +++ b/src/de.rs @@ -291,6 +291,12 @@ pub trait MapVisitor { fn size_hint(&self) -> (usize, Option) { (0, None) } + + fn missing_field(&mut self, field: &'static str) -> Result + where V: Deserialize, + { + Err(Error::missing_field_error(field)) + } } impl<'a, V_> MapVisitor for &'a mut V_ where V_: MapVisitor { diff --git a/src/json/de.rs b/src/json/de.rs index f0f96edb..3e6471bb 100644 --- a/src/json/de.rs +++ b/src/json/de.rs @@ -543,6 +543,7 @@ impl<'a, Iter> de::MapVisitor for MapVisitor<'a, Iter> } if self.de.eof() { + println!("here3"); return Err(self.de.error(ErrorCode::EOFWhileParsingValue)); } @@ -573,6 +574,31 @@ impl<'a, Iter> de::MapVisitor for MapVisitor<'a, Iter> Err(self.de.error(ErrorCode::TrailingCharacters)) } } + + fn missing_field(&mut self, _field: &'static str) -> Result + where V: de::Deserialize, + { + // See if the type can deserialize from a unit. + struct UnitDeserializer; + + impl de::Deserializer for UnitDeserializer { + type Error = Error; + + fn visit(&mut self, mut visitor: V) -> Result + where V: de::Visitor, + { + visitor.visit_unit() + } + + fn visit_option(&mut self, mut visitor: V) -> Result + where V: de::Visitor, + { + visitor.visit_none() + } + } + + Ok(try!(de::Deserialize::deserialize(&mut UnitDeserializer))) + } } struct EnumVisitor<'a, Iter: 'a> { diff --git a/src/json/value.rs b/src/json/value.rs index f444c754..b7685c52 100644 --- a/src/json/value.rs +++ b/src/json/value.rs @@ -553,6 +553,31 @@ impl<'a> de::MapVisitor for MapDeserializer<'a> { } } + fn missing_field(&mut self, _field: &'static str) -> Result + where V: de::Deserialize, + { + // See if the type can deserialize from a unit. + struct UnitDeserializer; + + impl de::Deserializer for UnitDeserializer { + type Error = Error; + + fn visit(&mut self, mut visitor: V) -> Result + where V: de::Visitor, + { + visitor.visit_unit() + } + + fn visit_option(&mut self, mut visitor: V) -> Result + where V: de::Visitor, + { + visitor.visit_none() + } + } + + Ok(try!(de::Deserialize::deserialize(&mut UnitDeserializer))) + } + fn size_hint(&self) -> (usize, Option) { (self.len, Some(self.len)) } diff --git a/tests/test_json.rs b/tests/test_json.rs index 1a7b2d62..fd0d10d2 100644 --- a/tests/test_json.rs +++ b/tests/test_json.rs @@ -643,7 +643,7 @@ fn test_parse_object() { fn test_parse_struct() { test_parse_err::(&[ ("[]", Error::SyntaxError(ErrorCode::ExpectedSomeValue, 0, 0)), - ("{}", Error::MissingFieldError("inner")), + ("{}", Error::SyntaxError(ErrorCode::ExpectedSomeValue, 0, 0)), ("{\"inner\": true}", Error::SyntaxError(ErrorCode::ExpectedSomeValue, 0, 0)), ]); @@ -759,3 +759,26 @@ fn test_multiline_errors() { ("{\n \"foo\":\n \"bar\"", Error::SyntaxError(ErrorCode::EOFWhileParsingObject, 3, 8)), ]); } + +#[test] +fn test_missing_field() { + #[derive(Debug, PartialEq)] + #[derive_deserialize] + struct Foo { + x: Option, + } + + let value: Foo = from_str("{}").unwrap(); + assert_eq!(value, Foo { x: None }); + + let value: Foo = from_str("{\"x\": 5}").unwrap(); + assert_eq!(value, Foo { x: Some(5) }); + + let value: Foo = from_value(Value::Object(treemap!())).unwrap(); + assert_eq!(value, Foo { x: None }); + + let value: Foo = from_value(Value::Object(treemap!( + "x".to_string() => Value::I64(5) + ))).unwrap(); + assert_eq!(value, Foo { x: Some(5) }); +}