diff --git a/serde_derive/src/ser.rs b/serde_derive/src/ser.rs index 4c8d8e64..2d04f278 100644 --- a/serde_derive/src/ser.rs +++ b/serde_derive/src/ser.rs @@ -243,8 +243,25 @@ fn serialize_tuple_struct( serialize_tuple_struct_visitor(fields, params, false, &TupleTrait::SerializeTupleStruct); let type_name = cattrs.name().serialize_name(); - let len = serialize_stmts.len(); - let let_mut = mut_if(len > 0); + + let mut serialized_fields = fields + .iter() + .enumerate() + .filter(|&(_, ref field)| !field.attrs.skip_serializing()) + .peekable(); + + let let_mut = mut_if(serialized_fields.peek().is_some()); + + let len = serialized_fields + .map(|(i, field)| match field.attrs.skip_serializing_if() { + None => quote!(1), + Some(path) => { + let index = syn::Index { index: i as u32, span: Span::call_site() }; + let field_expr = get_member(params, field, &Member::Unnamed(index)); + quote!(if #path(#field_expr) { 0 } else { 1 }) + } + }) + .fold(quote!(0), |sum, expr| quote!(#sum + #expr)); quote_block! { let #let_mut __serde_state = try!(_serde::Serializer::serialize_tuple_struct(__serializer, #type_name, #len)); @@ -743,8 +760,23 @@ fn serialize_tuple_variant( let serialize_stmts = serialize_tuple_struct_visitor(fields, params, true, &tuple_trait); - let len = serialize_stmts.len(); - let let_mut = mut_if(len > 0); + let mut serialized_fields = fields + .iter() + .enumerate() + .filter(|&(_, ref field)| !field.attrs.skip_serializing()) + .peekable(); + + let let_mut = mut_if(serialized_fields.peek().is_some()); + + let len = serialized_fields + .map(|(i, field)| match field.attrs.skip_serializing_if() { + None => quote!(1), + Some(path) => { + let field_expr = Ident::new(&format!("__field{}", i), Span::call_site()); + quote!(if #path(#field_expr) { 0 } else { 1 }) + } + }) + .fold(quote!(0), |sum, expr| quote!(#sum + #expr)); match context { TupleVariant::ExternallyTagged { diff --git a/test_suite/tests/test_annotations.rs b/test_suite/tests/test_annotations.rs index d3ae4726..00c3aec3 100644 --- a/test_suite/tests/test_annotations.rs +++ b/test_suite/tests/test_annotations.rs @@ -687,7 +687,7 @@ fn test_skip_serializing_tuple_struct() { &[ Token::TupleStruct { name: "SkipSerializingTupleStruct", - len: 2, + len: 1, }, Token::I8(1), Token::TupleStructEnd, @@ -807,7 +807,7 @@ fn test_skip_serializing_enum() { Token::TupleVariant { name: "SkipSerializingEnum", variant: "Tuple", - len: 2, + len: 1, }, Token::I8(1), Token::TupleVariantEnd,