mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-06-12 17:51:01 +00:00
allow the deserializer to optionally handle missing fields
This allows json to deserialize missing values as a `null`.
This commit is contained in:
+10
-38
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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]
|
||||||
|
|||||||
Reference in New Issue
Block a user