| use proc_macro2::{Span, TokenStream}; |
| use syn::spanned::Spanned; |
| use syn::{self, Ident, Index, Member}; |
| |
| use bound; |
| use dummy; |
| use fragment::{Fragment, Match, Stmts}; |
| use internals::ast::{Container, Data, Field, Style, Variant}; |
| use internals::{attr, replace_receiver, Ctxt, Derive}; |
| use pretend; |
| |
| pub fn expand_derive_serialize( |
| input: &mut syn::DeriveInput, |
| ) -> Result<TokenStream, Vec<syn::Error>> { |
| replace_receiver(input); |
| |
| let ctxt = Ctxt::new(); |
| let cont = match Container::from_ast(&ctxt, input, Derive::Serialize) { |
| Some(cont) => cont, |
| None => return Err(ctxt.check().unwrap_err()), |
| }; |
| precondition(&ctxt, &cont); |
| ctxt.check()?; |
| |
| let ident = &cont.ident; |
| let params = Parameters::new(&cont); |
| let (impl_generics, ty_generics, where_clause) = params.generics.split_for_impl(); |
| let body = Stmts(serialize_body(&cont, ¶ms)); |
| let serde = cont.attrs.serde_path(); |
| |
| let impl_block = if let Some(remote) = cont.attrs.remote() { |
| let vis = &input.vis; |
| let used = pretend::pretend_used(&cont, params.is_packed); |
| quote! { |
| impl #impl_generics #ident #ty_generics #where_clause { |
| #vis fn serialize<__S>(__self: &#remote #ty_generics, __serializer: __S) -> #serde::__private::Result<__S::Ok, __S::Error> |
| where |
| __S: #serde::Serializer, |
| { |
| #used |
| #body |
| } |
| } |
| } |
| } else { |
| quote! { |
| #[automatically_derived] |
| impl #impl_generics #serde::Serialize for #ident #ty_generics #where_clause { |
| fn serialize<__S>(&self, __serializer: __S) -> #serde::__private::Result<__S::Ok, __S::Error> |
| where |
| __S: #serde::Serializer, |
| { |
| #body |
| } |
| } |
| } |
| }; |
| |
| Ok(dummy::wrap_in_const( |
| cont.attrs.custom_serde_path(), |
| "SERIALIZE", |
| ident, |
| impl_block, |
| )) |
| } |
| |
| fn precondition(cx: &Ctxt, cont: &Container) { |
| match cont.attrs.identifier() { |
| attr::Identifier::No => {} |
| attr::Identifier::Field => { |
| cx.error_spanned_by(cont.original, "field identifiers cannot be serialized"); |
| } |
| attr::Identifier::Variant => { |
| cx.error_spanned_by(cont.original, "variant identifiers cannot be serialized"); |
| } |
| } |
| } |
| |
| struct Parameters { |
| /// Variable holding the value being serialized. Either `self` for local |
| /// types or `__self` for remote types. |
| self_var: Ident, |
| |
| /// Path to the type the impl is for. Either a single `Ident` for local |
| /// types or `some::remote::Ident` for remote types. Does not include |
| /// generic parameters. |
| this: syn::Path, |
| |
| /// Generics including any explicit and inferred bounds for the impl. |
| generics: syn::Generics, |
| |
| /// Type has a `serde(remote = "...")` attribute. |
| is_remote: bool, |
| |
| /// Type has a repr(packed) attribute. |
| is_packed: bool, |
| } |
| |
| impl Parameters { |
| fn new(cont: &Container) -> Self { |
| let is_remote = cont.attrs.remote().is_some(); |
| let self_var = if is_remote { |
| Ident::new("__self", Span::call_site()) |
| } else { |
| Ident::new("self", Span::call_site()) |
| }; |
| |
| let this = match cont.attrs.remote() { |
| Some(remote) => remote.clone(), |
| None => cont.ident.clone().into(), |
| }; |
| |
| let is_packed = cont.attrs.is_packed(); |
| |
| let generics = build_generics(cont); |
| |
| Parameters { |
| self_var, |
| this, |
| generics, |
| is_remote, |
| is_packed, |
| } |
| } |
| |
| /// Type name to use in error messages and `&'static str` arguments to |
| /// various Serializer methods. |
| fn type_name(&self) -> String { |
| self.this.segments.last().unwrap().ident.to_string() |
| } |
| } |
| |
| // All the generics in the input, plus a bound `T: Serialize` for each generic |
| // field type that will be serialized by us. |
| fn build_generics(cont: &Container) -> syn::Generics { |
| let generics = bound::without_defaults(cont.generics); |
| |
| let generics = |
| bound::with_where_predicates_from_fields(cont, &generics, attr::Field::ser_bound); |
| |
| let generics = |
| bound::with_where_predicates_from_variants(cont, &generics, attr::Variant::ser_bound); |
| |
| match cont.attrs.ser_bound() { |
| Some(predicates) => bound::with_where_predicates(&generics, predicates), |
| None => bound::with_bound( |
| cont, |
| &generics, |
| needs_serialize_bound, |
| &parse_quote!(_serde::Serialize), |
| ), |
| } |
| } |
| |
| // Fields with a `skip_serializing` or `serialize_with` attribute, or which |
| // belong to a variant with a 'skip_serializing` or `serialize_with` attribute, |
| // are not serialized by us so we do not generate a bound. Fields with a `bound` |
| // attribute specify their own bound so we do not generate one. All other fields |
| // may need a `T: Serialize` bound where T is the type of the field. |
| fn needs_serialize_bound(field: &attr::Field, variant: Option<&attr::Variant>) -> bool { |
| !field.skip_serializing() |
| && field.serialize_with().is_none() |
| && field.ser_bound().is_none() |
| && variant.map_or(true, |variant| { |
| !variant.skip_serializing() |
| && variant.serialize_with().is_none() |
| && variant.ser_bound().is_none() |
| }) |
| } |
| |
| fn serialize_body(cont: &Container, params: &Parameters) -> Fragment { |
| if cont.attrs.transparent() { |
| serialize_transparent(cont, params) |
| } else if let Some(type_into) = cont.attrs.type_into() { |
| serialize_into(params, type_into) |
| } else { |
| match &cont.data { |
| Data::Enum(variants) => serialize_enum(params, variants, &cont.attrs), |
| Data::Struct(Style::Struct, fields) => serialize_struct(params, fields, &cont.attrs), |
| Data::Struct(Style::Tuple, fields) => { |
| serialize_tuple_struct(params, fields, &cont.attrs) |
| } |
| Data::Struct(Style::Newtype, fields) => { |
| serialize_newtype_struct(params, &fields[0], &cont.attrs) |
| } |
| Data::Struct(Style::Unit, _) => serialize_unit_struct(&cont.attrs), |
| } |
| } |
| } |
| |
| fn serialize_transparent(cont: &Container, params: &Parameters) -> Fragment { |
| let fields = match &cont.data { |
| Data::Struct(_, fields) => fields, |
| Data::Enum(_) => unreachable!(), |
| }; |
| |
| let self_var = ¶ms.self_var; |
| let transparent_field = fields.iter().find(|f| f.attrs.transparent()).unwrap(); |
| let member = &transparent_field.member; |
| |
| let path = match transparent_field.attrs.serialize_with() { |
| Some(path) => quote!(#path), |
| None => { |
| let span = transparent_field.original.span(); |
| quote_spanned!(span=> _serde::Serialize::serialize) |
| } |
| }; |
| |
| quote_block! { |
| #path(&#self_var.#member, __serializer) |
| } |
| } |
| |
| fn serialize_into(params: &Parameters, type_into: &syn::Type) -> Fragment { |
| let self_var = ¶ms.self_var; |
| quote_block! { |
| _serde::Serialize::serialize( |
| &_serde::__private::Into::<#type_into>::into(_serde::__private::Clone::clone(#self_var)), |
| __serializer) |
| } |
| } |
| |
| fn serialize_unit_struct(cattrs: &attr::Container) -> Fragment { |
| let type_name = cattrs.name().serialize_name(); |
| |
| quote_expr! { |
| _serde::Serializer::serialize_unit_struct(__serializer, #type_name) |
| } |
| } |
| |
| fn serialize_newtype_struct( |
| params: &Parameters, |
| field: &Field, |
| cattrs: &attr::Container, |
| ) -> Fragment { |
| let type_name = cattrs.name().serialize_name(); |
| |
| let mut field_expr = get_member( |
| params, |
| field, |
| &Member::Unnamed(Index { |
| index: 0, |
| span: Span::call_site(), |
| }), |
| ); |
| if let Some(path) = field.attrs.serialize_with() { |
| field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); |
| } |
| |
| let span = field.original.span(); |
| let func = quote_spanned!(span=> _serde::Serializer::serialize_newtype_struct); |
| quote_expr! { |
| #func(__serializer, #type_name, #field_expr) |
| } |
| } |
| |
| fn serialize_tuple_struct( |
| params: &Parameters, |
| fields: &[Field], |
| cattrs: &attr::Container, |
| ) -> Fragment { |
| let serialize_stmts = |
| serialize_tuple_struct_visitor(fields, params, false, &TupleTrait::SerializeTupleStruct); |
| |
| let type_name = cattrs.name().serialize_name(); |
| |
| let mut serialized_fields = fields |
| .iter() |
| .enumerate() |
| .filter(|(_, 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)); |
| #(#serialize_stmts)* |
| _serde::ser::SerializeTupleStruct::end(__serde_state) |
| } |
| } |
| |
| fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment { |
| assert!(fields.len() as u64 <= u64::from(u32::max_value())); |
| |
| if cattrs.has_flatten() { |
| serialize_struct_as_map(params, fields, cattrs) |
| } else { |
| serialize_struct_as_struct(params, fields, cattrs) |
| } |
| } |
| |
| fn serialize_struct_tag_field(cattrs: &attr::Container, struct_trait: &StructTrait) -> TokenStream { |
| match cattrs.tag() { |
| attr::TagType::Internal { tag } => { |
| let type_name = cattrs.name().serialize_name(); |
| let func = struct_trait.serialize_field(Span::call_site()); |
| quote! { |
| try!(#func(&mut __serde_state, #tag, #type_name)); |
| } |
| } |
| _ => quote! {}, |
| } |
| } |
| |
| fn serialize_struct_as_struct( |
| params: &Parameters, |
| fields: &[Field], |
| cattrs: &attr::Container, |
| ) -> Fragment { |
| let serialize_fields = |
| serialize_struct_visitor(fields, params, false, &StructTrait::SerializeStruct); |
| |
| let type_name = cattrs.name().serialize_name(); |
| |
| let tag_field = serialize_struct_tag_field(cattrs, &StructTrait::SerializeStruct); |
| let tag_field_exists = !tag_field.is_empty(); |
| |
| let mut serialized_fields = fields |
| .iter() |
| .filter(|&field| !field.attrs.skip_serializing()) |
| .peekable(); |
| |
| let let_mut = mut_if(serialized_fields.peek().is_some() || tag_field_exists); |
| |
| let len = serialized_fields |
| .map(|field| match field.attrs.skip_serializing_if() { |
| None => quote!(1), |
| Some(path) => { |
| let field_expr = get_member(params, field, &field.member); |
| quote!(if #path(#field_expr) { 0 } else { 1 }) |
| } |
| }) |
| .fold( |
| quote!(#tag_field_exists as usize), |
| |sum, expr| quote!(#sum + #expr), |
| ); |
| |
| quote_block! { |
| let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct(__serializer, #type_name, #len)); |
| #tag_field |
| #(#serialize_fields)* |
| _serde::ser::SerializeStruct::end(__serde_state) |
| } |
| } |
| |
| fn serialize_struct_as_map( |
| params: &Parameters, |
| fields: &[Field], |
| cattrs: &attr::Container, |
| ) -> Fragment { |
| let serialize_fields = |
| serialize_struct_visitor(fields, params, false, &StructTrait::SerializeMap); |
| |
| let tag_field = serialize_struct_tag_field(cattrs, &StructTrait::SerializeMap); |
| let tag_field_exists = !tag_field.is_empty(); |
| |
| let mut serialized_fields = fields |
| .iter() |
| .filter(|&field| !field.attrs.skip_serializing()) |
| .peekable(); |
| |
| let let_mut = mut_if(serialized_fields.peek().is_some() || tag_field_exists); |
| |
| let len = if cattrs.has_flatten() { |
| quote!(_serde::__private::None) |
| } else { |
| let len = serialized_fields |
| .map(|field| match field.attrs.skip_serializing_if() { |
| None => quote!(1), |
| Some(path) => { |
| let field_expr = get_member(params, field, &field.member); |
| quote!(if #path(#field_expr) { 0 } else { 1 }) |
| } |
| }) |
| .fold( |
| quote!(#tag_field_exists as usize), |
| |sum, expr| quote!(#sum + #expr), |
| ); |
| quote!(_serde::__private::Some(#len)) |
| }; |
| |
| quote_block! { |
| let #let_mut __serde_state = try!(_serde::Serializer::serialize_map(__serializer, #len)); |
| #tag_field |
| #(#serialize_fields)* |
| _serde::ser::SerializeMap::end(__serde_state) |
| } |
| } |
| |
| fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Container) -> Fragment { |
| assert!(variants.len() as u64 <= u64::from(u32::max_value())); |
| |
| let self_var = ¶ms.self_var; |
| |
| let arms: Vec<_> = variants |
| .iter() |
| .enumerate() |
| .map(|(variant_index, variant)| { |
| serialize_variant(params, variant, variant_index as u32, cattrs) |
| }) |
| .collect(); |
| |
| quote_expr! { |
| match *#self_var { |
| #(#arms)* |
| } |
| } |
| } |
| |
| fn serialize_variant( |
| params: &Parameters, |
| variant: &Variant, |
| variant_index: u32, |
| cattrs: &attr::Container, |
| ) -> TokenStream { |
| let this = ¶ms.this; |
| let variant_ident = &variant.ident; |
| |
| if variant.attrs.skip_serializing() { |
| let skipped_msg = format!( |
| "the enum variant {}::{} cannot be serialized", |
| params.type_name(), |
| variant_ident |
| ); |
| let skipped_err = quote! { |
| _serde::__private::Err(_serde::ser::Error::custom(#skipped_msg)) |
| }; |
| let fields_pat = match variant.style { |
| Style::Unit => quote!(), |
| Style::Newtype | Style::Tuple => quote!((..)), |
| Style::Struct => quote!({ .. }), |
| }; |
| quote! { |
| #this::#variant_ident #fields_pat => #skipped_err, |
| } |
| } else { |
| // variant wasn't skipped |
| let case = match variant.style { |
| Style::Unit => { |
| quote! { |
| #this::#variant_ident |
| } |
| } |
| Style::Newtype => { |
| quote! { |
| #this::#variant_ident(ref __field0) |
| } |
| } |
| Style::Tuple => { |
| let field_names = (0..variant.fields.len()) |
| .map(|i| Ident::new(&format!("__field{}", i), Span::call_site())); |
| quote! { |
| #this::#variant_ident(#(ref #field_names),*) |
| } |
| } |
| Style::Struct => { |
| let members = variant.fields.iter().map(|f| &f.member); |
| quote! { |
| #this::#variant_ident { #(ref #members),* } |
| } |
| } |
| }; |
| |
| let body = Match(match cattrs.tag() { |
| attr::TagType::External => { |
| serialize_externally_tagged_variant(params, variant, variant_index, cattrs) |
| } |
| attr::TagType::Internal { tag } => { |
| serialize_internally_tagged_variant(params, variant, cattrs, tag) |
| } |
| attr::TagType::Adjacent { tag, content } => { |
| serialize_adjacently_tagged_variant(params, variant, cattrs, tag, content) |
| } |
| attr::TagType::None => serialize_untagged_variant(params, variant, cattrs), |
| }); |
| |
| quote! { |
| #case => #body |
| } |
| } |
| } |
| |
| fn serialize_externally_tagged_variant( |
| params: &Parameters, |
| variant: &Variant, |
| variant_index: u32, |
| cattrs: &attr::Container, |
| ) -> Fragment { |
| let type_name = cattrs.name().serialize_name(); |
| let variant_name = variant.attrs.name().serialize_name(); |
| |
| if let Some(path) = variant.attrs.serialize_with() { |
| let ser = wrap_serialize_variant_with(params, path, variant); |
| return quote_expr! { |
| _serde::Serializer::serialize_newtype_variant( |
| __serializer, |
| #type_name, |
| #variant_index, |
| #variant_name, |
| #ser, |
| ) |
| }; |
| } |
| |
| match effective_style(variant) { |
| Style::Unit => { |
| quote_expr! { |
| _serde::Serializer::serialize_unit_variant( |
| __serializer, |
| #type_name, |
| #variant_index, |
| #variant_name, |
| ) |
| } |
| } |
| Style::Newtype => { |
| let field = &variant.fields[0]; |
| let mut field_expr = quote!(__field0); |
| if let Some(path) = field.attrs.serialize_with() { |
| field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); |
| } |
| |
| let span = field.original.span(); |
| let func = quote_spanned!(span=> _serde::Serializer::serialize_newtype_variant); |
| quote_expr! { |
| #func( |
| __serializer, |
| #type_name, |
| #variant_index, |
| #variant_name, |
| #field_expr, |
| ) |
| } |
| } |
| Style::Tuple => serialize_tuple_variant( |
| TupleVariant::ExternallyTagged { |
| type_name, |
| variant_index, |
| variant_name, |
| }, |
| params, |
| &variant.fields, |
| ), |
| Style::Struct => serialize_struct_variant( |
| StructVariant::ExternallyTagged { |
| variant_index, |
| variant_name, |
| }, |
| params, |
| &variant.fields, |
| &type_name, |
| ), |
| } |
| } |
| |
| fn serialize_internally_tagged_variant( |
| params: &Parameters, |
| variant: &Variant, |
| cattrs: &attr::Container, |
| tag: &str, |
| ) -> Fragment { |
| let type_name = cattrs.name().serialize_name(); |
| let variant_name = variant.attrs.name().serialize_name(); |
| |
| let enum_ident_str = params.type_name(); |
| let variant_ident_str = variant.ident.to_string(); |
| |
| if let Some(path) = variant.attrs.serialize_with() { |
| let ser = wrap_serialize_variant_with(params, path, variant); |
| return quote_expr! { |
| _serde::__private::ser::serialize_tagged_newtype( |
| __serializer, |
| #enum_ident_str, |
| #variant_ident_str, |
| #tag, |
| #variant_name, |
| #ser, |
| ) |
| }; |
| } |
| |
| match effective_style(variant) { |
| Style::Unit => { |
| quote_block! { |
| let mut __struct = try!(_serde::Serializer::serialize_struct( |
| __serializer, #type_name, 1)); |
| try!(_serde::ser::SerializeStruct::serialize_field( |
| &mut __struct, #tag, #variant_name)); |
| _serde::ser::SerializeStruct::end(__struct) |
| } |
| } |
| Style::Newtype => { |
| let field = &variant.fields[0]; |
| let mut field_expr = quote!(__field0); |
| if let Some(path) = field.attrs.serialize_with() { |
| field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); |
| } |
| |
| let span = field.original.span(); |
| let func = quote_spanned!(span=> _serde::__private::ser::serialize_tagged_newtype); |
| quote_expr! { |
| #func( |
| __serializer, |
| #enum_ident_str, |
| #variant_ident_str, |
| #tag, |
| #variant_name, |
| #field_expr, |
| ) |
| } |
| } |
| Style::Struct => serialize_struct_variant( |
| StructVariant::InternallyTagged { tag, variant_name }, |
| params, |
| &variant.fields, |
| &type_name, |
| ), |
| Style::Tuple => unreachable!("checked in serde_derive_internals"), |
| } |
| } |
| |
| fn serialize_adjacently_tagged_variant( |
| params: &Parameters, |
| variant: &Variant, |
| cattrs: &attr::Container, |
| tag: &str, |
| content: &str, |
| ) -> Fragment { |
| let this = ¶ms.this; |
| let type_name = cattrs.name().serialize_name(); |
| let variant_name = variant.attrs.name().serialize_name(); |
| |
| let inner = Stmts(if let Some(path) = variant.attrs.serialize_with() { |
| let ser = wrap_serialize_variant_with(params, path, variant); |
| quote_expr! { |
| _serde::Serialize::serialize(#ser, __serializer) |
| } |
| } else { |
| match effective_style(variant) { |
| Style::Unit => { |
| return quote_block! { |
| let mut __struct = try!(_serde::Serializer::serialize_struct( |
| __serializer, #type_name, 1)); |
| try!(_serde::ser::SerializeStruct::serialize_field( |
| &mut __struct, #tag, #variant_name)); |
| _serde::ser::SerializeStruct::end(__struct) |
| }; |
| } |
| Style::Newtype => { |
| let field = &variant.fields[0]; |
| let mut field_expr = quote!(__field0); |
| if let Some(path) = field.attrs.serialize_with() { |
| field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); |
| } |
| |
| let span = field.original.span(); |
| let func = quote_spanned!(span=> _serde::ser::SerializeStruct::serialize_field); |
| return quote_block! { |
| let mut __struct = try!(_serde::Serializer::serialize_struct( |
| __serializer, #type_name, 2)); |
| try!(_serde::ser::SerializeStruct::serialize_field( |
| &mut __struct, #tag, #variant_name)); |
| try!(#func( |
| &mut __struct, #content, #field_expr)); |
| _serde::ser::SerializeStruct::end(__struct) |
| }; |
| } |
| Style::Tuple => { |
| serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields) |
| } |
| Style::Struct => serialize_struct_variant( |
| StructVariant::Untagged, |
| params, |
| &variant.fields, |
| &variant_name, |
| ), |
| } |
| }); |
| |
| let fields_ty = variant.fields.iter().map(|f| &f.ty); |
| let fields_ident: &Vec<_> = &match variant.style { |
| Style::Unit => { |
| if variant.attrs.serialize_with().is_some() { |
| vec![] |
| } else { |
| unreachable!() |
| } |
| } |
| Style::Newtype => vec![Member::Named(Ident::new("__field0", Span::call_site()))], |
| Style::Tuple => (0..variant.fields.len()) |
| .map(|i| Member::Named(Ident::new(&format!("__field{}", i), Span::call_site()))) |
| .collect(), |
| Style::Struct => variant.fields.iter().map(|f| f.member.clone()).collect(), |
| }; |
| |
| let (_, ty_generics, where_clause) = params.generics.split_for_impl(); |
| |
| let wrapper_generics = if fields_ident.is_empty() { |
| params.generics.clone() |
| } else { |
| bound::with_lifetime_bound(¶ms.generics, "'__a") |
| }; |
| let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl(); |
| |
| quote_block! { |
| struct __AdjacentlyTagged #wrapper_generics #where_clause { |
| data: (#(&'__a #fields_ty,)*), |
| phantom: _serde::__private::PhantomData<#this #ty_generics>, |
| } |
| |
| impl #wrapper_impl_generics _serde::Serialize for __AdjacentlyTagged #wrapper_ty_generics #where_clause { |
| fn serialize<__S>(&self, __serializer: __S) -> _serde::__private::Result<__S::Ok, __S::Error> |
| where |
| __S: _serde::Serializer, |
| { |
| // Elements that have skip_serializing will be unused. |
| #[allow(unused_variables)] |
| let (#(#fields_ident,)*) = self.data; |
| #inner |
| } |
| } |
| |
| let mut __struct = try!(_serde::Serializer::serialize_struct( |
| __serializer, #type_name, 2)); |
| try!(_serde::ser::SerializeStruct::serialize_field( |
| &mut __struct, #tag, #variant_name)); |
| try!(_serde::ser::SerializeStruct::serialize_field( |
| &mut __struct, #content, &__AdjacentlyTagged { |
| data: (#(#fields_ident,)*), |
| phantom: _serde::__private::PhantomData::<#this #ty_generics>, |
| })); |
| _serde::ser::SerializeStruct::end(__struct) |
| } |
| } |
| |
| fn serialize_untagged_variant( |
| params: &Parameters, |
| variant: &Variant, |
| cattrs: &attr::Container, |
| ) -> Fragment { |
| if let Some(path) = variant.attrs.serialize_with() { |
| let ser = wrap_serialize_variant_with(params, path, variant); |
| return quote_expr! { |
| _serde::Serialize::serialize(#ser, __serializer) |
| }; |
| } |
| |
| match effective_style(variant) { |
| Style::Unit => { |
| quote_expr! { |
| _serde::Serializer::serialize_unit(__serializer) |
| } |
| } |
| Style::Newtype => { |
| let field = &variant.fields[0]; |
| let mut field_expr = quote!(__field0); |
| if let Some(path) = field.attrs.serialize_with() { |
| field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); |
| } |
| |
| let span = field.original.span(); |
| let func = quote_spanned!(span=> _serde::Serialize::serialize); |
| quote_expr! { |
| #func(#field_expr, __serializer) |
| } |
| } |
| Style::Tuple => serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields), |
| Style::Struct => { |
| let type_name = cattrs.name().serialize_name(); |
| serialize_struct_variant(StructVariant::Untagged, params, &variant.fields, &type_name) |
| } |
| } |
| } |
| |
| enum TupleVariant { |
| ExternallyTagged { |
| type_name: String, |
| variant_index: u32, |
| variant_name: String, |
| }, |
| Untagged, |
| } |
| |
| fn serialize_tuple_variant( |
| context: TupleVariant, |
| params: &Parameters, |
| fields: &[Field], |
| ) -> Fragment { |
| let tuple_trait = match context { |
| TupleVariant::ExternallyTagged { .. } => TupleTrait::SerializeTupleVariant, |
| TupleVariant::Untagged => TupleTrait::SerializeTuple, |
| }; |
| |
| let serialize_stmts = serialize_tuple_struct_visitor(fields, params, true, &tuple_trait); |
| |
| let mut serialized_fields = fields |
| .iter() |
| .enumerate() |
| .filter(|(_, 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 { |
| type_name, |
| variant_index, |
| variant_name, |
| } => { |
| quote_block! { |
| let #let_mut __serde_state = try!(_serde::Serializer::serialize_tuple_variant( |
| __serializer, |
| #type_name, |
| #variant_index, |
| #variant_name, |
| #len)); |
| #(#serialize_stmts)* |
| _serde::ser::SerializeTupleVariant::end(__serde_state) |
| } |
| } |
| TupleVariant::Untagged => { |
| quote_block! { |
| let #let_mut __serde_state = try!(_serde::Serializer::serialize_tuple( |
| __serializer, |
| #len)); |
| #(#serialize_stmts)* |
| _serde::ser::SerializeTuple::end(__serde_state) |
| } |
| } |
| } |
| } |
| |
| enum StructVariant<'a> { |
| ExternallyTagged { |
| variant_index: u32, |
| variant_name: String, |
| }, |
| InternallyTagged { |
| tag: &'a str, |
| variant_name: String, |
| }, |
| Untagged, |
| } |
| |
| fn serialize_struct_variant<'a>( |
| context: StructVariant<'a>, |
| params: &Parameters, |
| 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 => { |
| StructTrait::SerializeStruct |
| } |
| }; |
| |
| 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()); |
| |
| let len = serialized_fields |
| .map(|field| { |
| let member = &field.member; |
| |
| match field.attrs.skip_serializing_if() { |
| Some(path) => quote!(if #path(#member) { 0 } else { 1 }), |
| None => quote!(1), |
| } |
| }) |
| .fold(quote!(0), |sum, expr| quote!(#sum + #expr)); |
| |
| match context { |
| StructVariant::ExternallyTagged { |
| variant_index, |
| variant_name, |
| } => { |
| quote_block! { |
| let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct_variant( |
| __serializer, |
| #name, |
| #variant_index, |
| #variant_name, |
| #len, |
| )); |
| #(#serialize_fields)* |
| _serde::ser::SerializeStructVariant::end(__serde_state) |
| } |
| } |
| StructVariant::InternallyTagged { tag, variant_name } => { |
| quote_block! { |
| let mut __serde_state = try!(_serde::Serializer::serialize_struct( |
| __serializer, |
| #name, |
| #len + 1, |
| )); |
| try!(_serde::ser::SerializeStruct::serialize_field( |
| &mut __serde_state, |
| #tag, |
| #variant_name, |
| )); |
| #(#serialize_fields)* |
| _serde::ser::SerializeStruct::end(__serde_state) |
| } |
| } |
| StructVariant::Untagged => { |
| quote_block! { |
| let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct( |
| __serializer, |
| #name, |
| #len, |
| )); |
| #(#serialize_fields)* |
| _serde::ser::SerializeStruct::end(__serde_state) |
| } |
| } |
| } |
| } |
| |
| 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 members = &fields.iter().map(|f| &f.member).collect::<Vec<_>>(); |
| |
| 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::__private::PhantomData<#this #ty_generics>, |
| } |
| |
| impl #wrapper_impl_generics _serde::Serialize for __EnumFlatten #wrapper_ty_generics #where_clause { |
| fn serialize<__S>(&self, __serializer: __S) -> _serde::__private::Result<__S::Ok, __S::Error> |
| where |
| __S: _serde::Serializer, |
| { |
| let (#(#members,)*) = self.data; |
| let #let_mut __serde_state = try!(_serde::Serializer::serialize_map( |
| __serializer, |
| _serde::__private::None)); |
| #(#serialize_fields)* |
| _serde::ser::SerializeMap::end(__serde_state) |
| } |
| } |
| |
| _serde::Serializer::serialize_newtype_variant( |
| __serializer, |
| #name, |
| #variant_index, |
| #variant_name, |
| &__EnumFlatten { |
| data: (#(#members,)*), |
| phantom: _serde::__private::PhantomData::<#this #ty_generics>, |
| }) |
| } |
| } |
| StructVariant::InternallyTagged { tag, variant_name } => { |
| quote_block! { |
| let #let_mut __serde_state = try!(_serde::Serializer::serialize_map( |
| __serializer, |
| _serde::__private::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::__private::None)); |
| #(#serialize_fields)* |
| _serde::ser::SerializeMap::end(__serde_state) |
| } |
| } |
| } |
| } |
| |
| fn serialize_tuple_struct_visitor( |
| fields: &[Field], |
| params: &Parameters, |
| is_enum: bool, |
| tuple_trait: &TupleTrait, |
| ) -> Vec<TokenStream> { |
| fields |
| .iter() |
| .enumerate() |
| .filter(|(_, field)| !field.attrs.skip_serializing()) |
| .map(|(i, field)| { |
| let mut field_expr = if is_enum { |
| let id = Ident::new(&format!("__field{}", i), Span::call_site()); |
| quote!(#id) |
| } else { |
| get_member( |
| params, |
| field, |
| &Member::Unnamed(Index { |
| index: i as u32, |
| span: Span::call_site(), |
| }), |
| ) |
| }; |
| |
| let skip = field |
| .attrs |
| .skip_serializing_if() |
| .map(|path| quote!(#path(#field_expr))); |
| |
| if let Some(path) = field.attrs.serialize_with() { |
| field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); |
| } |
| |
| let span = field.original.span(); |
| let func = tuple_trait.serialize_element(span); |
| let ser = quote! { |
| try!(#func(&mut __serde_state, #field_expr)); |
| }; |
| |
| match skip { |
| None => ser, |
| Some(skip) => quote!(if !#skip { #ser }), |
| } |
| }) |
| .collect() |
| } |
| |
| fn serialize_struct_visitor( |
| fields: &[Field], |
| params: &Parameters, |
| is_enum: bool, |
| struct_trait: &StructTrait, |
| ) -> Vec<TokenStream> { |
| fields |
| .iter() |
| .filter(|&field| !field.attrs.skip_serializing()) |
| .map(|field| { |
| let member = &field.member; |
| |
| let mut field_expr = if is_enum { |
| quote!(#member) |
| } else { |
| get_member(params, field, member) |
| }; |
| |
| let key_expr = field.attrs.name().serialize_name(); |
| |
| let skip = field |
| .attrs |
| .skip_serializing_if() |
| .map(|path| quote!(#path(#field_expr))); |
| |
| if let Some(path) = field.attrs.serialize_with() { |
| field_expr = wrap_serialize_field_with(params, field.ty, path, &field_expr); |
| } |
| |
| let span = field.original.span(); |
| let ser = if field.attrs.flatten() { |
| let func = quote_spanned!(span=> _serde::Serialize::serialize); |
| quote! { |
| try!(#func(&#field_expr, _serde::__private::ser::FlatMapSerializer(&mut __serde_state))); |
| } |
| } else { |
| let func = struct_trait.serialize_field(span); |
| quote! { |
| try!(#func(&mut __serde_state, #key_expr, #field_expr)); |
| } |
| }; |
| |
| match skip { |
| None => ser, |
| Some(skip) => { |
| if let Some(skip_func) = struct_trait.skip_field(span) { |
| quote! { |
| if !#skip { |
| #ser |
| } else { |
| try!(#skip_func(&mut __serde_state, #key_expr)); |
| } |
| } |
| } else { |
| quote! { |
| if !#skip { |
| #ser |
| } |
| } |
| } |
| } |
| } |
| }) |
| .collect() |
| } |
| |
| fn wrap_serialize_field_with( |
| params: &Parameters, |
| field_ty: &syn::Type, |
| serialize_with: &syn::ExprPath, |
| field_expr: &TokenStream, |
| ) -> TokenStream { |
| wrap_serialize_with(params, serialize_with, &[field_ty], &[quote!(#field_expr)]) |
| } |
| |
| fn wrap_serialize_variant_with( |
| params: &Parameters, |
| serialize_with: &syn::ExprPath, |
| variant: &Variant, |
| ) -> TokenStream { |
| let field_tys: Vec<_> = variant.fields.iter().map(|field| field.ty).collect(); |
| let field_exprs: Vec<_> = variant |
| .fields |
| .iter() |
| .map(|field| { |
| let id = match &field.member { |
| Member::Named(ident) => ident.clone(), |
| Member::Unnamed(member) => { |
| Ident::new(&format!("__field{}", member.index), Span::call_site()) |
| } |
| }; |
| quote!(#id) |
| }) |
| .collect(); |
| wrap_serialize_with( |
| params, |
| serialize_with, |
| field_tys.as_slice(), |
| field_exprs.as_slice(), |
| ) |
| } |
| |
| fn wrap_serialize_with( |
| params: &Parameters, |
| serialize_with: &syn::ExprPath, |
| field_tys: &[&syn::Type], |
| field_exprs: &[TokenStream], |
| ) -> TokenStream { |
| let this = ¶ms.this; |
| let (_, ty_generics, where_clause) = params.generics.split_for_impl(); |
| |
| let wrapper_generics = if field_exprs.is_empty() { |
| params.generics.clone() |
| } else { |
| bound::with_lifetime_bound(¶ms.generics, "'__a") |
| }; |
| let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl(); |
| |
| let field_access = (0..field_exprs.len()).map(|n| { |
| Member::Unnamed(Index { |
| index: n as u32, |
| span: Span::call_site(), |
| }) |
| }); |
| |
| quote!({ |
| struct __SerializeWith #wrapper_impl_generics #where_clause { |
| values: (#(&'__a #field_tys, )*), |
| phantom: _serde::__private::PhantomData<#this #ty_generics>, |
| } |
| |
| impl #wrapper_impl_generics _serde::Serialize for __SerializeWith #wrapper_ty_generics #where_clause { |
| fn serialize<__S>(&self, __s: __S) -> _serde::__private::Result<__S::Ok, __S::Error> |
| where |
| __S: _serde::Serializer, |
| { |
| #serialize_with(#(self.values.#field_access, )* __s) |
| } |
| } |
| |
| &__SerializeWith { |
| values: (#(#field_exprs, )*), |
| phantom: _serde::__private::PhantomData::<#this #ty_generics>, |
| } |
| }) |
| } |
| |
| // Serialization of an empty struct results in code like: |
| // |
| // let mut __serde_state = try!(serializer.serialize_struct("S", 0)); |
| // _serde::ser::SerializeStruct::end(__serde_state) |
| // |
| // where we want to omit the `mut` to avoid a warning. |
| fn mut_if(is_mut: bool) -> Option<TokenStream> { |
| if is_mut { |
| Some(quote!(mut)) |
| } else { |
| None |
| } |
| } |
| |
| fn get_member(params: &Parameters, field: &Field, member: &Member) -> TokenStream { |
| let self_var = ¶ms.self_var; |
| match (params.is_remote, field.attrs.getter()) { |
| (false, None) => { |
| if params.is_packed { |
| quote!(&{#self_var.#member}) |
| } else { |
| quote!(&#self_var.#member) |
| } |
| } |
| (true, None) => { |
| let inner = if params.is_packed { |
| quote!(&{#self_var.#member}) |
| } else { |
| quote!(&#self_var.#member) |
| }; |
| let ty = field.ty; |
| quote!(_serde::__private::ser::constrain::<#ty>(#inner)) |
| } |
| (true, Some(getter)) => { |
| let ty = field.ty; |
| quote!(_serde::__private::ser::constrain::<#ty>(&#getter(#self_var))) |
| } |
| (false, Some(_)) => { |
| unreachable!("getter is only allowed for remote impls"); |
| } |
| } |
| } |
| |
| fn effective_style(variant: &Variant) -> Style { |
| match variant.style { |
| Style::Newtype if variant.fields[0].attrs.skip_serializing() => Style::Unit, |
| other => other, |
| } |
| } |
| |
| enum StructTrait { |
| SerializeMap, |
| SerializeStruct, |
| SerializeStructVariant, |
| } |
| |
| impl StructTrait { |
| fn serialize_field(&self, span: Span) -> TokenStream { |
| match *self { |
| StructTrait::SerializeMap => { |
| quote_spanned!(span=> _serde::ser::SerializeMap::serialize_entry) |
| } |
| StructTrait::SerializeStruct => { |
| quote_spanned!(span=> _serde::ser::SerializeStruct::serialize_field) |
| } |
| StructTrait::SerializeStructVariant => { |
| quote_spanned!(span=> _serde::ser::SerializeStructVariant::serialize_field) |
| } |
| } |
| } |
| |
| fn skip_field(&self, span: Span) -> Option<TokenStream> { |
| match *self { |
| StructTrait::SerializeMap => None, |
| StructTrait::SerializeStruct => { |
| Some(quote_spanned!(span=> _serde::ser::SerializeStruct::skip_field)) |
| } |
| StructTrait::SerializeStructVariant => { |
| Some(quote_spanned!(span=> _serde::ser::SerializeStructVariant::skip_field)) |
| } |
| } |
| } |
| } |
| |
| enum TupleTrait { |
| SerializeTuple, |
| SerializeTupleStruct, |
| SerializeTupleVariant, |
| } |
| |
| impl TupleTrait { |
| fn serialize_element(&self, span: Span) -> TokenStream { |
| match *self { |
| TupleTrait::SerializeTuple => { |
| quote_spanned!(span=> _serde::ser::SerializeTuple::serialize_element) |
| } |
| TupleTrait::SerializeTupleStruct => { |
| quote_spanned!(span=> _serde::ser::SerializeTupleStruct::serialize_field) |
| } |
| TupleTrait::SerializeTupleVariant => { |
| quote_spanned!(span=> _serde::ser::SerializeTupleVariant::serialize_field) |
| } |
| } |
| } |
| } |