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(
|
fn deserialize_struct(
|
||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
@ -373,11 +418,20 @@ fn deserialize_struct(
|
|||||||
vec![deserializer_ty_arg(builder)],
|
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,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
struct_def,
|
struct_def,
|
||||||
builder.path().id(type_ident).build(),
|
type_path.clone()
|
||||||
);
|
);
|
||||||
|
|
||||||
let type_name = builder.expr().str(type_ident);
|
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 {
|
impl $visitor_generics ::serde::de::Visitor for $visitor_ty $where_clause {
|
||||||
type Value = $ty;
|
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]
|
#[inline]
|
||||||
fn visit_map<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
|
fn visit_map<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
|
||||||
where __V: ::serde::de::MapVisitor,
|
where __V: ::serde::de::MapVisitor,
|
||||||
@ -573,11 +634,23 @@ fn deserialize_struct_variant(
|
|||||||
) -> P<ast::Expr> {
|
) -> P<ast::Expr> {
|
||||||
let where_clause = &generics.where_clause;
|
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(
|
let (field_visitor, fields_stmt, field_expr) = deserialize_struct_visitor(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
struct_def,
|
struct_def,
|
||||||
builder.path().id(type_ident).id(variant_ident).build(),
|
type_path
|
||||||
);
|
);
|
||||||
|
|
||||||
let (visitor_item, visitor_ty, visitor_expr, visitor_generics) =
|
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 {
|
impl $visitor_generics ::serde::de::Visitor for $visitor_ty $where_clause {
|
||||||
type Value = $ty;
|
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>
|
fn visit_map<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ty, __V::Error>
|
||||||
where __V: ::serde::de::MapVisitor,
|
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()] }
|
Inner { a: (), b: 2, c: vec!["abc".to_string(), "xyz".to_string()] }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
)
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let v: Outer = from_str("{}").unwrap();
|
let v: Outer = from_str("{}").unwrap();
|
||||||
@ -902,6 +902,22 @@ fn test_parse_struct() {
|
|||||||
inner: vec![],
|
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]
|
#[test]
|
||||||
@ -934,7 +950,7 @@ fn test_parse_enum_errors() {
|
|||||||
("{\"unknown\":[]}", Error::SyntaxError(ErrorCode::UnknownField("unknown".to_string()), 1, 11)),
|
("{\"unknown\":[]}", Error::SyntaxError(ErrorCode::UnknownField("unknown".to_string()), 1, 11)),
|
||||||
("{\"Dog\":{}}", Error::SyntaxError(ErrorCode::ExpectedSomeValue, 1, 9)),
|
("{\"Dog\":{}}", Error::SyntaxError(ErrorCode::ExpectedSomeValue, 1, 9)),
|
||||||
("{\"Frog\":{}}", Error::SyntaxError(ErrorCode::ExpectedSomeValue, 1, 10)),
|
("{\"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