Added support for serialization of structs as maps
This commit is contained in:
parent
5a91ac5ba5
commit
b4dbae250b
@ -245,6 +245,13 @@ fn serialize_tuple_struct(
|
||||
fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment {
|
||||
assert!(fields.len() as u64 <= u64::from(u32::MAX));
|
||||
|
||||
match cattrs.repr() {
|
||||
attr::ContainerRepr::Struct | attr::ContainerRepr::Auto => serialize_struct_as_struct(params, fields, cattrs),
|
||||
attr::ContainerRepr::Map => serialize_struct_as_map(params, fields, cattrs),
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_struct_as_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment {
|
||||
let serialize_fields = serialize_struct_visitor(
|
||||
fields,
|
||||
params,
|
||||
@ -279,6 +286,64 @@ fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Contai
|
||||
}
|
||||
}
|
||||
|
||||
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 mut serialized_fields = fields
|
||||
.iter()
|
||||
.filter(|&field| !field.attrs.skip_serializing())
|
||||
.peekable();
|
||||
|
||||
let mut collect_extra = None;
|
||||
if cattrs.unknown_fields_into().is_some() {
|
||||
if let Some(field) = fields
|
||||
.iter()
|
||||
.filter(|field| field.attrs.collection_field())
|
||||
.next()
|
||||
{
|
||||
let ident = &field.ident;
|
||||
collect_extra = Some(quote! {
|
||||
for (ref __key, ref __value) in &self.#ident {
|
||||
try!(_serde::ser::SerializeMap::serialize_entry(
|
||||
&mut __serde_state,
|
||||
__key,
|
||||
__value));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let let_mut = mut_if(serialized_fields.peek().is_some());
|
||||
|
||||
let len = if collect_extra.is_some() {
|
||||
quote!(None)
|
||||
} else {
|
||||
let len = serialized_fields
|
||||
.map(|field| match field.attrs.skip_serializing_if() {
|
||||
None => quote!(1),
|
||||
Some(path) => {
|
||||
let ident = field.ident.expect("struct has unnamed fields");
|
||||
let field_expr = get_member(params, field, &Member::Named(ident));
|
||||
quote!(if #path(#field_expr) { 0 } else { 1 })
|
||||
}
|
||||
})
|
||||
.fold(quote!(0), |sum, expr| quote!(#sum + #expr));
|
||||
quote!(Some(#len))
|
||||
};
|
||||
|
||||
quote_block! {
|
||||
let #let_mut __serde_state = try!(_serde::Serializer::serialize_map(__serializer, #len));
|
||||
#(#serialize_fields)*
|
||||
#collect_extra
|
||||
_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));
|
||||
|
||||
@ -885,12 +950,19 @@ fn serialize_struct_visitor(
|
||||
match skip {
|
||||
None => ser,
|
||||
Some(skip) => {
|
||||
let skip_func = struct_trait.skip_field(span);
|
||||
quote! {
|
||||
if !#skip {
|
||||
#ser
|
||||
} else {
|
||||
try!(#skip_func(&mut __serde_state, #key_expr));
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1011,6 +1083,7 @@ fn get_member(params: &Parameters, field: &Field, member: &Member) -> Tokens {
|
||||
}
|
||||
|
||||
enum StructTrait {
|
||||
SerializeMap,
|
||||
SerializeStruct,
|
||||
SerializeStructVariant,
|
||||
}
|
||||
@ -1018,6 +1091,9 @@ enum StructTrait {
|
||||
impl StructTrait {
|
||||
fn serialize_field(&self, span: Span) -> Tokens {
|
||||
match *self {
|
||||
StructTrait::SerializeMap => {
|
||||
quote_spanned!(span=> _serde::ser::SerializeMap::serialize_entry)
|
||||
}
|
||||
StructTrait::SerializeStruct => {
|
||||
quote_spanned!(span=> _serde::ser::SerializeStruct::serialize_field)
|
||||
}
|
||||
@ -1027,14 +1103,15 @@ impl StructTrait {
|
||||
}
|
||||
}
|
||||
|
||||
fn skip_field(&self, span: Span) -> Tokens {
|
||||
fn skip_field(&self, span: Span) -> Option<Tokens> {
|
||||
match *self {
|
||||
StructTrait::SerializeStruct => {
|
||||
StructTrait::SerializeMap => None,
|
||||
StructTrait::SerializeStruct => Some({
|
||||
quote_spanned!(span=> _serde::ser::SerializeStruct::skip_field)
|
||||
}
|
||||
StructTrait::SerializeStructVariant => {
|
||||
}),
|
||||
StructTrait::SerializeStructVariant => Some({
|
||||
quote_spanned!(span=> _serde::ser::SerializeStructVariant::skip_field)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user