From de89f95f3162a2f1404ed63940dc26ffa1bfbaf0 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Fri, 12 Feb 2016 22:05:02 -0800 Subject: [PATCH] feat(codegen): Add support for #![serde(skip_serialize_if="$expr")] This allows end users to use an arbitrary expression to decide whether or not to serialize some field. This expression has access to all the fields in the struct, but none of the internal state of the Serialize implementation. For structs, serde implements this by creating a temporary trait and implementing the struct for it. For struct variants, the fields are copied by reference into a temporary struct first before implementing the temporary trait. This also fixes a bug where the serde_codegen wasn't making calls to Serializer::serialize_{tuple,struct}_variant{,_elt}. --- serde_codegen/src/attr.rs | 46 ++- serde_codegen/src/de.rs | 19 +- serde_codegen/src/ser.rs | 262 ++++++++++------- serde_tests/tests/test_annotations.rs | 138 +++++---- serde_tests/tests/test_de.rs | 42 +-- serde_tests/tests/test_macros.rs | 129 +++++---- serde_tests/tests/test_ser.rs | 34 +-- serde_tests/tests/token.rs | 396 +++++++++++++++++++++++--- 8 files changed, 761 insertions(+), 305 deletions(-) diff --git a/serde_codegen/src/attr.rs b/serde_codegen/src/attr.rs index 7c69cdf1..b440af7e 100644 --- a/serde_codegen/src/attr.rs +++ b/serde_codegen/src/attr.rs @@ -166,6 +166,7 @@ pub struct FieldAttrs { serialize_name: Option, deserialize_name: Option, skip_serializing_field: bool, + skip_serializing_field_if: Option>, skip_serializing_field_if_empty: bool, skip_serializing_field_if_none: bool, default_expr_if_missing: Option>, @@ -174,6 +175,7 @@ pub struct FieldAttrs { impl FieldAttrs { /// Extract out the `#[serde(...)]` attributes from a struct field. pub fn from_field(cx: &ExtCtxt, + container_ty: &P, generics: &ast::Generics, field: &ast::StructField) -> Result { let builder = AstBuilder::new(); @@ -188,6 +190,7 @@ impl FieldAttrs { serialize_name: None, deserialize_name: None, skip_serializing_field: false, + skip_serializing_field_if: None, skip_serializing_field_if_empty: false, skip_serializing_field_if_none: false, default_expr_if_missing: None, @@ -232,6 +235,18 @@ impl FieldAttrs { field_attrs.skip_serializing_field = true; } + // Parse `#[serde(skip_serializing_if="...")]` + ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"skip_serializing_if" => { + let expr = wrap_skip_serializing( + cx, + container_ty, + generics, + try!(parse_lit_into_expr(cx, name, lit)), + ); + + field_attrs.skip_serializing_field_if = Some(expr); + } + // Parse `#[serde(skip_serializing_if_none)]` ast::MetaItemKind::Word(ref name) if name == &"skip_serializing_if_none" => { field_attrs.skip_serializing_field_if_none = true; @@ -298,6 +313,10 @@ impl FieldAttrs { self.skip_serializing_field } + pub fn skip_serializing_field_if(&self) -> Option<&P> { + self.skip_serializing_field_if.as_ref() + } + pub fn skip_serializing_field_if_empty(&self) -> bool { self.skip_serializing_field_if_empty } @@ -307,12 +326,14 @@ impl FieldAttrs { } } + /// Extract out the `#[serde(...)]` attributes from a struct field. pub fn get_struct_field_attrs(cx: &ExtCtxt, + container_ty: &P, generics: &ast::Generics, fields: &[ast::StructField]) -> Result, Error> { fields.iter() - .map(|field| FieldAttrs::from_field(cx, generics, field)) + .map(|field| FieldAttrs::from_field(cx, container_ty, generics, field)) .collect() } @@ -401,3 +422,26 @@ fn wrap_default(cx: &ExtCtxt, $fn_path() }) } + +/// This function wraps the expression in `#[serde(skip_serializing_if="...")]` in a trait to +/// prevent it from accessing the internal `Serialize` state. +fn wrap_skip_serializing(cx: &ExtCtxt, + container_ty: &P, + generics: &ast::Generics, + expr: P) -> P { + let where_clause = &generics.where_clause; + + quote_expr!(cx, { + trait __SerdeShouldSkipSerializing { + fn __serde_should_skip_serializing(&self) -> bool; + } + + impl $generics __SerdeShouldSkipSerializing for $container_ty $where_clause { + fn __serde_should_skip_serializing(&self) -> bool { + $expr + } + } + + self.value.__serde_should_skip_serializing() + }) +} diff --git a/serde_codegen/src/de.rs b/serde_codegen/src/de.rs index 458913e0..e95fe2dc 100644 --- a/serde_codegen/src/de.rs +++ b/serde_codegen/src/de.rs @@ -503,6 +503,7 @@ fn deserialize_struct( cx, builder, type_path.clone(), + &ty, impl_generics, fields, container_attrs @@ -757,6 +758,7 @@ fn deserialize_struct_variant( cx, builder, type_path, + &ty, generics, fields, container_attrs, @@ -920,13 +922,19 @@ fn deserialize_struct_visitor( cx: &ExtCtxt, builder: &aster::AstBuilder, struct_path: ast::Path, + container_ty: &P, generics: &ast::Generics, fields: &[ast::StructField], container_attrs: &attr::ContainerAttrs, ) -> Result<(Vec>, ast::Stmt, P), Error> { let field_exprs = fields.iter() .map(|field| { - let field_attrs = try!(attr::FieldAttrs::from_field(cx, generics, field)); + let field_attrs = try!( + attr::FieldAttrs::from_field(cx, + container_ty, + generics, + field) + ); Ok(field_attrs.deserialize_name_expr()) }) .collect(); @@ -942,6 +950,7 @@ fn deserialize_struct_visitor( cx, builder, struct_path, + container_ty, generics, fields, container_attrs, @@ -972,6 +981,7 @@ fn deserialize_map( cx: &ExtCtxt, builder: &aster::AstBuilder, struct_path: ast::Path, + container_ty: &P, generics: &ast::Generics, fields: &[ast::StructField], container_attrs: &attr::ContainerAttrs, @@ -1011,7 +1021,12 @@ fn deserialize_map( let extract_values = fields.iter() .zip(field_names.iter()) .map(|(field, field_name)| { - let field_attr = try!(attr::FieldAttrs::from_field(cx, generics, field)); + let field_attr = try!( + attr::FieldAttrs::from_field(cx, + container_ty, + generics, + field) + ); let missing_expr = field_attr.expr_is_missing(); Ok(quote_stmt!(cx, diff --git a/serde_codegen/src/ser.rs b/serde_codegen/src/ser.rs index 7aef3de1..a604d298 100644 --- a/serde_codegen/src/ser.rs +++ b/serde_codegen/src/ser.rs @@ -33,14 +33,30 @@ pub fn expand_derive_serialize( let builder = aster::AstBuilder::new().span(span); + let impl_item = match serialize_item(cx, &builder, &item) { + Ok(item) => item, + Err(Error) => { + // An error occured, but it should have been reported already. + return; + } + }; + + push(Annotatable::Item(impl_item)) +} + +fn serialize_item( + cx: &ExtCtxt, + builder: &aster::AstBuilder, + item: &Item, +) -> Result, Error> { let generics = match item.node { ast::ItemKind::Struct(_, ref generics) => generics, ast::ItemKind::Enum(_, ref generics) => generics, _ => { cx.span_err( - meta_item.span, + item.span, "`#[derive(Serialize)]` may only be applied to structs and enums"); - return; + return Err(Error); } }; @@ -54,17 +70,15 @@ pub fn expand_derive_serialize( .segment(item.ident).with_generics(impl_generics.clone()).build() .build(); - let body = match serialize_body(cx, &builder, &item, &impl_generics, ty.clone()) { - Ok(body) => body, - Err(Error) => { - // An error occured, but it should have been reported already. - return; - } - }; + let body = try!(serialize_body(cx, + &builder, + &item, + &impl_generics, + ty.clone())); let where_clause = &impl_generics.where_clause; - let impl_item = quote_item!(cx, + Ok(quote_item!(cx, impl $impl_generics ::serde::ser::Serialize for $ty $where_clause { fn serialize<__S>(&self, serializer: &mut __S) -> ::std::result::Result<(), __S::Error> where __S: ::serde::ser::Serializer, @@ -72,9 +86,7 @@ pub fn expand_derive_serialize( $body } } - ).unwrap(); - - push(Annotatable::Item(impl_item)) + ).unwrap()) } fn serialize_body( @@ -207,6 +219,7 @@ fn serialize_tuple_struct( .ref_() .lifetime("'__a") .build_ty(ty.clone()), + builder.id("serialize_tuple_struct_elt"), fields, impl_generics, ); @@ -232,11 +245,6 @@ fn serialize_struct( fields: &[ast::StructField], container_attrs: &attr::ContainerAttrs, ) -> Result, Error> { - let value_exprs = fields.iter().map(|field| { - let name = field.node.ident().expect("struct has unnamed field"); - quote_expr!(cx, &self.value.$name) - }); - let (visitor_struct, visitor_impl) = try!(serialize_struct_visitor( cx, builder, @@ -245,9 +253,9 @@ fn serialize_struct( .ref_() .lifetime("'__a") .build_ty(ty.clone()), + builder.id("serialize_struct_elt"), fields, impl_generics, - value_exprs, )); let type_name = container_attrs.serialize_name_expr(); @@ -272,22 +280,23 @@ fn serialize_item_enum( enum_def: &ast::EnumDef, container_attrs: &attr::ContainerAttrs, ) -> Result, Error> { - let mut arms = vec![]; - - for (variant_index, variant) in enum_def.variants.iter().enumerate() { - let arm = try!(serialize_variant( - cx, - builder, - type_ident, - impl_generics, - ty.clone(), - variant, - variant_index, - container_attrs, - )); - - arms.push(arm); - } + let arms: Vec<_> = try!( + enum_def.variants.iter() + .enumerate() + .map(|(variant_index, variant)| { + serialize_variant( + cx, + builder, + type_ident, + impl_generics, + ty.clone(), + variant, + variant_index, + container_attrs, + ) + }) + .collect() + ); Ok(quote_expr!(cx, match *self { @@ -404,13 +413,13 @@ fn serialize_variant( let expr = try!(serialize_struct_variant( cx, builder, - type_name, variant_index, variant_name, generics, ty, fields, field_names, + container_attrs, )); Ok(quote_arm!(cx, @@ -447,6 +456,7 @@ fn serialize_tuple_variant( builder, structure_ty.clone(), variant_ty, + builder.id("serialize_tuple_variant_elt"), fields.len(), generics, ); @@ -473,55 +483,88 @@ fn serialize_tuple_variant( fn serialize_struct_variant( cx: &ExtCtxt, builder: &aster::AstBuilder, - type_name: P, variant_index: usize, variant_name: P, generics: &ast::Generics, - structure_ty: P, + ty: P, fields: &[ast::StructField], field_names: Vec, + container_attrs: &attr::ContainerAttrs, ) -> Result, Error> { - let value_ty = builder.ty().tuple() - .with_tys( + let variant_generics = builder.generics() + .with(generics.clone()) + .add_lifetime_bound("'__serde_variant") + .lifetime_name("'__serde_variant") + .build(); + + let variant_struct = builder.item().struct_("__VariantStruct") + .with_generics(variant_generics.clone()) + .with_fields( fields.iter().map(|field| { - builder.ty() + builder.struct_field(field.node.ident().expect("struct has unnamed fields")) + .with_attrs(field.node.attrs.iter().cloned()) + .ty() .ref_() - .lifetime("'__a") + .lifetime("'__serde_variant") .build_ty(field.node.ty.clone()) }) ) + .field("__serde_container_ty") + .ty().phantom_data().build(ty.clone()) .build(); - let value_expr = builder.expr().tuple() - .with_exprs( - field_names.iter().map(|field| { - builder.expr().id(field) - }) + let variant_expr = builder.expr().struct_id("__VariantStruct") + .with_id_exprs( + fields.iter() + .zip(field_names.iter()) + .map(|(field, field_name)| { + ( + field.node.ident().expect("struct has unnamed fields"), + builder.expr().id(field_name), + ) + }) ) + .field("__serde_container_ty").path() + .global() + .id("std").id("marker") + .segment("PhantomData") + .with_ty(ty.clone()) + .build() + .build() + .build(); + + let variant_ty = builder.ty().path() + .segment("__VariantStruct") + .with_generics(variant_generics.clone()) + .build() .build(); let (visitor_struct, visitor_impl) = try!(serialize_struct_visitor( cx, builder, - structure_ty.clone(), - value_ty, + variant_ty.clone(), + variant_ty.clone(), + builder.id("serialize_struct_variant_elt"), fields, - generics, - (0 .. field_names.len()).map(|i| { - builder.expr() - .tup_field(i) - .field("value").self_() - }) + &variant_generics, )); + let container_name = container_attrs.serialize_name_expr(); + Ok(quote_expr!(cx, { + $variant_struct $visitor_struct $visitor_impl - serializer.serialize_struct_variant($type_name, $variant_index, $variant_name, Visitor { - value: $value_expr, - state: 0, - _structure_ty: ::std::marker::PhantomData::<&$structure_ty>, - }) + serializer.serialize_struct_variant( + $container_name, + $variant_index, + $variant_name, + Visitor { + value: $variant_expr, + state: 0, + _structure_ty: ::std::marker::PhantomData, + }, + ) })) } @@ -530,20 +573,21 @@ fn serialize_tuple_struct_visitor( builder: &aster::AstBuilder, structure_ty: P, variant_ty: P, + serializer_method: ast::Ident, fields: usize, generics: &ast::Generics ) -> (P, P) { let arms: Vec = (0 .. fields) .map(|i| { - let expr = builder.expr() - .tup_field(i) - .field("value").self_(); + let expr = builder.expr().method_call(serializer_method) + .id("serializer") + .arg().ref_().tup_field(i).field("value").self_() + .build(); quote_arm!(cx, $i => { self.state += 1; - let v = try!(serializer.serialize_tuple_struct_elt(&$expr)); - Ok(Some(v)) + Ok(Some(try!($expr))) } ) }) @@ -592,51 +636,51 @@ fn serialize_tuple_struct_visitor( ) } -fn serialize_struct_visitor( +fn serialize_struct_visitor( cx: &ExtCtxt, builder: &aster::AstBuilder, structure_ty: P, variant_ty: P, + serializer_method: ast::Ident, fields: &[ast::StructField], generics: &ast::Generics, - value_exprs: I, -) -> Result<(P, P), Error> - where I: Iterator>, -{ - let value_exprs = value_exprs.collect::>(); +) -> Result<(P, P), Error> { + let field_attrs = try!( + attr::get_struct_field_attrs(cx, &structure_ty, generics, fields) + ); - let field_attrs = try!(attr::get_struct_field_attrs(cx, generics, fields)); - - let arms: Vec = field_attrs.iter() - .zip(value_exprs.iter()) - .filter(|&(ref field, _)| !field.skip_serializing_field()) + let arms: Vec = fields.iter().zip(field_attrs.iter()) + .filter(|&(_, ref field_attr)| !field_attr.skip_serializing_field()) .enumerate() - .map(|(i, (ref field, value_expr))| { - let key_expr = field.serialize_name_expr(); + .map(|(i, (ref field, ref field_attr))| { + let name = field.node.ident().expect("struct has unnamed field"); - let stmt = if field.skip_serializing_field_if_empty() { - quote_stmt!(cx, if ($value_expr).is_empty() { continue; }) - } else if field.skip_serializing_field_if_none() { - quote_stmt!(cx, if ($value_expr).is_none() { continue; }) - } else { - quote_stmt!(cx, {}) + let key_expr = field_attr.serialize_name_expr(); + + let stmt = match field_attr.skip_serializing_field_if() { + Some(expr) => { + Some(quote_stmt!(cx, if $expr { continue; })) + } + None => { + if field_attr.skip_serializing_field_if_empty() { + Some(quote_stmt!(cx, if self.value.$name.is_empty() { continue; })) + } else if field_attr.skip_serializing_field_if_none() { + Some(quote_stmt!(cx, if self.value.$name.is_none() { continue; })) + } else { + None + } + } }; + let expr = quote_expr!(cx, + serializer.$serializer_method($key_expr, &self.value.$name) + ); + quote_arm!(cx, $i => { self.state += 1; $stmt - - return Ok( - Some( - try!( - serializer.serialize_struct_elt( - $key_expr, - $value_expr, - ) - ) - ) - ); + return Ok(Some(try!($expr))); } ) }) @@ -653,17 +697,27 @@ fn serialize_struct_visitor( .strip_bounds() .build(); - let len = field_attrs.iter() - .zip(value_exprs.iter()) - .map(|(field, value_expr)| { - if field.skip_serializing_field() { + let len = fields.iter().zip(field_attrs.iter()) + .map(|(field, field_attr)| { + if field_attr.skip_serializing_field() { quote_expr!(cx, 0) - } else if field.skip_serializing_field_if_empty() { - quote_expr!(cx, if ($value_expr).is_empty() { 0 } else { 1 }) - } else if field.skip_serializing_field_if_none() { - quote_expr!(cx, if ($value_expr).is_none() { 0 } else { 1 }) } else { - quote_expr!(cx, 1) + match field_attr.skip_serializing_field_if() { + Some(expr) => { + quote_expr!(cx, if $expr { 0 } else { 1 }) + } + None => { + let name = field.node.ident().expect("struct has unnamed field"); + + if field_attr.skip_serializing_field_if_empty() { + quote_expr!(cx, if self.value.$name.is_empty() { 0 } else { 1 }) + } else if field_attr.skip_serializing_field_if_none() { + quote_expr!(cx, if self.value.$name.is_none() { 0 } else { 1 }) + } else { + quote_expr!(cx, 1) + } + } + } } }) .fold(quote_expr!(cx, 0), |sum, expr| quote_expr!(cx, $sum + $expr)); diff --git a/serde_tests/tests/test_annotations.rs b/serde_tests/tests/test_annotations.rs index 7f525746..831c32cd 100644 --- a/serde_tests/tests/test_annotations.rs +++ b/serde_tests/tests/test_annotations.rs @@ -9,10 +9,14 @@ use token::{ trait Trait { fn my_default() -> Self; + + fn should_skip(&self) -> bool; } impl Trait for i32 { fn my_default() -> Self { 123 } + + fn should_skip(&self) -> bool { *self == 123 } } #[derive(Debug, PartialEq, Serialize, Deserialize)] @@ -31,19 +35,19 @@ fn test_default_struct() { vec![ Token::StructStart("DefaultStruct", Some(3)), - Token::MapSep, + Token::StructSep, Token::Str("a1"), Token::I32(1), - Token::MapSep, + Token::StructSep, Token::Str("a2"), Token::I32(2), - Token::MapSep, + Token::StructSep, Token::Str("a3"), Token::I32(3), - Token::MapEnd, + Token::StructEnd, ] ); @@ -52,11 +56,11 @@ fn test_default_struct() { vec![ Token::StructStart("DefaultStruct", Some(1)), - Token::MapSep, + Token::StructSep, Token::Str("a1"), Token::I32(1), - Token::MapEnd, + Token::StructEnd, ] ); } @@ -79,19 +83,19 @@ fn test_default_enum() { vec![ Token::EnumMapStart("DefaultEnum", "Struct", Some(3)), - Token::MapSep, + Token::EnumMapSep, Token::Str("a1"), Token::I32(1), - Token::MapSep, + Token::EnumMapSep, Token::Str("a2"), Token::I32(2), - Token::MapSep, + Token::EnumMapSep, Token::Str("a3"), Token::I32(3), - Token::MapEnd, + Token::EnumMapEnd, ] ); @@ -100,11 +104,11 @@ fn test_default_enum() { vec![ Token::EnumMapStart("DefaultEnum", "Struct", Some(3)), - Token::MapSep, + Token::EnumMapSep, Token::Str("a1"), Token::I32(1), - Token::MapEnd, + Token::EnumMapEnd, ] ); } @@ -123,34 +127,34 @@ fn test_ignore_unknown() { vec![ Token::StructStart("DefaultStruct", Some(5)), - Token::MapSep, + Token::StructSep, Token::Str("whoops1"), Token::I32(2), - Token::MapSep, + Token::StructSep, Token::Str("a1"), Token::I32(1), - Token::MapSep, + Token::StructSep, Token::Str("whoops2"), Token::SeqStart(Some(1)), Token::SeqSep, Token::I32(2), Token::SeqEnd, - Token::MapSep, + Token::StructSep, Token::Str("a2"), Token::I32(2), - Token::MapSep, + Token::StructSep, Token::Str("whoops3"), Token::I32(2), - Token::MapSep, + Token::StructSep, Token::Str("a3"), Token::I32(3), - Token::MapEnd, + Token::StructEnd, ] ); @@ -158,15 +162,15 @@ fn test_ignore_unknown() { vec![ Token::StructStart("DenyUnknown", Some(2)), - Token::MapSep, + Token::StructSep, Token::Str("a1"), Token::I32(1), - Token::MapSep, + Token::StructSep, Token::Str("whoops"), Token::I32(2), - Token::MapEnd, + Token::StructEnd, ], Error::UnknownFieldError("whoops".to_owned()) ); @@ -195,15 +199,15 @@ fn test_rename_struct() { vec![ Token::StructStart("Superhero", Some(2)), - Token::MapSep, + Token::StructSep, Token::Str("a1"), Token::I32(1), - Token::MapSep, + Token::StructSep, Token::Str("a3"), Token::I32(2), - Token::MapEnd, + Token::StructEnd, ] ); @@ -212,15 +216,15 @@ fn test_rename_struct() { &[ Token::StructStart("SuperheroSer", Some(2)), - Token::MapSep, + Token::StructSep, Token::Str("a1"), Token::I32(1), - Token::MapSep, + Token::StructSep, Token::Str("a4"), Token::I32(2), - Token::MapEnd, + Token::StructEnd, ] ); @@ -229,15 +233,15 @@ fn test_rename_struct() { vec![ Token::StructStart("SuperheroDe", Some(2)), - Token::MapSep, + Token::StructSep, Token::Str("a1"), Token::I32(1), - Token::MapSep, + Token::StructSep, Token::Str("a5"), Token::I32(2), - Token::MapEnd, + Token::StructEnd, ] ); } @@ -281,7 +285,7 @@ fn test_rename_enum() { assert_tokens( &RenameEnum::Superman(0), vec![ - Token::EnumNewtype("Superhero", "clark_kent"), + Token::EnumNewType("Superhero", "clark_kent"), Token::I8(0), ] ); @@ -291,13 +295,13 @@ fn test_rename_enum() { vec![ Token::EnumSeqStart("Superhero", "diana_prince", Some(2)), - Token::SeqSep, + Token::EnumSeqSep, Token::I8(0), - Token::SeqSep, + Token::EnumSeqSep, Token::I8(1), - Token::SeqEnd, + Token::EnumSeqEnd, ] ); @@ -306,11 +310,11 @@ fn test_rename_enum() { vec![ Token::EnumMapStart("Superhero", "barry_allan", Some(1)), - Token::MapSep, + Token::EnumMapSep, Token::Str("b"), Token::I32(1), - Token::MapEnd, + Token::EnumMapEnd, ] ); @@ -322,15 +326,15 @@ fn test_rename_enum() { &[ Token::EnumMapStart("SuperheroSer", "dick_grayson", Some(2)), - Token::MapSep, + Token::EnumMapSep, Token::Str("a"), Token::I8(0), - Token::MapSep, + Token::EnumMapSep, Token::Str("c"), Token::Str(""), - Token::MapEnd, + Token::EnumMapEnd, ] ); @@ -342,24 +346,26 @@ fn test_rename_enum() { vec![ Token::EnumMapStart("SuperheroDe", "jason_todd", Some(2)), - Token::MapSep, + Token::EnumMapSep, Token::Str("a"), Token::I8(0), - Token::MapSep, + Token::EnumMapSep, Token::Str("d"), Token::Str(""), - Token::MapEnd, + Token::EnumMapEnd, ] ); } #[derive(Debug, PartialEq, Serialize)] -struct SkipSerializingStruct<'a, B, D, E> { +struct SkipSerializingStruct<'a, B, C, D, E> where C: Trait { a: &'a i8, #[serde(skip_serializing)] b: B, + #[serde(skip_serializing_if="self.c.should_skip()")] + c: C, #[serde(skip_serializing_if_none)] d: Option, #[serde(skip_serializing_if_empty)] @@ -373,29 +379,34 @@ fn test_skip_serializing_struct() { &SkipSerializingStruct { a: &a, b: 2, + c: 3, d: Some(4), e: vec![5], }, &[ - Token::StructStart("SkipSerializingStruct", Some(3)), + Token::StructStart("SkipSerializingStruct", Some(4)), - Token::MapSep, + Token::StructSep, Token::Str("a"), Token::I8(1), - Token::MapSep, + Token::StructSep, + Token::Str("c"), + Token::I32(3), + + Token::StructSep, Token::Str("d"), Token::Option(true), Token::I32(4), - Token::MapSep, + Token::StructSep, Token::Str("e"), Token::SeqStart(Some(1)), Token::SeqSep, Token::I32(5), Token::SeqEnd, - Token::MapEnd, + Token::StructEnd, ] ); @@ -403,27 +414,30 @@ fn test_skip_serializing_struct() { &SkipSerializingStruct { a: &a, b: 2, + c: 123, d: None::, e: Vec::::new(), }, &[ Token::StructStart("SkipSerializingStruct", Some(1)), - Token::MapSep, + Token::StructSep, Token::Str("a"), Token::I8(1), - Token::MapEnd, + Token::StructEnd, ] ); } #[derive(Debug, PartialEq, Serialize)] -enum SkipSerializingEnum<'a, B, D, E> { +enum SkipSerializingEnum<'a, B, C, D, E> where C: Trait { Struct { a: &'a i8, #[serde(skip_serializing)] _b: B, + #[serde(skip_serializing_if="self.c.should_skip()")] + c: C, #[serde(skip_serializing_if_none)] d: Option, #[serde(skip_serializing_if_empty)] @@ -438,29 +452,34 @@ fn test_skip_serializing_enum() { &SkipSerializingEnum::Struct { a: &a, _b: 2, + c: 3, d: Some(4), e: vec![5], }, &[ - Token::EnumMapStart("SkipSerializingEnum", "Struct", Some(3)), + Token::EnumMapStart("SkipSerializingEnum", "Struct", Some(4)), - Token::MapSep, + Token::EnumMapSep, Token::Str("a"), Token::I8(1), - Token::MapSep, + Token::EnumMapSep, + Token::Str("c"), + Token::I32(3), + + Token::EnumMapSep, Token::Str("d"), Token::Option(true), Token::I32(4), - Token::MapSep, + Token::EnumMapSep, Token::Str("e"), Token::SeqStart(Some(1)), Token::SeqSep, Token::I32(5), Token::SeqEnd, - Token::MapEnd, + Token::EnumMapEnd, ] ); @@ -468,17 +487,18 @@ fn test_skip_serializing_enum() { &SkipSerializingEnum::Struct { a: &a, _b: 2, + c: 123, d: None::, e: Vec::::new(), }, &[ Token::EnumMapStart("SkipSerializingEnum", "Struct", Some(1)), - Token::MapSep, + Token::EnumMapSep, Token::Str("a"), Token::I8(1), - Token::MapEnd, + Token::EnumMapEnd, ] ); } diff --git a/serde_tests/tests/test_de.rs b/serde_tests/tests/test_de.rs index 395e7645..dcc6e8f0 100644 --- a/serde_tests/tests/test_de.rs +++ b/serde_tests/tests/test_de.rs @@ -184,27 +184,27 @@ declare_tests! { ], TupleStruct(1, 2, 3) => vec![ Token::TupleStructStart("TupleStruct", Some(3)), - Token::SeqSep, + Token::TupleSeqSep, Token::I32(1), - Token::SeqSep, + Token::TupleSeqSep, Token::I32(2), - Token::SeqSep, + Token::TupleSeqSep, Token::I32(3), - Token::SeqEnd, + Token::TupleSeqEnd, ], TupleStruct(1, 2, 3) => vec![ Token::TupleStructStart("TupleStruct", None), - Token::SeqSep, + Token::TupleSeqSep, Token::I32(1), - Token::SeqSep, + Token::TupleSeqSep, Token::I32(2), - Token::SeqSep, + Token::TupleSeqSep, Token::I32(3), - Token::SeqEnd, + Token::TupleSeqEnd, ], } test_btreeset { @@ -495,18 +495,18 @@ declare_tests! { ], Struct { a: 1, b: 2, c: 3 } => vec![ Token::StructStart("Struct", Some(3)), - Token::MapSep, + Token::StructSep, Token::Str("a"), Token::I32(1), - Token::MapSep, + Token::StructSep, Token::Str("b"), Token::I32(2), - Token::MapSep, + Token::StructSep, Token::Str("c"), Token::I32(3), - Token::MapEnd, + Token::StructEnd, ], } test_enum_unit { @@ -516,39 +516,39 @@ declare_tests! { } test_enum_simple { Enum::Simple(1) => vec![ - Token::EnumNewtype("Enum", "Simple"), + Token::EnumNewType("Enum", "Simple"), Token::I32(1), ], } test_enum_seq { Enum::Seq(1, 2, 3) => vec![ Token::EnumSeqStart("Enum", "Seq", Some(3)), - Token::SeqSep, + Token::EnumSeqSep, Token::I32(1), - Token::SeqSep, + Token::EnumSeqSep, Token::I32(2), - Token::SeqSep, + Token::EnumSeqSep, Token::I32(3), - Token::SeqEnd, + Token::EnumSeqEnd, ], } test_enum_map { Enum::Map { a: 1, b: 2, c: 3 } => vec![ Token::EnumMapStart("Enum", "Map", Some(3)), - Token::MapSep, + Token::EnumMapSep, Token::Str("a"), Token::I32(1), - Token::MapSep, + Token::EnumMapSep, Token::Str("b"), Token::I32(2), - Token::MapSep, + Token::EnumMapSep, Token::Str("c"), Token::I32(3), - Token::MapEnd, + Token::EnumMapEnd, ], } test_enum_unit_usize { diff --git a/serde_tests/tests/test_macros.rs b/serde_tests/tests/test_macros.rs index f8396fb7..842fa670 100644 --- a/serde_tests/tests/test_macros.rs +++ b/serde_tests/tests/test_macros.rs @@ -123,7 +123,7 @@ pub struct GenericStruct { } #[derive(Debug, PartialEq, Serialize, Deserialize)] -pub struct GenericNewtypeStruct(T); +pub struct GenericNewTypeStruct(T); #[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct GenericTupleStruct(T, U); @@ -131,7 +131,7 @@ pub struct GenericTupleStruct(T, U); #[derive(Debug, PartialEq, Serialize, Deserialize)] pub enum GenericEnum { Unit, - Newtype(T), + NewType(T), Seq(T, U), Map { x: T, y: U }, } @@ -153,16 +153,16 @@ fn test_ser_named_tuple() { &SerNamedTuple(&a, &mut b, c), &[ Token::TupleStructStart("SerNamedTuple", Some(3)), - Token::SeqSep, + Token::TupleSeqSep, Token::I32(5), - Token::SeqSep, + Token::TupleSeqSep, Token::I32(6), - Token::SeqSep, + Token::TupleSeqSep, Token::I32(7), - Token::SeqEnd, + Token::TupleSeqEnd, ], ); } @@ -172,7 +172,7 @@ fn test_de_named_tuple() { assert_de_tokens( &DeNamedTuple(5, 6, 7), vec![ - Token::TupleStructStart("DeNamedTuple", Some(3)), + Token::SeqStart(Some(3)), Token::SeqSep, Token::I32(5), @@ -185,6 +185,23 @@ fn test_de_named_tuple() { Token::SeqEnd, ] ); + + assert_de_tokens( + &DeNamedTuple(5, 6, 7), + vec![ + Token::TupleStructStart("DeNamedTuple", Some(3)), + Token::TupleSeqSep, + Token::I32(5), + + Token::TupleSeqSep, + Token::I32(6), + + Token::TupleSeqSep, + Token::I32(7), + + Token::TupleSeqEnd, + ] + ); } #[test] @@ -202,19 +219,19 @@ fn test_ser_named_map() { &[ Token::StructStart("SerNamedMap", Some(3)), - Token::MapSep, + Token::StructSep, Token::Str("a"), Token::I32(5), - Token::MapSep, + Token::StructSep, Token::Str("b"), Token::I32(6), - Token::MapSep, + Token::StructSep, Token::Str("c"), Token::I32(7), - Token::MapEnd, + Token::StructEnd, ] ); } @@ -230,19 +247,19 @@ fn test_de_named_map() { vec![ Token::StructStart("DeNamedMap", Some(3)), - Token::MapSep, + Token::StructSep, Token::Str("a"), Token::I32(5), - Token::MapSep, + Token::StructSep, Token::Str("b"), Token::I32(6), - Token::MapSep, + Token::StructSep, Token::Str("c"), Token::I32(7), - Token::MapEnd, + Token::StructEnd, ] ); } @@ -278,19 +295,19 @@ fn test_ser_enum_seq() { &[ Token::EnumSeqStart("SerEnum", "Seq", Some(4)), - Token::SeqSep, + Token::EnumSeqSep, Token::I8(1), - Token::SeqSep, + Token::EnumSeqSep, Token::I32(2), - Token::SeqSep, + Token::EnumSeqSep, Token::I32(3), - Token::SeqSep, + Token::EnumSeqSep, Token::I32(5), - Token::SeqEnd, + Token::EnumSeqEnd, ], ); } @@ -316,23 +333,23 @@ fn test_ser_enum_map() { &[ Token::EnumMapStart("SerEnum", "Map", Some(4)), - Token::MapSep, + Token::EnumMapSep, Token::Str("a"), Token::I8(1), - Token::MapSep, + Token::EnumMapSep, Token::Str("b"), Token::I32(2), - Token::MapSep, + Token::EnumMapSep, Token::Str("c"), Token::I32(3), - Token::MapSep, + Token::EnumMapSep, Token::Str("e"), Token::I32(5), - Token::MapEnd, + Token::EnumMapEnd, ], ); } @@ -368,19 +385,19 @@ fn test_de_enum_seq() { vec![ Token::EnumSeqStart("DeEnum", "Seq", Some(4)), - Token::SeqSep, + Token::EnumSeqSep, Token::I8(1), - Token::SeqSep, + Token::EnumSeqSep, Token::I32(2), - Token::SeqSep, + Token::EnumSeqSep, Token::I32(3), - Token::SeqSep, + Token::EnumSeqSep, Token::I32(5), - Token::SeqEnd, + Token::EnumSeqEnd, ], ); } @@ -406,23 +423,23 @@ fn test_de_enum_map() { vec![ Token::EnumMapStart("DeEnum", "Map", Some(4)), - Token::MapSep, + Token::EnumMapSep, Token::Str("a"), Token::I8(1), - Token::MapSep, + Token::EnumMapSep, Token::Str("b"), Token::I32(2), - Token::MapSep, + Token::EnumMapSep, Token::Str("c"), Token::I32(3), - Token::MapSep, + Token::EnumMapSep, Token::Str("e"), Token::I32(5), - Token::MapEnd, + Token::EnumMapEnd, ], ); } @@ -434,7 +451,7 @@ fn test_lifetimes() { assert_ser_tokens( &Lifetimes::LifetimeSeq(&value), &[ - Token::EnumNewtype("Lifetimes", "LifetimeSeq"), + Token::EnumNewType("Lifetimes", "LifetimeSeq"), Token::I32(5), ] ); @@ -442,7 +459,7 @@ fn test_lifetimes() { assert_ser_tokens( &Lifetimes::NoLifetimeSeq(5), &[ - Token::EnumNewtype("Lifetimes", "NoLifetimeSeq"), + Token::EnumNewType("Lifetimes", "NoLifetimeSeq"), Token::I32(5), ] ); @@ -452,11 +469,11 @@ fn test_lifetimes() { &[ Token::EnumMapStart("Lifetimes", "LifetimeMap", Some(1)), - Token::MapSep, + Token::EnumMapSep, Token::Str("a"), Token::I32(5), - Token::MapEnd, + Token::EnumMapEnd, ] ); @@ -465,11 +482,11 @@ fn test_lifetimes() { &[ Token::EnumMapStart("Lifetimes", "NoLifetimeMap", Some(1)), - Token::MapSep, + Token::EnumMapSep, Token::Str("a"), Token::I32(5), - Token::MapEnd, + Token::EnumMapEnd, ] ); } @@ -481,11 +498,11 @@ fn test_generic_struct() { vec![ Token::StructStart("GenericStruct", Some(1)), - Token::MapSep, + Token::StructSep, Token::Str("x"), Token::U32(5), - Token::MapEnd, + Token::StructEnd, ] ); } @@ -493,9 +510,9 @@ fn test_generic_struct() { #[test] fn test_generic_newtype_struct() { assert_tokens( - &GenericNewtypeStruct(5u32), + &GenericNewTypeStruct(5u32), vec![ - Token::StructNewtype("GenericNewtypeStruct"), + Token::StructNewType("GenericNewTypeStruct"), Token::U32(5), ] ); @@ -508,13 +525,13 @@ fn test_generic_tuple_struct() { vec![ Token::TupleStructStart("GenericTupleStruct", Some(2)), - Token::SeqSep, + Token::TupleSeqSep, Token::U32(5), - Token::SeqSep, + Token::TupleSeqSep, Token::U32(6), - Token::SeqEnd, + Token::TupleSeqEnd, ] ); } @@ -532,9 +549,9 @@ fn test_generic_enum_unit() { #[test] fn test_generic_enum_newtype() { assert_tokens( - &GenericEnum::Newtype::(5), + &GenericEnum::NewType::(5), vec![ - Token::EnumNewtype("GenericEnum", "Newtype"), + Token::EnumNewType("GenericEnum", "NewType"), Token::U32(5), ] ); @@ -547,13 +564,13 @@ fn test_generic_enum_seq() { vec![ Token::EnumSeqStart("GenericEnum", "Seq", Some(2)), - Token::SeqSep, + Token::EnumSeqSep, Token::U32(5), - Token::SeqSep, + Token::EnumSeqSep, Token::U32(6), - Token::SeqEnd, + Token::EnumSeqEnd, ] ); } @@ -565,15 +582,15 @@ fn test_generic_enum_map() { vec![ Token::EnumMapStart("GenericEnum", "Map", Some(2)), - Token::MapSep, + Token::EnumMapSep, Token::Str("x"), Token::U32(5), - Token::MapSep, + Token::EnumMapSep, Token::Str("y"), Token::U32(6), - Token::MapEnd, + Token::EnumMapEnd, ] ); } diff --git a/serde_tests/tests/test_ser.rs b/serde_tests/tests/test_ser.rs index 77bf3eb8..e08d8c14 100644 --- a/serde_tests/tests/test_ser.rs +++ b/serde_tests/tests/test_ser.rs @@ -76,11 +76,11 @@ declare_ser_tests! { } test_result { Ok::(0) => &[ - Token::EnumNewtype("Result", "Ok"), + Token::EnumNewType("Result", "Ok"), Token::I32(0), ], Err::(1) => &[ - Token::EnumNewtype("Result", "Err"), + Token::EnumNewType("Result", "Err"), Token::I32(1), ], } @@ -214,56 +214,56 @@ declare_ser_tests! { test_tuple_struct { TupleStruct(1, 2, 3) => &[ Token::TupleStructStart("TupleStruct", Some(3)), - Token::SeqSep, + Token::TupleSeqSep, Token::I32(1), - Token::SeqSep, + Token::TupleSeqSep, Token::I32(2), - Token::SeqSep, + Token::TupleSeqSep, Token::I32(3), - Token::SeqEnd, + Token::TupleSeqEnd, ], } test_struct { Struct { a: 1, b: 2, c: 3 } => &[ Token::StructStart("Struct", Some(3)), - Token::MapSep, + Token::StructSep, Token::Str("a"), Token::I32(1), - Token::MapSep, + Token::StructSep, Token::Str("b"), Token::I32(2), - Token::MapSep, + Token::StructSep, Token::Str("c"), Token::I32(3), - Token::MapEnd, + Token::StructEnd, ], } test_enum { Enum::Unit => &[Token::EnumUnit("Enum", "Unit")], - Enum::One(42) => &[Token::EnumNewtype("Enum", "One"), Token::I32(42)], + Enum::One(42) => &[Token::EnumNewType("Enum", "One"), Token::I32(42)], Enum::Seq(1, 2) => &[ Token::EnumSeqStart("Enum", "Seq", Some(2)), - Token::SeqSep, + Token::EnumSeqSep, Token::I32(1), - Token::SeqSep, + Token::EnumSeqSep, Token::I32(2), - Token::SeqEnd, + Token::EnumSeqEnd, ], Enum::Map { a: 1, b: 2 } => &[ Token::EnumMapStart("Enum", "Map", Some(2)), - Token::MapSep, + Token::EnumMapSep, Token::Str("a"), Token::I32(1), - Token::MapSep, + Token::EnumMapSep, Token::Str("b"), Token::I32(2), - Token::MapEnd, + Token::EnumMapEnd, ], } test_num_bigint { diff --git a/serde_tests/tests/token.rs b/serde_tests/tests/token.rs index 1b14a7d3..40810d47 100644 --- a/serde_tests/tests/token.rs +++ b/serde_tests/tests/token.rs @@ -2,7 +2,8 @@ use std::fmt; use std::iter; use std::error; -use serde::{ser, de}; +use serde::ser::{self, Serialize}; +use serde::de; use serde::de::value::{self, ValueDeserializer}; #[derive(Clone, PartialEq, Debug)] @@ -30,23 +31,35 @@ pub enum Token<'a> { Unit, UnitStruct(&'a str), - StructNewtype(&'a str), + StructNewType(&'a str), EnumStart(&'a str), EnumUnit(&'a str, &'a str), - EnumNewtype(&'a str, &'a str), - EnumSeqStart(&'a str, &'a str, Option), - EnumMapStart(&'a str, &'a str, Option), + EnumNewType(&'a str, &'a str), SeqStart(Option), - TupleStructStart(&'a str, Option), SeqSep, SeqEnd, + TupleStructStart(&'a str, Option), + TupleSeqSep, + TupleSeqEnd, + MapStart(Option), - StructStart(&'a str, Option), MapSep, MapEnd, + + StructStart(&'a str, Option), + StructSep, + StructEnd, + + EnumSeqStart(&'a str, &'a str, Option), + EnumSeqSep, + EnumSeqEnd, + + EnumMapStart(&'a str, &'a str, Option), + EnumMapSep, + EnumMapEnd, } ////////////////////////////////////////////////////////////////////////////// @@ -102,7 +115,7 @@ impl<'a, I> ser::Serializer for Serializer value: T) -> Result<(), Error> where T: ser::Serialize, { - assert_eq!(self.tokens.next(), Some(&Token::EnumNewtype(name, variant))); + assert_eq!(self.tokens.next(), Some(&Token::EnumNewType(name, variant))); value.serialize(self) } @@ -218,43 +231,65 @@ impl<'a, I> ser::Serializer for Serializer self.visit_sequence(visitor) } + fn serialize_seq_elt(&mut self, value: T) -> Result<(), Error> + where T: ser::Serialize + { + assert_eq!(self.tokens.next(), Some(&Token::SeqSep)); + value.serialize(self) + } + fn serialize_newtype_struct(&mut self, name: &'static str, value: T) -> Result<(), Error> where T: ser::Serialize, { - assert_eq!(self.tokens.next(), Some(&Token::StructNewtype(name))); + assert_eq!(self.tokens.next(), Some(&Token::StructNewType(name))); value.serialize(self) } - fn serialize_tuple_struct(&mut self, name: &str, visitor: V) -> Result<(), Error> + fn serialize_tuple_struct(&mut self, name: &str, mut visitor: V) -> Result<(), Error> where V: ser::SeqVisitor { let len = visitor.len(); assert_eq!(self.tokens.next(), Some(&Token::TupleStructStart(name, len))); - self.visit_sequence(visitor) + while let Some(()) = try!(visitor.visit(self)) { } + + assert_eq!(self.tokens.next(), Some(&Token::TupleSeqEnd)); + + Ok(()) + } + + fn serialize_tuple_struct_elt(&mut self, value: T) -> Result<(), Error> + where T: ser::Serialize, + { + assert_eq!(self.tokens.next(), Some(&Token::TupleSeqSep)); + value.serialize(self) } fn serialize_tuple_variant(&mut self, - name: &str, - _variant_index: usize, - variant: &str, - visitor: V) -> Result<(), Error> + name: &str, + _variant_index: usize, + variant: &str, + mut visitor: V) -> Result<(), Error> where V: ser::SeqVisitor { let len = visitor.len(); assert_eq!(self.tokens.next(), Some(&Token::EnumSeqStart(name, variant, len))); - self.visit_sequence(visitor) + while let Some(()) = try!(visitor.visit(self)) { } + + assert_eq!(self.tokens.next(), Some(&Token::EnumSeqEnd)); + + Ok(()) } - fn serialize_seq_elt(&mut self, value: T) -> Result<(), Error> - where T: ser::Serialize + fn serialize_tuple_variant_elt(&mut self, value: T) -> Result<(), Error> + where T: ser::Serialize, { - assert_eq!(self.tokens.next(), Some(&Token::SeqSep)); + assert_eq!(self.tokens.next(), Some(&Token::EnumSeqSep)); value.serialize(self) } @@ -268,35 +303,61 @@ impl<'a, I> ser::Serializer for Serializer self.visit_mapping(visitor) } - fn serialize_struct(&mut self, name: &str, visitor: V) -> Result<(), Error> + fn serialize_map_elt(&mut self, key: K, value: V) -> Result<(), Error> + where K: ser::Serialize, + V: ser::Serialize, + { + assert_eq!(self.tokens.next(), Some(&Token::MapSep)); + + try!(key.serialize(self)); + value.serialize(self) + } + + fn serialize_struct(&mut self, name: &str, mut visitor: V) -> Result<(), Error> where V: ser::MapVisitor { let len = visitor.len(); assert_eq!(self.tokens.next(), Some(&Token::StructStart(name, len))); - self.visit_mapping(visitor) + while let Some(()) = try!(visitor.visit(self)) { } + + assert_eq!(self.tokens.next(), Some(&Token::StructEnd)); + + Ok(()) + } + + fn serialize_struct_elt(&mut self, key: &'static str, value: T) -> Result<(), Error> + where T: ser::Serialize, + { + assert_eq!(self.tokens.next(), Some(&Token::StructSep)); + + try!(key.serialize(self)); + value.serialize(self) } fn serialize_struct_variant(&mut self, - name: &str, - _variant_index: usize, - variant: &str, - visitor: V) -> Result<(), Error> + name: &str, + _variant_index: usize, + variant: &str, + mut visitor: V) -> Result<(), Error> where V: ser::MapVisitor { let len = visitor.len(); assert_eq!(self.tokens.next(), Some(&Token::EnumMapStart(name, variant, len))); - self.visit_mapping(visitor) + while let Some(()) = try!(visitor.visit(self)) { } + + assert_eq!(self.tokens.next(), Some(&Token::EnumMapEnd)); + + Ok(()) } - fn serialize_map_elt(&mut self, key: K, value: V) -> Result<(), Error> - where K: ser::Serialize, - V: ser::Serialize, + fn serialize_struct_variant_elt(&mut self, key: &'static str, value: T) -> Result<(), Error> + where T: ser::Serialize, { - assert_eq!(self.tokens.next(), Some(&Token::MapSep)); + assert_eq!(self.tokens.next(), Some(&Token::EnumMapSep)); try!(key.serialize(self)); value.serialize(self) @@ -383,6 +444,24 @@ impl Deserializer }) } + fn visit_tuple_seq(&mut self, len: Option, mut visitor: V) -> Result + where V: de::Visitor, + { + visitor.visit_seq(DeserializerTupleSeqVisitor { + de: self, + len: len, + }) + } + + fn visit_variant_seq(&mut self, len: Option, mut visitor: V) -> Result + where V: de::Visitor, + { + visitor.visit_seq(DeserializerVariantSeqVisitor { + de: self, + len: len, + }) + } + fn visit_map(&mut self, len: Option, mut visitor: V) -> Result where V: de::Visitor, { @@ -391,6 +470,24 @@ impl Deserializer len: len, }) } + + fn visit_struct(&mut self, len: Option, mut visitor: V) -> Result + where V: de::Visitor, + { + visitor.visit_map(DeserializerStructVisitor { + de: self, + len: len, + }) + } + + fn visit_variant_map(&mut self, len: Option, mut visitor: V) -> Result + where V: de::Visitor, + { + visitor.visit_map(DeserializerVariantMapVisitor { + de: self, + len: len, + }) + } } impl de::Deserializer for Deserializer @@ -429,7 +526,6 @@ impl de::Deserializer for Deserializer Some(Token::MapStart(len)) | Some(Token::StructStart(_, len)) => { self.visit_map(len, visitor) } - //Some(Token::Name(_)) => self.visit(visitor), Some(token) => Err(Error::UnexpectedToken(token)), None => Err(Error::EndOfStreamError), } @@ -473,7 +569,7 @@ impl de::Deserializer for Deserializer }) } Some(&Token::EnumUnit(n, _)) - | Some(&Token::EnumNewtype(n, _)) + | Some(&Token::EnumNewType(n, _)) | Some(&Token::EnumSeqStart(n, _, _)) | Some(&Token::EnumMapStart(n, _, _)) if name == n => { visitor.visit(DeserializerVariantVisitor { @@ -506,12 +602,12 @@ impl de::Deserializer for Deserializer } fn deserialize_newtype_struct(&mut self, - name: &str, - mut visitor: V) -> Result + name: &str, + mut visitor: V) -> Result where V: de::Visitor, { match self.tokens.peek() { - Some(&Token::StructNewtype(n)) => { + Some(&Token::StructNewType(n)) => { self.tokens.next(); if name == n { visitor.visit_newtype_struct(self) @@ -525,9 +621,9 @@ impl de::Deserializer for Deserializer } fn deserialize_tuple_struct(&mut self, - name: &str, - len: usize, - mut visitor: V) -> Result + name: &str, + len: usize, + mut visitor: V) -> Result where V: de::Visitor, { match self.tokens.peek() { @@ -542,7 +638,7 @@ impl de::Deserializer for Deserializer Some(&Token::TupleStructStart(n, _)) => { self.tokens.next(); if name == n { - self.visit_seq(Some(len), visitor) + self.visit_tuple_seq(Some(len), visitor) } else { Err(Error::InvalidName(n)) } @@ -557,16 +653,16 @@ impl de::Deserializer for Deserializer } fn deserialize_struct(&mut self, - name: &str, - fields: &'static [&'static str], - visitor: V) -> Result + name: &str, + fields: &'static [&'static str], + visitor: V) -> Result where V: de::Visitor, { match self.tokens.peek() { Some(&Token::StructStart(n, _)) => { self.tokens.next(); if name == n { - self.visit_map(Some(fields.len()), visitor) + self.visit_struct(Some(fields.len()), visitor) } else { Err(Error::InvalidName(n)) } @@ -628,6 +724,96 @@ impl<'a, I> de::SeqVisitor for DeserializerSeqVisitor<'a, I> ////////////////////////////////////////////////////////////////////////// +struct DeserializerTupleSeqVisitor<'a, I: 'a> where I: Iterator> { + de: &'a mut Deserializer, + len: Option, +} + +impl<'a, I> de::SeqVisitor for DeserializerTupleSeqVisitor<'a, I> + where I: Iterator>, +{ + type Error = Error; + + fn visit(&mut self) -> Result, Error> + where T: de::Deserialize, + { + match self.de.tokens.peek() { + Some(&Token::TupleSeqSep) => { + self.de.tokens.next(); + self.len = self.len.map(|len| len - 1); + Ok(Some(try!(de::Deserialize::deserialize(self.de)))) + } + Some(&Token::TupleSeqEnd) => Ok(None), + Some(_) => { + let token = self.de.tokens.next().unwrap(); + Err(Error::UnexpectedToken(token)) + } + None => Err(Error::EndOfStreamError), + } + } + + fn end(&mut self) -> Result<(), Error> { + //assert_eq!(self.len.unwrap_or(0), 0); + match self.de.tokens.next() { + Some(Token::TupleSeqEnd) => Ok(()), + Some(token) => Err(Error::UnexpectedToken(token)), + None => Err(Error::EndOfStreamError), + } + } + + fn size_hint(&self) -> (usize, Option) { + let len = self.len.unwrap_or(0); + (len, self.len) + } +} + +////////////////////////////////////////////////////////////////////////// + +struct DeserializerVariantSeqVisitor<'a, I: 'a> where I: Iterator> { + de: &'a mut Deserializer, + len: Option, +} + +impl<'a, I> de::SeqVisitor for DeserializerVariantSeqVisitor<'a, I> + where I: Iterator>, +{ + type Error = Error; + + fn visit(&mut self) -> Result, Error> + where T: de::Deserialize, + { + match self.de.tokens.peek() { + Some(&Token::EnumSeqSep) => { + self.de.tokens.next(); + self.len = self.len.map(|len| len - 1); + Ok(Some(try!(de::Deserialize::deserialize(self.de)))) + } + Some(&Token::EnumSeqEnd) => Ok(None), + Some(_) => { + let token = self.de.tokens.next().unwrap(); + Err(Error::UnexpectedToken(token)) + } + None => Err(Error::EndOfStreamError), + } + } + + fn end(&mut self) -> Result<(), Error> { + //assert_eq!(self.len.unwrap_or(0), 0); + match self.de.tokens.next() { + Some(Token::EnumSeqEnd) => Ok(()), + Some(token) => Err(Error::UnexpectedToken(token)), + None => Err(Error::EndOfStreamError), + } + } + + fn size_hint(&self) -> (usize, Option) { + let len = self.len.unwrap_or(0); + (len, self.len) + } +} + +////////////////////////////////////////////////////////////////////////// + struct DeserializerMapVisitor<'a, I: 'a> where I: Iterator> { de: &'a mut Deserializer, len: Option, @@ -679,6 +865,57 @@ impl<'a, I> de::MapVisitor for DeserializerMapVisitor<'a, I> ////////////////////////////////////////////////////////////////////////// +struct DeserializerStructVisitor<'a, I: 'a> where I: Iterator> { + de: &'a mut Deserializer, + len: Option, +} + +impl<'a, I> de::MapVisitor for DeserializerStructVisitor<'a, I> + where I: Iterator>, +{ + type Error = Error; + + fn visit_key(&mut self) -> Result, Error> + where K: de::Deserialize, + { + match self.de.tokens.peek() { + Some(&Token::StructSep) => { + self.de.tokens.next(); + self.len = self.len.map(|len| if len > 0 { len - 1} else { 0 }); + Ok(Some(try!(de::Deserialize::deserialize(self.de)))) + } + Some(&Token::StructEnd) => Ok(None), + Some(_) => { + let token = self.de.tokens.next().unwrap(); + Err(Error::UnexpectedToken(token)) + } + None => Err(Error::EndOfStreamError), + } + } + + fn visit_value(&mut self) -> Result + where V: de::Deserialize, + { + Ok(try!(de::Deserialize::deserialize(self.de))) + } + + fn end(&mut self) -> Result<(), Error> { + //assert_eq!(self.len.unwrap_or(0), 0); + match self.de.tokens.next() { + Some(Token::StructEnd) => Ok(()), + Some(token) => Err(Error::UnexpectedToken(token)), + None => Err(Error::EndOfStreamError), + } + } + + fn size_hint(&self) -> (usize, Option) { + let len = self.len.unwrap_or(0); + (len, self.len) + } +} + +////////////////////////////////////////////////////////////////////////// + struct DeserializerVariantVisitor<'a, I: 'a> where I: Iterator> { de: &'a mut Deserializer, } @@ -693,7 +930,7 @@ impl<'a, I> de::VariantVisitor for DeserializerVariantVisitor<'a, I> { match self.de.tokens.peek() { Some(&Token::EnumUnit(_, v)) - | Some(&Token::EnumNewtype(_, v)) + | Some(&Token::EnumNewType(_, v)) | Some(&Token::EnumSeqStart(_, v, _)) | Some(&Token::EnumMapStart(_, v, _)) => { let mut de = ValueDeserializer::::into_deserializer(v); @@ -724,7 +961,7 @@ impl<'a, I> de::VariantVisitor for DeserializerVariantVisitor<'a, I> where T: de::Deserialize, { match self.de.tokens.peek() { - Some(&Token::EnumNewtype(_, _)) => { + Some(&Token::EnumNewType(_, _)) => { self.de.tokens.next(); de::Deserialize::deserialize(self.de) } @@ -744,6 +981,15 @@ impl<'a, I> de::VariantVisitor for DeserializerVariantVisitor<'a, I> Some(&Token::EnumSeqStart(_, _, Some(enum_len))) => { let token = self.de.tokens.next().unwrap(); + if len == enum_len { + self.de.visit_variant_seq(Some(len), visitor) + } else { + Err(Error::UnexpectedToken(token)) + } + } + Some(&Token::SeqStart(Some(enum_len))) => { + let token = self.de.tokens.next().unwrap(); + if len == enum_len { self.de.visit_seq(Some(len), visitor) } else { @@ -766,6 +1012,15 @@ impl<'a, I> de::VariantVisitor for DeserializerVariantVisitor<'a, I> Some(&Token::EnumMapStart(_, _, Some(enum_len))) => { let token = self.de.tokens.next().unwrap(); + if fields.len() == enum_len { + self.de.visit_variant_map(Some(fields.len()), visitor) + } else { + Err(Error::UnexpectedToken(token)) + } + } + Some(&Token::MapStart(Some(enum_len))) => { + let token = self.de.tokens.next().unwrap(); + if fields.len() == enum_len { self.de.visit_map(Some(fields.len()), visitor) } else { @@ -780,6 +1035,57 @@ impl<'a, I> de::VariantVisitor for DeserializerVariantVisitor<'a, I> } } +////////////////////////////////////////////////////////////////////////// + +struct DeserializerVariantMapVisitor<'a, I: 'a> where I: Iterator> { + de: &'a mut Deserializer, + len: Option, +} + +impl<'a, I> de::MapVisitor for DeserializerVariantMapVisitor<'a, I> + where I: Iterator>, +{ + type Error = Error; + + fn visit_key(&mut self) -> Result, Error> + where K: de::Deserialize, + { + match self.de.tokens.peek() { + Some(&Token::EnumMapSep) => { + self.de.tokens.next(); + self.len = self.len.map(|len| if len > 0 { len - 1} else { 0 }); + Ok(Some(try!(de::Deserialize::deserialize(self.de)))) + } + Some(&Token::EnumMapEnd) => Ok(None), + Some(_) => { + let token = self.de.tokens.next().unwrap(); + Err(Error::UnexpectedToken(token)) + } + None => Err(Error::EndOfStreamError), + } + } + + fn visit_value(&mut self) -> Result + where V: de::Deserialize, + { + Ok(try!(de::Deserialize::deserialize(self.de))) + } + + fn end(&mut self) -> Result<(), Error> { + //assert_eq!(self.len.unwrap_or(0), 0); + match self.de.tokens.next() { + Some(Token::EnumMapEnd) => Ok(()), + Some(token) => Err(Error::UnexpectedToken(token)), + None => Err(Error::EndOfStreamError), + } + } + + fn size_hint(&self) -> (usize, Option) { + let len = self.len.unwrap_or(0); + (len, self.len) + } +} + ////////////////////////////////////////////////////////////////////////////// pub fn assert_ser_tokens(value: &T, tokens: &[Token])