Allow structs to be deserialized from sequences

This relies on the sequence to have the same ordering as the
struct field order.
This commit is contained in:
Erick Tryzelaar 2015-07-21 21:35:20 -07:00
parent b9a938a01c
commit dbe2beacb0
2 changed files with 101 additions and 5 deletions

View File

@ -356,6 +356,51 @@ fn deserialize_seq(
})
}
fn deserialize_struct_as_seq(
cx: &ExtCtxt,
builder: &aster::AstBuilder,
struct_path: ast::Path,
struct_def: &StructDef,
) -> P<ast::Expr> {
let let_values: Vec<P<ast::Stmt>> = (0 .. struct_def.fields.len())
.map(|i| {
let name = builder.id(format!("__field{}", i));
quote_stmt!(cx,
let $name = match try!(visitor.visit()) {
Some(value) => { value },
None => {
return Err(::serde::de::Error::end_of_stream_error());
}
};
).unwrap()
})
.collect();
let result = builder.expr().struct_path(struct_path)
.with_id_exprs(
struct_def.fields.iter()
.enumerate()
.map(|(i, field)| {
(
match field.node.kind {
ast::NamedField(name, _) => name.clone(),
ast::UnnamedField(_) => panic!("struct contains unnamed fields"),
},
builder.expr().id(format!("__field{}", i)),
)
})
)
.build();
quote_expr!(cx, {
$let_values
try!(visitor.end());
Ok($result)
})
}
fn deserialize_struct(
cx: &ExtCtxt,
builder: &aster::AstBuilder,
@ -373,11 +418,20 @@ fn deserialize_struct(
vec![deserializer_ty_arg(builder)],
);
let (field_visitor, fields_stmt, visit_map_expr,) = deserialize_struct_visitor(
let type_path = builder.path().id(type_ident).build();
let visit_seq_expr = deserialize_struct_as_seq(
cx,
builder,
type_path.clone(),
struct_def
);
let (field_visitor, fields_stmt, visit_map_expr) = deserialize_struct_visitor(
cx,
builder,
struct_def,
builder.path().id(type_ident).build(),
type_path.clone()
);
let type_name = builder.expr().str(type_ident);
@ -390,6 +444,13 @@ fn deserialize_struct(
impl $visitor_generics ::serde::de::Visitor for $visitor_ty $where_clause {
type Value = $ty;
#[inline]
fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
where __V: ::serde::de::SeqVisitor,
{
$visit_seq_expr
}
#[inline]
fn visit_map<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
where __V: ::serde::de::MapVisitor,
@ -573,11 +634,23 @@ fn deserialize_struct_variant(
) -> P<ast::Expr> {
let where_clause = &generics.where_clause;
let type_path = builder.path()
.id(type_ident)
.id(variant_ident)
.build();
let visit_seq_expr = deserialize_struct_as_seq(
cx,
builder,
type_path.clone(),
struct_def
);
let (field_visitor, fields_stmt, field_expr) = deserialize_struct_visitor(
cx,
builder,
struct_def,
builder.path().id(type_ident).id(variant_ident).build(),
type_path
);
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) =
@ -596,6 +669,13 @@ fn deserialize_struct_variant(
impl $visitor_generics ::serde::de::Visitor for $visitor_ty $where_clause {
type Value = $ty;
#[inline]
fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
where __V: ::serde::de::SeqVisitor,
{
$visit_seq_expr
}
fn visit_map<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
where __V: ::serde::de::MapVisitor,
{

View File

@ -891,7 +891,7 @@ fn test_parse_struct() {
Inner { a: (), b: 2, c: vec!["abc".to_string(), "xyz".to_string()] }
]
},
)
),
]);
let v: Outer = from_str("{}").unwrap();
@ -902,6 +902,22 @@ fn test_parse_struct() {
inner: vec![],
}
);
let v: Outer = from_str(
"[
[
[ null, 2, [\"abc\", \"xyz\"] ]
]
]").unwrap();
assert_eq!(
v,
Outer {
inner: vec![
Inner { a: (), b: 2, c: vec!["abc".to_string(), "xyz".to_string()] }
],
}
);
}
#[test]
@ -934,7 +950,7 @@ fn test_parse_enum_errors() {
("{\"unknown\":[]}", Error::SyntaxError(ErrorCode::UnknownField("unknown".to_string()), 1, 11)),
("{\"Dog\":{}}", Error::SyntaxError(ErrorCode::ExpectedSomeValue, 1, 9)),
("{\"Frog\":{}}", Error::SyntaxError(ErrorCode::ExpectedSomeValue, 1, 10)),
("{\"Cat\":[]}", Error::SyntaxError(ErrorCode::ExpectedSomeValue, 1, 9)),
("{\"Cat\":[]}", Error::SyntaxError(ErrorCode::EOFWhileParsingValue, 1, 9)),
]);
}