From 979df3427bfbf9462cd93eaece3c451ca656f5e6 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 6 May 2018 20:14:35 -0700 Subject: [PATCH] Support serializing enums containing flatten --- serde_derive/src/ser.rs | 90 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/serde_derive/src/ser.rs b/serde_derive/src/ser.rs index e40ed46d..987cc53a 100644 --- a/serde_derive/src/ser.rs +++ b/serde_derive/src/ser.rs @@ -789,6 +789,10 @@ fn serialize_struct_variant<'a>( fields: &[Field], name: &str, ) -> Fragment { + if fields.iter().any(|field| field.attrs.flatten()) { + return serialize_struct_variant_with_flatten(context, params, fields, name); + } + let struct_trait = match context { StructVariant::ExternallyTagged { .. } => (StructTrait::SerializeStructVariant), StructVariant::InternallyTagged { .. } | StructVariant::Untagged => { @@ -863,6 +867,92 @@ fn serialize_struct_variant<'a>( } } +fn serialize_struct_variant_with_flatten<'a>( + context: StructVariant<'a>, + params: &Parameters, + fields: &[Field], + name: &str, +) -> Fragment { + let struct_trait = StructTrait::SerializeMap; + let serialize_fields = serialize_struct_visitor(fields, params, true, &struct_trait); + + let mut serialized_fields = fields + .iter() + .filter(|&field| !field.attrs.skip_serializing()) + .peekable(); + + let let_mut = mut_if(serialized_fields.peek().is_some()); + + match context { + StructVariant::ExternallyTagged { + variant_index, + variant_name, + } => { + let this = ¶ms.this; + let fields_ty = fields.iter().map(|f| &f.ty); + let fields_ident = &fields.iter().map(|f| f.ident).collect::>(); + + let (_, ty_generics, where_clause) = params.generics.split_for_impl(); + let wrapper_generics = bound::with_lifetime_bound(¶ms.generics, "'__a"); + let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl(); + + quote_block! { + struct __EnumFlatten #wrapper_generics #where_clause { + data: (#(&'__a #fields_ty,)*), + phantom: _serde::export::PhantomData<#this #ty_generics>, + } + + impl #wrapper_impl_generics _serde::Serialize for __EnumFlatten #wrapper_ty_generics #where_clause { + fn serialize<__S>(&self, __serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error> + where + __S: _serde::Serializer, + { + let (#(#fields_ident,)*) = self.data; + let #let_mut __serde_state = try!(_serde::Serializer::serialize_map( + __serializer, + _serde::export::None)); + #(#serialize_fields)* + _serde::ser::SerializeMap::end(__serde_state) + } + } + + _serde::Serializer::serialize_newtype_variant( + __serializer, + #name, + #variant_index, + #variant_name, + &__EnumFlatten { + data: (#(#fields_ident,)*), + phantom: _serde::export::PhantomData::<#this #ty_generics>, + }) + } + } + StructVariant::InternallyTagged { tag, variant_name } => { + quote_block! { + let #let_mut __serde_state = try!(_serde::Serializer::serialize_map( + __serializer, + _serde::export::None)); + try!(_serde::ser::SerializeMap::serialize_entry( + &mut __serde_state, + #tag, + #variant_name, + )); + #(#serialize_fields)* + _serde::ser::SerializeMap::end(__serde_state) + } + } + StructVariant::Untagged => { + quote_block! { + let #let_mut __serde_state = try!(_serde::Serializer::serialize_map( + __serializer, + _serde::export::None)); + #(#serialize_fields)* + _serde::ser::SerializeMap::end(__serde_state) + } + } + } +} + fn serialize_tuple_struct_visitor( fields: &[Field], params: &Parameters,