Implement skip_serializing for enum variant

This commit is contained in:
Shing Lyu 2016-12-24 14:37:23 +08:00
parent 2c984980a0
commit 2fea8c9c28
3 changed files with 148 additions and 63 deletions

View File

@ -255,77 +255,123 @@ fn serialize_variant(
let variant_ident = variant.ident.clone(); let variant_ident = variant.ident.clone();
let variant_name = variant.attrs.name().serialize_name(); let variant_name = variant.attrs.name().serialize_name();
let skipped_err = quote! {
Err(_serde::ser::Error::invalid_value("The enum variant was skipped for serialization"))
};
match variant.style { if variant.attrs.skip_serializing() {
Style::Unit => { match variant.style {
quote! { Style::Unit => {
#type_ident::#variant_ident => quote! {
_serde::ser::Serializer::serialize_unit_variant( #type_ident::#variant_ident => #skipped_err,
_serializer, }
#type_name, },
#variant_index, Style::Newtype => {
#variant_name, quote! {
), #type_ident::#variant_ident(ref __simple_value) => #skipped_err,
} }
}, },
Style::Newtype => { Style::Tuple => {
let block = serialize_newtype_variant( let field_names: Vec<Tokens> = (0 .. variant.fields.len())
type_name, .map(|i| {
variant_index, let id = aster::id(format!("__field{}", i));
variant_name, quote!(ref #id)
ty, })
generics, .collect();
&variant.fields[0],
);
quote! { let pat = quote!(#type_ident::#variant_ident(#(#field_names),*));
#type_ident::#variant_ident(ref __simple_value) => #block,
quote! {
#pat => #skipped_err,
}
} }
}, Style::Struct => {
Style::Tuple => { let fields = variant.fields.iter().map(|field| {
let field_names: Vec<Tokens> = (0 .. variant.fields.len()) let id = match field.ident {
.map(|i| { Some(ref name) => name.clone(),
let id = aster::id(format!("__field{}", i)); None => panic!("struct variant has unnamed fields"),
};
quote!(ref #id) quote!(ref #id)
}) });
.collect(); let pat = quote!(#type_ident::#variant_ident { #(#fields),* });
let pat = quote!(#type_ident::#variant_ident(#(#field_names),*)); quote! {
#pat => #skipped_err,
let block = serialize_tuple_variant( }
type_name,
variant_index,
variant_name,
generics,
ty,
&variant.fields,
);
quote! {
#pat => { #block }
} }
} }
Style::Struct => { } else { // variant wasn't skipped
let fields = variant.fields.iter().map(|field| { match variant.style {
let id = match field.ident { Style::Unit => {
Some(ref name) => name.clone(), quote! {
None => panic!("struct variant has unnamed fields"), #type_ident::#variant_ident =>
}; _serde::ser::Serializer::serialize_unit_variant(
quote!(ref #id) _serializer,
}); #type_name,
let pat = quote!(#type_ident::#variant_ident { #(#fields),* }); #variant_index,
#variant_name,
),
}
},
Style::Newtype => {
let block = serialize_newtype_variant(
type_name,
variant_index,
variant_name,
ty,
generics,
&variant.fields[0],
);
let block = serialize_struct_variant( quote! {
variant_index, #type_ident::#variant_ident(ref __simple_value) => #block,
variant_name, }
generics, },
ty, Style::Tuple => {
&variant.fields, let field_names: Vec<Tokens> = (0 .. variant.fields.len())
item_attrs, .map(|i| {
); let id = aster::id(format!("__field{}", i));
quote!(ref #id)
})
.collect();
quote! { let pat = quote!(#type_ident::#variant_ident(#(#field_names),*));
#pat => { #block }
let block = serialize_tuple_variant(
type_name,
variant_index,
variant_name,
generics,
ty,
&variant.fields,
);
quote! {
#pat => { #block }
}
}
Style::Struct => {
let fields = variant.fields.iter().map(|field| {
let id = match field.ident {
Some(ref name) => name.clone(),
None => panic!("struct variant has unnamed fields"),
};
quote!(ref #id)
});
let pat = quote!(#type_ident::#variant_ident { #(#fields),* });
let block = serialize_struct_variant(
variant_index,
variant_name,
generics,
ty,
&variant.fields,
item_attrs,
);
quote! {
#pat => { #block }
}
} }
} }
} }

View File

@ -188,6 +188,7 @@ impl Item {
pub struct Variant { pub struct Variant {
name: Name, name: Name,
skip_deserializing: bool, skip_deserializing: bool,
skip_serializing: bool,
} }
impl Variant { impl Variant {
@ -195,6 +196,7 @@ impl Variant {
let mut ser_name = Attr::none(cx, "rename"); let mut ser_name = Attr::none(cx, "rename");
let mut de_name = Attr::none(cx, "rename"); let mut de_name = Attr::none(cx, "rename");
let mut skip_deserializing = BoolAttr::none(cx, "skip_deserializing"); let mut skip_deserializing = BoolAttr::none(cx, "skip_deserializing");
let mut skip_serializing = BoolAttr::none(cx, "skip_serializing");
for meta_items in variant.attrs.iter().filter_map(get_serde_meta_items) { for meta_items in variant.attrs.iter().filter_map(get_serde_meta_items) {
for meta_item in meta_items { for meta_item in meta_items {
@ -218,6 +220,10 @@ impl Variant {
MetaItem(Word(ref name)) if name == "skip_deserializing" => { MetaItem(Word(ref name)) if name == "skip_deserializing" => {
skip_deserializing.set_true(); skip_deserializing.set_true();
} }
// Parse `#[serde(skip_serializing)]`
MetaItem(Word(ref name)) if name == "skip_serializing" => {
skip_serializing.set_true();
}
MetaItem(ref meta_item) => { MetaItem(ref meta_item) => {
cx.error(format!("unknown serde variant attribute `{}`", cx.error(format!("unknown serde variant attribute `{}`",
@ -237,6 +243,7 @@ impl Variant {
deserialize: de_name.get().unwrap_or_else(|| variant.ident.to_string()), deserialize: de_name.get().unwrap_or_else(|| variant.ident.to_string()),
}, },
skip_deserializing: skip_deserializing.get(), skip_deserializing: skip_deserializing.get(),
skip_serializing: skip_serializing.get(),
} }
} }
@ -247,6 +254,10 @@ impl Variant {
pub fn skip_deserializing(&self) -> bool { pub fn skip_deserializing(&self) -> bool {
self.skip_deserializing self.skip_deserializing
} }
pub fn skip_serializing(&self) -> bool {
self.skip_serializing
}
} }
/// Represents field attribute information /// Represents field attribute information

View File

@ -30,12 +30,20 @@ struct Struct {
c: i32, c: i32,
} }
#[derive(Serialize)] #[derive(Serialize, PartialEq, Debug)]
enum Enum { enum Enum {
Unit, Unit,
One(i32), One(i32),
Seq(i32, i32), Seq(i32, i32),
Map { a: i32, b: i32 }, Map { a: i32, b: i32 },
#[serde(skip_serializing)]
SkippedUnit,
#[serde(skip_serializing)]
SkippedOne(i32),
#[serde(skip_serializing)]
SkippedSeq(i32, i32),
#[serde(skip_serializing)]
SkippedMap { _a: i32, _b: i32 },
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -388,3 +396,23 @@ fn test_cannot_serialize_paths() {
&[], &[],
Error::InvalidValue("Path contains invalid UTF-8 characters".to_owned())); Error::InvalidValue("Path contains invalid UTF-8 characters".to_owned()));
} }
#[test]
fn test_enum_skipped() {
assert_ser_tokens_error(
&Enum::SkippedUnit,
&[],
Error::InvalidValue("The enum variant was skipped for serialization".to_owned()));
assert_ser_tokens_error(
&Enum::SkippedOne(42),
&[],
Error::InvalidValue("The enum variant was skipped for serialization".to_owned()));
assert_ser_tokens_error(
&Enum::SkippedSeq(1, 2),
&[],
Error::InvalidValue("The enum variant was skipped for serialization".to_owned()));
assert_ser_tokens_error(
&Enum::SkippedMap { _a: 1, _b: 2 },
&[],
Error::InvalidValue("The enum variant was skipped for serialization".to_owned()));
}