allow the deserializer to optionally handle missing fields

This allows json to deserialize missing values as a `null`.
This commit is contained in:
Erick Tryzelaar 2014-08-18 07:37:44 -07:00
parent c6d28afb6f
commit aff53e8dd4
7 changed files with 80 additions and 70 deletions

View File

@ -394,23 +394,18 @@ fn deserialize_struct_from_map(
})
.collect();
let fields_tuple = cx.expr_tuple(
span,
fields.iter()
.map(|&(name, span)| {
cx.expr_ident(span, name)
})
.collect()
);
let fields_pats: Vec<Gc<ast::Pat>> = fields.iter()
let extract_fields: Vec<Gc<ast::Stmt>> = fields.iter()
.map(|&(name, span)| {
quote_pat!(cx, Some($name))
let name_str = cx.expr_str(span, token::get_ident(name));
quote_stmt!(cx,
let $name = match $name {
Some($name) => $name,
None => try!($deserializer.missing_field($name_str)),
};
)
})
.collect();
let fields_pat = cx.pat_tuple(span, fields_pats);
let result = cx.expr_struct_ident(
span,
type_ident,
@ -421,27 +416,6 @@ fn deserialize_struct_from_map(
.collect()
);
let error_arms: Vec<ast::Arm> = fields.iter()
.map(|&(name, span)| {
let pats = fields.iter()
.map(|&(n, _)| {
if n == name {
quote_pat!(cx, None)
} else {
quote_pat!(cx, _)
}
})
.collect();
let pat = cx.pat_tuple(span, pats);
let s = cx.expr_str(span, token::get_ident(name));
quote_arm!(cx,
$pat => Err($deserializer.missing_field_error($s)),
)
})
.collect();
quote_expr!(cx, {
$let_fields
@ -473,10 +447,8 @@ fn deserialize_struct_from_map(
try!($deserializer.ignore_field(token))
}
match $fields_tuple {
$fields_pat => Ok($result),
$error_arms
}
$extract_fields
Ok($result)
})
}

View File

@ -240,11 +240,6 @@ mod deserializer {
SyntaxError
}
#[inline]
fn missing_field_error(&mut self, _field: &'static str) -> Error {
SyntaxError
}
#[inline]
fn unexpected_name_error(&mut self, _token: de::Token) -> Error {
SyntaxError
@ -254,6 +249,13 @@ mod deserializer {
fn conversion_error(&mut self, _token: de::Token) -> Error {
SyntaxError
}
#[inline]
fn missing_field<
T: de::Deserializable
>(&mut self, _field: &'static str) -> Result<T, Error> {
Err(SyntaxError)
}
}
}

View File

@ -236,11 +236,6 @@ mod deserializer {
SyntaxError
}
#[inline]
fn missing_field_error(&mut self, _field: &'static str) -> Error {
SyntaxError
}
#[inline]
fn unexpected_name_error(&mut self, _token: de::Token) -> Error {
SyntaxError
@ -250,6 +245,13 @@ mod deserializer {
fn conversion_error(&mut self, _token: de::Token) -> Error {
SyntaxError
}
#[inline]
fn missing_field<
T: de::Deserializable
>(&mut self, _field: &'static str) -> Result<T, Error> {
Err(SyntaxError)
}
}
}

View File

@ -360,11 +360,6 @@ mod deserializer {
SyntaxError
}
#[inline]
fn missing_field_error(&mut self, _field: &'static str) -> Error {
SyntaxError
}
#[inline]
fn unexpected_name_error(&mut self, _token: de::Token) -> Error {
SyntaxError
@ -374,6 +369,13 @@ mod deserializer {
fn conversion_error(&mut self, _token: de::Token) -> Error {
SyntaxError
}
#[inline]
fn missing_field<
T: de::Deserializable
>(&mut self, _field: &'static str) -> Result<T, Error> {
Err(SyntaxError)
}
}
}

View File

@ -304,11 +304,6 @@ mod deserializer {
SyntaxError
}
#[inline]
fn missing_field_error(&mut self, _field: &'static str) -> Error {
SyntaxError
}
#[inline]
fn unexpected_name_error(&mut self, _token: de::Token) -> Error {
SyntaxError
@ -318,6 +313,13 @@ mod deserializer {
fn conversion_error(&mut self, _token: de::Token) -> Error {
SyntaxError
}
#[inline]
fn missing_field<
T: de::Deserializable
>(&mut self, _field: &'static str) -> Result<T, Error> {
Err(SyntaxError)
}
}
pub struct U8Deserializer {
@ -374,11 +376,6 @@ mod deserializer {
SyntaxError
}
#[inline]
fn missing_field_error(&mut self, _field: &'static str) -> Error {
SyntaxError
}
#[inline]
fn unexpected_name_error(&mut self, _token: de::Token) -> Error {
SyntaxError
@ -388,6 +385,13 @@ mod deserializer {
fn conversion_error(&mut self, _token: de::Token) -> Error {
SyntaxError
}
#[inline]
fn missing_field<
T: de::Deserializable
>(&mut self, _field: &'static str) -> Result<T, Error> {
Err(SyntaxError)
}
}
}

View File

@ -191,7 +191,9 @@ pub trait Deserializer<E>: Iterator<Result<Token, E>> {
/// Called when a `Deserializable` structure did not deserialize a field
/// named `field`.
fn missing_field_error(&mut self, field: &'static str) -> E;
fn missing_field<
T: Deserializable
>(&mut self, field: &'static str) -> Result<T, E>;
/// Called when a deserializable has decided to not consume this token.
fn ignore_field(&mut self, _token: Token) -> Result<(), E> {
@ -1161,8 +1163,11 @@ mod tests {
SyntaxError
}
fn missing_field_error(&mut self, _field: &'static str) -> Error {
IncompleteValue
#[inline]
fn missing_field<
T: Deserializable
>(&mut self, _field: &'static str) -> Result<T, Error> {
Err(SyntaxError)
}
}

View File

@ -663,8 +663,13 @@ impl de::Deserializer<ParserError> for JsonDeserializer {
SyntaxError(InvalidSyntax, 0, 0)
}
fn missing_field_error(&mut self, field: &'static str) -> ParserError {
SyntaxError(MissingField(field), 0, 0)
#[inline]
fn missing_field<
T: de::Deserializable
>(&mut self, _field: &'static str) -> Result<T, ParserError> {
// JSON can represent `null` values as a missing value, so this isn't
// necessarily an error.
de::Deserializable::deserialize_token(self, de::Null)
}
// Special case treating options as a nullable value.
@ -2039,8 +2044,13 @@ impl<T: Iterator<char>> de::Deserializer<ParserError> for Parser<T> {
SyntaxError(InvalidSyntax, self.line, self.col)
}
fn missing_field_error(&mut self, field: &'static str) -> ParserError {
SyntaxError(MissingField(field), self.line, self.col)
#[inline]
fn missing_field<
T: de::Deserializable
>(&mut self, _field: &'static str) -> Result<T, ParserError> {
// JSON can represent `null` values as a missing value, so this isn't
// necessarily an error.
de::Deserializable::deserialize_token(self, de::Null)
}
// Special case treating options as a nullable value.
@ -3066,6 +3076,19 @@ mod tests {
("null", None),
("\"jodhpurs\"", Some("jodhpurs".to_string())),
]);
#[deriving(PartialEq, Show)]
#[deriving_serializable]
#[deriving_deserializable]
struct Foo {
x: Option<int>,
}
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) });
}
#[test]