diff --git a/serde/src/ser/mod.rs b/serde/src/ser/mod.rs index 4356f930..e934adb9 100644 --- a/serde/src/ser/mod.rs +++ b/serde/src/ser/mod.rs @@ -1727,6 +1727,13 @@ pub trait SerializeStruct { where T: Serialize; + /// Indicate that a struct field has been skipped. + #[inline] + fn skip_field(&mut self, key: &'static str) -> Result<(), Self::Error> { + let _ = key; + Ok(()) + } + /// Finish serializing a struct. fn end(self) -> Result<Self::Ok, Self::Error>; } @@ -1772,6 +1779,13 @@ pub trait SerializeStructVariant { where T: Serialize; + /// Indicate that a struct variant field has been skipped. + #[inline] + fn skip_field(&mut self, key: &'static str) -> Result<(), Self::Error> { + let _ = key; + Ok(()) + } + /// Finish serializing a struct variant. fn end(self) -> Result<Self::Ok, Self::Error>; } diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 5ab6d0a9..8f6f717b 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -1384,26 +1384,27 @@ fn deserialize_identifier( "field identifier" }; - let visit_index = if is_variant { - let variant_indices = 0u32..; - let fallthrough_msg = format!("variant index 0 <= i < {}", fields.len()); - let visit_index = quote! { - fn visit_u32<__E>(self, __value: u32) -> _serde::export::Result<Self::Value, __E> - where __E: _serde::de::Error - { - match __value { - #( - #variant_indices => _serde::export::Ok(#constructors), - )* - _ => _serde::export::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value as u64), - &#fallthrough_msg)) - } - } - }; - Some(visit_index) + let index_expecting = if is_variant { + "variant" } else { - None + "field" + }; + + let variant_indices = 0u32..; + let fallthrough_msg = format!("{} index 0 <= i < {}", index_expecting, fields.len()); + let visit_index = quote! { + fn visit_u32<__E>(self, __value: u32) -> _serde::export::Result<Self::Value, __E> + where __E: _serde::de::Error + { + match __value { + #( + #variant_indices => _serde::export::Ok(#constructors), + )* + _ => _serde::export::Err(_serde::de::Error::invalid_value( + _serde::de::Unexpected::Unsigned(__value as u64), + &#fallthrough_msg)) + } + } }; let bytes_to_str = if fallthrough.is_some() { diff --git a/serde_derive/src/ser.rs b/serde_derive/src/ser.rs index 9be9bddc..9c3310be 100644 --- a/serde_derive/src/ser.rs +++ b/serde_derive/src/ser.rs @@ -242,6 +242,7 @@ fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Contai params, false, quote!(_serde::ser::SerializeStruct::serialize_field), + quote!(_serde::ser::SerializeStruct::skip_field), ); let type_name = cattrs.name().serialize_name(); @@ -707,15 +708,23 @@ fn serialize_struct_variant<'a>( fields: &[Field], name: &str, ) -> Fragment { - let method = match context { + let (method, skip_method) = match context { StructVariant::ExternallyTagged { .. } => { - quote!(_serde::ser::SerializeStructVariant::serialize_field) + ( + quote!(_serde::ser::SerializeStructVariant::serialize_field), + quote!(_serde::ser::SerializeStructVariant::skip_field), + ) } StructVariant::InternallyTagged { .. } | - StructVariant::Untagged => quote!(_serde::ser::SerializeStruct::serialize_field), + StructVariant::Untagged => { + ( + quote!(_serde::ser::SerializeStruct::serialize_field), + quote!(_serde::ser::SerializeStruct::skip_field), + ) + } }; - let serialize_fields = serialize_struct_visitor(fields, params, true, method); + let serialize_fields = serialize_struct_visitor(fields, params, true, method, skip_method); let mut serialized_fields = fields .iter() @@ -829,6 +838,7 @@ fn serialize_struct_visitor( params: &Parameters, is_enum: bool, func: Tokens, + skip_func: Tokens, ) -> Vec<Tokens> { fields .iter() @@ -859,7 +869,15 @@ fn serialize_struct_visitor( match skip { None => ser, - Some(skip) => quote!(if !#skip { #ser }), + Some(skip) => { + quote! { + if !#skip { + #ser + } else { + try!(#skip_func(&mut __serde_state, #key_expr)); + } + } + } } }, ) diff --git a/test_suite/tests/test_de.rs b/test_suite/tests/test_de.rs index 9fbfed46..da7232a5 100644 --- a/test_suite/tests/test_de.rs +++ b/test_suite/tests/test_de.rs @@ -521,6 +521,15 @@ declare_tests! { Token::I32(2), Token::MapEnd, ], + Struct { a: 1, b: 2, c: 0 } => &[ + Token::Map { len: Some(3) }, + Token::U32(0), + Token::I32(1), + + Token::U32(1), + Token::I32(2), + Token::MapEnd, + ], Struct { a: 1, b: 2, c: 0 } => &[ Token::Struct { name: "Struct", len: 3 }, Token::Str("a"),