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
+10 -38
View File
@@ -394,23 +394,18 @@ fn deserialize_struct_from_map(
}) })
.collect(); .collect();
let fields_tuple = cx.expr_tuple( let extract_fields: Vec<Gc<ast::Stmt>> = fields.iter()
span,
fields.iter()
.map(|&(name, span)| {
cx.expr_ident(span, name)
})
.collect()
);
let fields_pats: Vec<Gc<ast::Pat>> = fields.iter()
.map(|&(name, span)| { .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(); .collect();
let fields_pat = cx.pat_tuple(span, fields_pats);
let result = cx.expr_struct_ident( let result = cx.expr_struct_ident(
span, span,
type_ident, type_ident,
@@ -421,27 +416,6 @@ fn deserialize_struct_from_map(
.collect() .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, { quote_expr!(cx, {
$let_fields $let_fields
@@ -473,10 +447,8 @@ fn deserialize_struct_from_map(
try!($deserializer.ignore_field(token)) try!($deserializer.ignore_field(token))
} }
match $fields_tuple { $extract_fields
$fields_pat => Ok($result), Ok($result)
$error_arms
}
}) })
} }
+7 -5
View File
@@ -240,11 +240,6 @@ mod deserializer {
SyntaxError SyntaxError
} }
#[inline]
fn missing_field_error(&mut self, _field: &'static str) -> Error {
SyntaxError
}
#[inline] #[inline]
fn unexpected_name_error(&mut self, _token: de::Token) -> Error { fn unexpected_name_error(&mut self, _token: de::Token) -> Error {
SyntaxError SyntaxError
@@ -254,6 +249,13 @@ mod deserializer {
fn conversion_error(&mut self, _token: de::Token) -> Error { fn conversion_error(&mut self, _token: de::Token) -> Error {
SyntaxError SyntaxError
} }
#[inline]
fn missing_field<
T: de::Deserializable
>(&mut self, _field: &'static str) -> Result<T, Error> {
Err(SyntaxError)
}
} }
} }
+7 -5
View File
@@ -236,11 +236,6 @@ mod deserializer {
SyntaxError SyntaxError
} }
#[inline]
fn missing_field_error(&mut self, _field: &'static str) -> Error {
SyntaxError
}
#[inline] #[inline]
fn unexpected_name_error(&mut self, _token: de::Token) -> Error { fn unexpected_name_error(&mut self, _token: de::Token) -> Error {
SyntaxError SyntaxError
@@ -250,6 +245,13 @@ mod deserializer {
fn conversion_error(&mut self, _token: de::Token) -> Error { fn conversion_error(&mut self, _token: de::Token) -> Error {
SyntaxError SyntaxError
} }
#[inline]
fn missing_field<
T: de::Deserializable
>(&mut self, _field: &'static str) -> Result<T, Error> {
Err(SyntaxError)
}
} }
} }
+7 -5
View File
@@ -360,11 +360,6 @@ mod deserializer {
SyntaxError SyntaxError
} }
#[inline]
fn missing_field_error(&mut self, _field: &'static str) -> Error {
SyntaxError
}
#[inline] #[inline]
fn unexpected_name_error(&mut self, _token: de::Token) -> Error { fn unexpected_name_error(&mut self, _token: de::Token) -> Error {
SyntaxError SyntaxError
@@ -374,6 +369,13 @@ mod deserializer {
fn conversion_error(&mut self, _token: de::Token) -> Error { fn conversion_error(&mut self, _token: de::Token) -> Error {
SyntaxError SyntaxError
} }
#[inline]
fn missing_field<
T: de::Deserializable
>(&mut self, _field: &'static str) -> Result<T, Error> {
Err(SyntaxError)
}
} }
} }
+14 -10
View File
@@ -304,11 +304,6 @@ mod deserializer {
SyntaxError SyntaxError
} }
#[inline]
fn missing_field_error(&mut self, _field: &'static str) -> Error {
SyntaxError
}
#[inline] #[inline]
fn unexpected_name_error(&mut self, _token: de::Token) -> Error { fn unexpected_name_error(&mut self, _token: de::Token) -> Error {
SyntaxError SyntaxError
@@ -318,6 +313,13 @@ mod deserializer {
fn conversion_error(&mut self, _token: de::Token) -> Error { fn conversion_error(&mut self, _token: de::Token) -> Error {
SyntaxError SyntaxError
} }
#[inline]
fn missing_field<
T: de::Deserializable
>(&mut self, _field: &'static str) -> Result<T, Error> {
Err(SyntaxError)
}
} }
pub struct U8Deserializer { pub struct U8Deserializer {
@@ -374,11 +376,6 @@ mod deserializer {
SyntaxError SyntaxError
} }
#[inline]
fn missing_field_error(&mut self, _field: &'static str) -> Error {
SyntaxError
}
#[inline] #[inline]
fn unexpected_name_error(&mut self, _token: de::Token) -> Error { fn unexpected_name_error(&mut self, _token: de::Token) -> Error {
SyntaxError SyntaxError
@@ -388,6 +385,13 @@ mod deserializer {
fn conversion_error(&mut self, _token: de::Token) -> Error { fn conversion_error(&mut self, _token: de::Token) -> Error {
SyntaxError SyntaxError
} }
#[inline]
fn missing_field<
T: de::Deserializable
>(&mut self, _field: &'static str) -> Result<T, Error> {
Err(SyntaxError)
}
} }
} }
+8 -3
View File
@@ -191,7 +191,9 @@ pub trait Deserializer<E>: Iterator<Result<Token, E>> {
/// Called when a `Deserializable` structure did not deserialize a field /// Called when a `Deserializable` structure did not deserialize a field
/// named `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. /// Called when a deserializable has decided to not consume this token.
fn ignore_field(&mut self, _token: Token) -> Result<(), E> { fn ignore_field(&mut self, _token: Token) -> Result<(), E> {
@@ -1161,8 +1163,11 @@ mod tests {
SyntaxError SyntaxError
} }
fn missing_field_error(&mut self, _field: &'static str) -> Error { #[inline]
IncompleteValue fn missing_field<
T: Deserializable
>(&mut self, _field: &'static str) -> Result<T, Error> {
Err(SyntaxError)
} }
} }
+27 -4
View File
@@ -663,8 +663,13 @@ impl de::Deserializer<ParserError> for JsonDeserializer {
SyntaxError(InvalidSyntax, 0, 0) SyntaxError(InvalidSyntax, 0, 0)
} }
fn missing_field_error(&mut self, field: &'static str) -> ParserError { #[inline]
SyntaxError(MissingField(field), 0, 0) 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. // 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) SyntaxError(InvalidSyntax, self.line, self.col)
} }
fn missing_field_error(&mut self, field: &'static str) -> ParserError { #[inline]
SyntaxError(MissingField(field), self.line, self.col) 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. // Special case treating options as a nullable value.
@@ -3066,6 +3076,19 @@ mod tests {
("null", None), ("null", None),
("\"jodhpurs\"", Some("jodhpurs".to_string())), ("\"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] #[test]