From dbe2beacb03797103e1800b5d2f13092322a727d Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 21 Jul 2015 21:35:20 -0700 Subject: [PATCH] Allow structs to be deserialized from sequences This relies on the sequence to have the same ordering as the struct field order. --- serde_codegen/src/de.rs | 86 ++++++++++++++++++++++++++++++++-- serde_tests/tests/test_json.rs | 20 +++++++- 2 files changed, 101 insertions(+), 5 deletions(-) diff --git a/serde_codegen/src/de.rs b/serde_codegen/src/de.rs index 85028cdc..19a32483 100644 --- a/serde_codegen/src/de.rs +++ b/serde_codegen/src/de.rs @@ -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 { + let let_values: Vec> = (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 { 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, { diff --git a/serde_tests/tests/test_json.rs b/serde_tests/tests/test_json.rs index c29f8286..f2dd9a29 100644 --- a/serde_tests/tests/test_json.rs +++ b/serde_tests/tests/test_json.rs @@ -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)), ]); }