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 {
|
fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment {
|
||||||
assert!(fields.len() as u64 <= u64::from(u32::MAX));
|
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(
|
let serialize_fields = serialize_struct_visitor(
|
||||||
fields,
|
fields,
|
||||||
params,
|
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 {
|
fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Container) -> Fragment {
|
||||||
assert!(variants.len() as u64 <= u64::from(u32::MAX));
|
assert!(variants.len() as u64 <= u64::from(u32::MAX));
|
||||||
|
|
||||||
@ -885,12 +950,19 @@ fn serialize_struct_visitor(
|
|||||||
match skip {
|
match skip {
|
||||||
None => ser,
|
None => ser,
|
||||||
Some(skip) => {
|
Some(skip) => {
|
||||||
let skip_func = struct_trait.skip_field(span);
|
if let Some(skip_func) = struct_trait.skip_field(span) {
|
||||||
quote! {
|
quote! {
|
||||||
if !#skip {
|
if !#skip {
|
||||||
#ser
|
#ser
|
||||||
} else {
|
} else {
|
||||||
try!(#skip_func(&mut __serde_state, #key_expr));
|
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 {
|
enum StructTrait {
|
||||||
|
SerializeMap,
|
||||||
SerializeStruct,
|
SerializeStruct,
|
||||||
SerializeStructVariant,
|
SerializeStructVariant,
|
||||||
}
|
}
|
||||||
@ -1018,6 +1091,9 @@ enum StructTrait {
|
|||||||
impl StructTrait {
|
impl StructTrait {
|
||||||
fn serialize_field(&self, span: Span) -> Tokens {
|
fn serialize_field(&self, span: Span) -> Tokens {
|
||||||
match *self {
|
match *self {
|
||||||
|
StructTrait::SerializeMap => {
|
||||||
|
quote_spanned!(span=> _serde::ser::SerializeMap::serialize_entry)
|
||||||
|
}
|
||||||
StructTrait::SerializeStruct => {
|
StructTrait::SerializeStruct => {
|
||||||
quote_spanned!(span=> _serde::ser::SerializeStruct::serialize_field)
|
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 {
|
match *self {
|
||||||
StructTrait::SerializeStruct => {
|
StructTrait::SerializeMap => None,
|
||||||
|
StructTrait::SerializeStruct => Some({
|
||||||
quote_spanned!(span=> _serde::ser::SerializeStruct::skip_field)
|
quote_spanned!(span=> _serde::ser::SerializeStruct::skip_field)
|
||||||
}
|
}),
|
||||||
StructTrait::SerializeStructVariant => {
|
StructTrait::SerializeStructVariant => Some({
|
||||||
quote_spanned!(span=> _serde::ser::SerializeStructVariant::skip_field)
|
quote_spanned!(span=> _serde::ser::SerializeStructVariant::skip_field)
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user