Files
serde/serde_derive/src/ser.rs
T
David Tolnay dd1f4b483e Make it clearer that the private implementation details are private
Both of these modules are doc(hidden) and commented "Not public API",
but incorrect downstream code sometimes still references them. Naming
the module __private will make it more likely to be noticed in code
review.
2021-01-08 19:55:31 -08:00

1335 lines
43 KiB
Rust

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, Ctxt, Derive};
use pretend;
pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<TokenStream, Vec<syn::Error>> {
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, &params));
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);
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 = &params.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 = &params.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 = &params.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 = &params.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 = &params.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(&params.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 = &params.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(&params.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 = &params.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(&params.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 = &params.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)
}
}
}
}