mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-06-13 06:41:03 +00:00
Serialization of Haskell style enums
This commit is contained in:
@@ -110,14 +110,14 @@ pub enum EnumTag {
|
|||||||
/// ```json
|
/// ```json
|
||||||
/// {"type": "variant1", "key1": "value1", "key2": "value2"}
|
/// {"type": "variant1", "key1": "value1", "key2": "value2"}
|
||||||
/// ```
|
/// ```
|
||||||
Internal(String),
|
Internal { tag: String },
|
||||||
|
|
||||||
/// `#[serde(tag = "type", content = "name")]`
|
/// `#[serde(tag = "t", content = "c")]`
|
||||||
///
|
///
|
||||||
/// ```json
|
/// ```json
|
||||||
/// {"type": "variant1", "name": {"key1": "value1", "key2": "value2"}}
|
/// {"t": "variant1", "c": {"key1": "value1", "key2": "value2"}}
|
||||||
/// ```
|
/// ```
|
||||||
Adjacent(String, String),
|
Adjacent { tag: String, content: String },
|
||||||
|
|
||||||
/// `#[serde(untagged)]`
|
/// `#[serde(untagged)]`
|
||||||
///
|
///
|
||||||
@@ -137,7 +137,7 @@ impl Item {
|
|||||||
let mut de_bound = Attr::none(cx, "bound");
|
let mut de_bound = Attr::none(cx, "bound");
|
||||||
let mut untagged = BoolAttr::none(cx, "untagged");
|
let mut untagged = BoolAttr::none(cx, "untagged");
|
||||||
let mut internal_tag = Attr::none(cx, "tag");
|
let mut internal_tag = Attr::none(cx, "tag");
|
||||||
let mut internal_content = Attr::none(cx, "content");
|
let mut content = Attr::none(cx, "content");
|
||||||
|
|
||||||
for meta_items in item.attrs.iter().filter_map(get_serde_meta_items) {
|
for meta_items in item.attrs.iter().filter_map(get_serde_meta_items) {
|
||||||
for meta_item in meta_items {
|
for meta_item in meta_items {
|
||||||
@@ -206,15 +206,15 @@ impl Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(content = "name")]`
|
// Parse `#[serde(content = "c")]`
|
||||||
MetaItem(NameValue(ref name, ref lit)) if name == "content" => {
|
MetaItem(NameValue(ref name, ref lit)) if name == "content" => {
|
||||||
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
|
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) {
|
||||||
match item.body {
|
match item.body {
|
||||||
syn::Body::Enum(_) => {
|
syn::Body::Enum(_) => {
|
||||||
internal_content.set(s);
|
content.set(s);
|
||||||
}
|
}
|
||||||
syn::Body::Struct(_) => {
|
syn::Body::Struct(_) => {
|
||||||
cx.error("#[serde(tag = \"...\")] can only be used on enums")
|
cx.error("#[serde(content = \"...\")] can only be used on enums")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -232,7 +232,7 @@ impl Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let tag = match (untagged.get(), internal_tag.get(), internal_content.get()) {
|
let tag = match (untagged.get(), internal_tag.get(), content.get()) {
|
||||||
(false, None, None) => EnumTag::External,
|
(false, None, None) => EnumTag::External,
|
||||||
(true, None, None) => EnumTag::None,
|
(true, None, None) => EnumTag::None,
|
||||||
(false, Some(tag), None) => {
|
(false, Some(tag), None) => {
|
||||||
@@ -252,34 +252,26 @@ impl Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EnumTag::Internal(tag)
|
EnumTag::Internal { tag: tag }
|
||||||
}
|
}
|
||||||
(false, Some(tag), Some(content)) => {
|
(true, Some(_), None) => {
|
||||||
// Check that there are no struct variants.
|
|
||||||
if let syn::Body::Enum(ref variants) = item.body {
|
|
||||||
for variant in variants {
|
|
||||||
match variant.data {
|
|
||||||
syn::VariantData::Tuple(_) |
|
|
||||||
syn::VariantData::Unit => {}
|
|
||||||
syn::VariantData::Struct(ref fields) => {
|
|
||||||
if fields.len() != 1 {
|
|
||||||
cx.error("#[serde(tag = \"...\", content = \"...\")] cannot \
|
|
||||||
be used with struct variants");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EnumTag::Adjacent(tag, content)
|
|
||||||
}
|
|
||||||
(true, Some(_), _) => {
|
|
||||||
cx.error("enum cannot be both untagged and internally tagged");
|
cx.error("enum cannot be both untagged and internally tagged");
|
||||||
EnumTag::External // doesn't matter, will error
|
EnumTag::External // doesn't matter, will error
|
||||||
}
|
}
|
||||||
(_, None, Some(_)) => {
|
(false, None, Some(_)) => {
|
||||||
cx.error("#[serde(content = \"...\")] cannot be used without #[serde(tag = \"...\")]");
|
cx.error("#[serde(tag = \"...\", content = \"...\")] must be used together");
|
||||||
EnumTag::External // doesn't matter, will error
|
EnumTag::External
|
||||||
|
}
|
||||||
|
(true, None, Some(_)) => {
|
||||||
|
cx.error("untagged enum cannot have #[serde(content = \"...\")]");
|
||||||
|
EnumTag::External
|
||||||
|
}
|
||||||
|
(false, Some(tag), Some(content)) => {
|
||||||
|
EnumTag::Adjacent { tag: tag, content: content }
|
||||||
|
}
|
||||||
|
(true, Some(_), Some(_)) => {
|
||||||
|
cx.error("untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]");
|
||||||
|
EnumTag::External
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -494,7 +494,7 @@ fn deserialize_item_enum(type_ident: &syn::Ident,
|
|||||||
attr::EnumTag::External => {
|
attr::EnumTag::External => {
|
||||||
deserialize_externally_tagged_enum(type_ident, impl_generics, ty, variants, item_attrs)
|
deserialize_externally_tagged_enum(type_ident, impl_generics, ty, variants, item_attrs)
|
||||||
}
|
}
|
||||||
attr::EnumTag::Internal(ref tag) => {
|
attr::EnumTag::Internal { ref tag } => {
|
||||||
deserialize_internally_tagged_enum(type_ident,
|
deserialize_internally_tagged_enum(type_ident,
|
||||||
impl_generics,
|
impl_generics,
|
||||||
ty,
|
ty,
|
||||||
@@ -502,9 +502,7 @@ fn deserialize_item_enum(type_ident: &syn::Ident,
|
|||||||
item_attrs,
|
item_attrs,
|
||||||
tag)
|
tag)
|
||||||
}
|
}
|
||||||
attr::EnumTag::Adjacent(ref tag, ref content) => {
|
attr::EnumTag::Adjacent { .. } => unimplemented!(),
|
||||||
panic!("FIXME: unimplemented")
|
|
||||||
}
|
|
||||||
attr::EnumTag::None => {
|
attr::EnumTag::None => {
|
||||||
deserialize_untagged_enum(type_ident, impl_generics, ty, variants, item_attrs)
|
deserialize_untagged_enum(type_ident, impl_generics, ty, variants, item_attrs)
|
||||||
}
|
}
|
||||||
|
|||||||
+100
-109
@@ -230,38 +230,30 @@ fn serialize_variant(type_ident: &syn::Ident,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// variant wasn't skipped
|
// variant wasn't skipped
|
||||||
let field_values;
|
|
||||||
let case = match variant.style {
|
let case = match variant.style {
|
||||||
Style::Unit => {
|
Style::Unit => {
|
||||||
field_values = vec![];
|
|
||||||
quote! {
|
quote! {
|
||||||
#type_ident::#variant_ident
|
#type_ident::#variant_ident
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Style::Newtype => {
|
Style::Newtype => {
|
||||||
let field_name = Ident::new("__simple_value");
|
|
||||||
field_values = vec![field_name.clone()];
|
|
||||||
quote! {
|
quote! {
|
||||||
#type_ident::#variant_ident(ref #field_name)
|
#type_ident::#variant_ident(ref __simple_value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Style::Tuple => {
|
Style::Tuple => {
|
||||||
let field_names: Vec<_> = (0..variant.fields.len())
|
let field_names = (0..variant.fields.len())
|
||||||
.map(|i| Ident::new(format!("__field{}", i)))
|
.map(|i| Ident::new(format!("__field{}", i)));
|
||||||
.collect();
|
|
||||||
field_values = field_names.clone();
|
|
||||||
quote! {
|
quote! {
|
||||||
#type_ident::#variant_ident(#(ref #field_names),*)
|
#type_ident::#variant_ident(#(ref #field_names),*)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Style::Struct => {
|
Style::Struct => {
|
||||||
let field_names: Vec<_> = variant.fields
|
let fields = variant.fields
|
||||||
.iter()
|
.iter()
|
||||||
.map(|f| f.ident.clone().expect("struct variant has unnamed fields"))
|
.map(|f| f.ident.clone().expect("struct variant has unnamed fields"));
|
||||||
.collect();
|
|
||||||
field_values = field_names.clone();
|
|
||||||
quote! {
|
quote! {
|
||||||
#type_ident::#variant_ident { #(ref #field_names),* }
|
#type_ident::#variant_ident { #(ref #fields),* }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -274,7 +266,7 @@ fn serialize_variant(type_ident: &syn::Ident,
|
|||||||
variant_index,
|
variant_index,
|
||||||
item_attrs)
|
item_attrs)
|
||||||
}
|
}
|
||||||
attr::EnumTag::Internal(ref tag) => {
|
attr::EnumTag::Internal { ref tag } => {
|
||||||
serialize_internally_tagged_variant(type_ident.as_ref(),
|
serialize_internally_tagged_variant(type_ident.as_ref(),
|
||||||
variant_ident.as_ref(),
|
variant_ident.as_ref(),
|
||||||
generics,
|
generics,
|
||||||
@@ -283,14 +275,8 @@ fn serialize_variant(type_ident: &syn::Ident,
|
|||||||
item_attrs,
|
item_attrs,
|
||||||
tag)
|
tag)
|
||||||
}
|
}
|
||||||
attr::EnumTag::Adjacent(ref tag, ref content) => {
|
attr::EnumTag::Adjacent { ref tag, ref content } => {
|
||||||
serialize_adjacently_tagged_variant(generics,
|
serialize_adjacently_tagged_variant(generics, ty, variant, item_attrs, tag, content)
|
||||||
ty,
|
|
||||||
variant,
|
|
||||||
item_attrs,
|
|
||||||
&field_values,
|
|
||||||
tag,
|
|
||||||
content)
|
|
||||||
}
|
}
|
||||||
attr::EnumTag::None => serialize_untagged_variant(generics, ty, variant, item_attrs),
|
attr::EnumTag::None => serialize_untagged_variant(generics, ty, variant, item_attrs),
|
||||||
};
|
};
|
||||||
@@ -360,7 +346,7 @@ fn serialize_externally_tagged_variant(generics: &syn::Generics,
|
|||||||
generics,
|
generics,
|
||||||
ty,
|
ty,
|
||||||
&variant.fields,
|
&variant.fields,
|
||||||
item_attrs);
|
&type_name);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
{ #block }
|
{ #block }
|
||||||
@@ -416,7 +402,7 @@ fn serialize_internally_tagged_variant(type_ident: &str,
|
|||||||
generics,
|
generics,
|
||||||
ty,
|
ty,
|
||||||
&variant.fields,
|
&variant.fields,
|
||||||
item_attrs);
|
&type_name);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
{ #block }
|
{ #block }
|
||||||
@@ -430,98 +416,104 @@ fn serialize_adjacently_tagged_variant(generics: &syn::Generics,
|
|||||||
ty: syn::Ty,
|
ty: syn::Ty,
|
||||||
variant: &Variant,
|
variant: &Variant,
|
||||||
item_attrs: &attr::Item,
|
item_attrs: &attr::Item,
|
||||||
field_values: &Vec<syn::Ident>,
|
|
||||||
tag: &str,
|
tag: &str,
|
||||||
content: &str)
|
content: &str)
|
||||||
-> Tokens {
|
-> Tokens {
|
||||||
let type_name = item_attrs.name().serialize_name();
|
let type_name = item_attrs.name().serialize_name();
|
||||||
let variant_name = variant.attrs.name().serialize_name();
|
let variant_name = variant.attrs.name().serialize_name();
|
||||||
|
|
||||||
match variant.style {
|
let inner = match variant.style {
|
||||||
Style::Unit => {
|
Style::Unit => {
|
||||||
quote!({
|
return quote!({
|
||||||
let mut __struct = try!(_serde::Serializer::serialize_struct(
|
let mut __struct = try!(_serde::Serializer::serialize_struct(
|
||||||
_serializer, #type_name, 1));
|
_serializer, #type_name, 1));
|
||||||
try!(_serde::ser::SerializeStruct::serialize_field(
|
try!(_serde::ser::SerializeStruct::serialize_field(
|
||||||
&mut __struct, #tag, #variant_name));
|
&mut __struct, #tag, #variant_name));
|
||||||
_serde::ser::SerializeStruct::end(__struct)
|
_serde::ser::SerializeStruct::end(__struct)
|
||||||
})
|
});
|
||||||
|
}
|
||||||
|
Style::Newtype => {
|
||||||
|
let field = &variant.fields[0];
|
||||||
|
let mut field_expr = quote!(__simple_value);
|
||||||
|
if let Some(path) = field.attrs.serialize_with() {
|
||||||
|
field_expr = wrap_serialize_with(&ty, generics, field.ty, path, field_expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
_serde::Serialize::serialize(#field_expr, _serializer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Style::Newtype |
|
|
||||||
Style::Tuple => {
|
Style::Tuple => {
|
||||||
let define_inner = match variant.style {
|
serialize_tuple_variant(TupleVariant::Untagged,
|
||||||
Style::Unit => unreachable!("checked above"),
|
generics,
|
||||||
Style::Newtype => {
|
ty.clone(),
|
||||||
// FIXME: This doesn't handle nested newtype.
|
&variant.fields)
|
||||||
let value = field_values[0].clone();
|
|
||||||
quote!({
|
|
||||||
__inner = #value;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Style::Tuple => {
|
|
||||||
let where_clause = &generics.where_clause;
|
|
||||||
|
|
||||||
let wrapper_generics = aster::from_generics(generics.clone())
|
|
||||||
.add_lifetime_bound("'__a")
|
|
||||||
.lifetime_name("'__a")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let wrapper_ty = aster::path()
|
|
||||||
.segment("Inner")
|
|
||||||
.with_generics(wrapper_generics.clone())
|
|
||||||
.build()
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let field_count = variant.fields.len();
|
|
||||||
let field_offset = (0..field_count).map(
|
|
||||||
|i| syn::Lit::Int(i as u64, syn::IntTy::Unsuffixed));
|
|
||||||
let field_tys = variant.fields.iter().map(|f| f.ty.clone());
|
|
||||||
|
|
||||||
quote!({
|
|
||||||
// Define a tuple struct for the interior along with
|
|
||||||
// the necessary serialization logic.
|
|
||||||
struct Inner #wrapper_generics #where_clause {
|
|
||||||
data: (#(&'__a #field_tys),*),
|
|
||||||
phantom: _serde::export::PhantomData<#ty>,
|
|
||||||
};
|
|
||||||
impl #wrapper_generics _serde::ser::Serialize for #wrapper_ty #where_clause {
|
|
||||||
fn serialize<S>(&self, __inner_serializer: S) -> _serde::export::Result<S::Ok, S::Error>
|
|
||||||
where S: _serde::ser::Serializer
|
|
||||||
{
|
|
||||||
let mut __tuple = try!(_serde::ser::Serializer::serialize_tuple(
|
|
||||||
__inner_serializer, #field_count));
|
|
||||||
#(try!(_serde::ser::SerializeTuple::serialize_element(
|
|
||||||
&mut __tuple, &(self.data.#field_offset)));)*
|
|
||||||
_serde::ser::SerializeTuple::end(__tuple)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
__inner = Inner {
|
|
||||||
data: (#(#field_values),*),
|
|
||||||
phantom: _serde::export::PhantomData::<#ty>,
|
|
||||||
};
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Style::Struct => unreachable!("checked in serde_codegen_internals"),
|
|
||||||
};
|
|
||||||
|
|
||||||
quote!({
|
|
||||||
let __inner;
|
|
||||||
{ #define_inner }
|
|
||||||
|
|
||||||
// Serialize the exterior struct with tag name.
|
|
||||||
let mut __struct = try!(_serde::Serializer::serialize_struct(
|
|
||||||
_serializer, #type_name, 2));
|
|
||||||
try!(_serde::ser::SerializeStruct::serialize_field(
|
|
||||||
&mut __struct, #tag, #variant_name));
|
|
||||||
// Serialize the interior tuple.
|
|
||||||
try!(_serde::ser::SerializeStruct::serialize_field(
|
|
||||||
&mut __struct, #content, &__inner));
|
|
||||||
_serde::ser::SerializeStruct::end(__struct)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
Style::Struct => unreachable!("checked in serde_codegen_internals"),
|
Style::Struct => {
|
||||||
}
|
serialize_struct_variant(StructVariant::Untagged,
|
||||||
|
generics,
|
||||||
|
ty.clone(),
|
||||||
|
&variant.fields,
|
||||||
|
&variant_name)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let fields_ty = variant.fields.iter().map(|f| &f.ty);
|
||||||
|
let ref fields_ident: Vec<_> = match variant.style {
|
||||||
|
Style::Unit => unreachable!(),
|
||||||
|
Style::Newtype => vec![Ident::new("__simple_value")],
|
||||||
|
Style::Tuple => {
|
||||||
|
(0..variant.fields.len())
|
||||||
|
.map(|i| Ident::new(format!("__field{}", i)))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
Style::Struct => {
|
||||||
|
variant.fields
|
||||||
|
.iter()
|
||||||
|
.map(|f| f.ident.clone().expect("struct variant has unnamed fields"))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let where_clause = &generics.where_clause;
|
||||||
|
|
||||||
|
let wrapper_generics = aster::from_generics(generics.clone())
|
||||||
|
.add_lifetime_bound("'__a")
|
||||||
|
.lifetime_name("'__a")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let wrapper_ty = aster::path()
|
||||||
|
.segment("__AdjacentlyTagged")
|
||||||
|
.with_generics(wrapper_generics.clone())
|
||||||
|
.build()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
quote!({
|
||||||
|
struct __AdjacentlyTagged #wrapper_generics #where_clause {
|
||||||
|
data: (#(&'__a #fields_ty,)*),
|
||||||
|
phantom: _serde::export::PhantomData<#ty>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl #wrapper_generics _serde::Serialize for #wrapper_ty #where_clause {
|
||||||
|
fn serialize<__S>(&self, _serializer: __S) -> _serde::export::Result<__S::Ok, __S::Error>
|
||||||
|
where __S: _serde::Serializer
|
||||||
|
{
|
||||||
|
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::export::PhantomData::<#ty>,
|
||||||
|
}));
|
||||||
|
_serde::ser::SerializeStruct::end(__struct)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_untagged_variant(generics: &syn::Generics,
|
fn serialize_untagged_variant(generics: &syn::Generics,
|
||||||
@@ -555,11 +547,12 @@ fn serialize_untagged_variant(generics: &syn::Generics,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Style::Struct => {
|
Style::Struct => {
|
||||||
|
let type_name = item_attrs.name().serialize_name();
|
||||||
let block = serialize_struct_variant(StructVariant::Untagged,
|
let block = serialize_struct_variant(StructVariant::Untagged,
|
||||||
generics,
|
generics,
|
||||||
ty,
|
ty,
|
||||||
&variant.fields,
|
&variant.fields,
|
||||||
item_attrs);
|
&type_name);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
{ #block }
|
{ #block }
|
||||||
@@ -633,7 +626,7 @@ fn serialize_struct_variant<'a>(context: StructVariant<'a>,
|
|||||||
generics: &syn::Generics,
|
generics: &syn::Generics,
|
||||||
ty: syn::Ty,
|
ty: syn::Ty,
|
||||||
fields: &[Field],
|
fields: &[Field],
|
||||||
item_attrs: &attr::Item)
|
name: &str)
|
||||||
-> Tokens {
|
-> Tokens {
|
||||||
let method = match context {
|
let method = match context {
|
||||||
StructVariant::ExternallyTagged { .. } => {
|
StructVariant::ExternallyTagged { .. } => {
|
||||||
@@ -645,8 +638,6 @@ fn serialize_struct_variant<'a>(context: StructVariant<'a>,
|
|||||||
|
|
||||||
let serialize_fields = serialize_struct_visitor(ty.clone(), fields, generics, true, method);
|
let serialize_fields = serialize_struct_visitor(ty.clone(), fields, generics, true, method);
|
||||||
|
|
||||||
let item_name = item_attrs.name().serialize_name();
|
|
||||||
|
|
||||||
let mut serialized_fields = fields.iter()
|
let mut serialized_fields = fields.iter()
|
||||||
.filter(|&field| !field.attrs.skip_serializing())
|
.filter(|&field| !field.attrs.skip_serializing())
|
||||||
.peekable();
|
.peekable();
|
||||||
@@ -668,7 +659,7 @@ fn serialize_struct_variant<'a>(context: StructVariant<'a>,
|
|||||||
quote! {
|
quote! {
|
||||||
let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct_variant(
|
let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct_variant(
|
||||||
_serializer,
|
_serializer,
|
||||||
#item_name,
|
#name,
|
||||||
#variant_index,
|
#variant_index,
|
||||||
#variant_name,
|
#variant_name,
|
||||||
#len,
|
#len,
|
||||||
@@ -681,7 +672,7 @@ fn serialize_struct_variant<'a>(context: StructVariant<'a>,
|
|||||||
quote! {
|
quote! {
|
||||||
let mut __serde_state = try!(_serde::Serializer::serialize_struct(
|
let mut __serde_state = try!(_serde::Serializer::serialize_struct(
|
||||||
_serializer,
|
_serializer,
|
||||||
#item_name,
|
#name,
|
||||||
#len + 1,
|
#len + 1,
|
||||||
));
|
));
|
||||||
try!(_serde::ser::SerializeStruct::serialize_field(
|
try!(_serde::ser::SerializeStruct::serialize_field(
|
||||||
@@ -697,7 +688,7 @@ fn serialize_struct_variant<'a>(context: StructVariant<'a>,
|
|||||||
quote! {
|
quote! {
|
||||||
let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct(
|
let #let_mut __serde_state = try!(_serde::Serializer::serialize_struct(
|
||||||
_serializer,
|
_serializer,
|
||||||
#item_name,
|
#name,
|
||||||
#len,
|
#len,
|
||||||
));
|
));
|
||||||
#(#serialize_fields)*
|
#(#serialize_fields)*
|
||||||
|
|||||||
@@ -884,36 +884,39 @@ fn test_internally_tagged_enum() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_adjacently_tagged_enum() {
|
fn test_adjacently_tagged_enum() {
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize)]
|
||||||
struct Newtype(BTreeMap<String, String>);
|
#[serde(tag = "t", content = "c")]
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
|
||||||
struct Struct {
|
|
||||||
f: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize)] // , Deserialize
|
|
||||||
#[serde(tag = "type", content = "content")]
|
|
||||||
enum AdjacentlyTagged {
|
enum AdjacentlyTagged {
|
||||||
A(u8),
|
Unit,
|
||||||
B(u8, u16, u32),
|
Newtype(u8),
|
||||||
C,
|
Tuple(u8, u8),
|
||||||
D(BTreeMap<String, String>),
|
Struct { f: u8 },
|
||||||
E(Newtype),
|
|
||||||
F(Struct),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_ser_tokens(
|
assert_ser_tokens(
|
||||||
&AdjacentlyTagged::A(1),
|
&AdjacentlyTagged::Unit,
|
||||||
|
&[
|
||||||
|
Token::StructStart("AdjacentlyTagged", 1),
|
||||||
|
|
||||||
|
Token::StructSep,
|
||||||
|
Token::Str("t"),
|
||||||
|
Token::Str("Unit"),
|
||||||
|
|
||||||
|
Token::StructEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_ser_tokens(
|
||||||
|
&AdjacentlyTagged::Newtype(1),
|
||||||
&[
|
&[
|
||||||
Token::StructStart("AdjacentlyTagged", 2),
|
Token::StructStart("AdjacentlyTagged", 2),
|
||||||
|
|
||||||
Token::StructSep,
|
Token::StructSep,
|
||||||
Token::Str("type"),
|
Token::Str("t"),
|
||||||
Token::Str("A"),
|
Token::Str("Newtype"),
|
||||||
|
|
||||||
Token::StructSep,
|
Token::StructSep,
|
||||||
Token::Str("content"),
|
Token::Str("c"),
|
||||||
Token::U8(1),
|
Token::U8(1),
|
||||||
|
|
||||||
Token::StructEnd,
|
Token::StructEnd,
|
||||||
@@ -921,28 +924,21 @@ fn test_adjacently_tagged_enum() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
assert_ser_tokens(
|
assert_ser_tokens(
|
||||||
&AdjacentlyTagged::B(1, 300, 70000),
|
&AdjacentlyTagged::Tuple(1, 1),
|
||||||
&[
|
&[
|
||||||
Token::StructStart("AdjacentlyTagged", 2),
|
Token::StructStart("AdjacentlyTagged", 2),
|
||||||
|
|
||||||
Token::StructSep,
|
Token::StructSep,
|
||||||
Token::Str("type"),
|
Token::Str("t"),
|
||||||
Token::Str("B"),
|
Token::Str("Tuple"),
|
||||||
|
|
||||||
Token::StructSep,
|
Token::StructSep,
|
||||||
Token::Str("content"),
|
Token::Str("c"),
|
||||||
|
Token::TupleStart(2),
|
||||||
Token::TupleStart(3),
|
|
||||||
|
|
||||||
Token::TupleSep,
|
Token::TupleSep,
|
||||||
Token::U8(1),
|
Token::U8(1),
|
||||||
|
|
||||||
Token::TupleSep,
|
Token::TupleSep,
|
||||||
Token::U16(300),
|
Token::U8(1),
|
||||||
|
|
||||||
Token::TupleSep,
|
|
||||||
Token::U32(70000),
|
|
||||||
|
|
||||||
Token::TupleEnd,
|
Token::TupleEnd,
|
||||||
|
|
||||||
Token::StructEnd,
|
Token::StructEnd,
|
||||||
@@ -950,74 +946,20 @@ fn test_adjacently_tagged_enum() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
assert_ser_tokens(
|
assert_ser_tokens(
|
||||||
&AdjacentlyTagged::C,
|
&AdjacentlyTagged::Struct { f: 1 },
|
||||||
&[
|
|
||||||
Token::StructStart("AdjacentlyTagged", 1),
|
|
||||||
|
|
||||||
Token::StructSep,
|
|
||||||
Token::Str("type"),
|
|
||||||
Token::Str("C"),
|
|
||||||
|
|
||||||
Token::StructEnd,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_ser_tokens(
|
|
||||||
&AdjacentlyTagged::D(BTreeMap::new()),
|
|
||||||
&[
|
&[
|
||||||
Token::StructStart("AdjacentlyTagged", 2),
|
Token::StructStart("AdjacentlyTagged", 2),
|
||||||
|
|
||||||
Token::StructSep,
|
Token::StructSep,
|
||||||
Token::Str("type"),
|
Token::Str("t"),
|
||||||
Token::Str("D"),
|
Token::Str("Struct"),
|
||||||
|
|
||||||
Token::StructSep,
|
Token::StructSep,
|
||||||
Token::Str("content"),
|
Token::Str("c"),
|
||||||
Token::MapStart(Some(0)),
|
|
||||||
Token::MapEnd,
|
|
||||||
|
|
||||||
Token::StructEnd,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
// FIXME: Nested newtype is broken
|
|
||||||
|
|
||||||
// assert_ser_tokens(
|
|
||||||
// &AdjacentlyTagged::E(Newtype(BTreeMap::new())),
|
|
||||||
// &[
|
|
||||||
// Token::StructStart("AdjacentlyTagged", 2),
|
|
||||||
|
|
||||||
// Token::StructSep,
|
|
||||||
// Token::Str("type"),
|
|
||||||
// Token::Str("E"),
|
|
||||||
|
|
||||||
// Token::StructSep,
|
|
||||||
// Token::Str("content"),
|
|
||||||
// Token::MapStart(Some(0)),
|
|
||||||
// Token::MapEnd,
|
|
||||||
|
|
||||||
// Token::StructEnd,
|
|
||||||
// ]
|
|
||||||
// );
|
|
||||||
|
|
||||||
assert_ser_tokens(
|
|
||||||
&AdjacentlyTagged::F(Struct { f: 6 }),
|
|
||||||
&[
|
|
||||||
Token::StructStart("AdjacentlyTagged", 2),
|
|
||||||
|
|
||||||
Token::StructSep,
|
|
||||||
Token::Str("type"),
|
|
||||||
Token::Str("F"),
|
|
||||||
|
|
||||||
Token::StructSep,
|
|
||||||
Token::Str("content"),
|
|
||||||
|
|
||||||
Token::StructStart("Struct", 1),
|
Token::StructStart("Struct", 1),
|
||||||
|
|
||||||
Token::StructSep,
|
Token::StructSep,
|
||||||
Token::Str("f"),
|
Token::Str("f"),
|
||||||
Token::U8(6),
|
Token::U8(1),
|
||||||
|
|
||||||
Token::StructEnd,
|
Token::StructEnd,
|
||||||
|
|
||||||
Token::StructEnd,
|
Token::StructEnd,
|
||||||
|
|||||||
Reference in New Issue
Block a user