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:
parent
b9a938a01c
commit
dbe2beacb0
@ -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,
|
||||
{
|
||||
|
@ -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)),
|
||||
]);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user