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,7 +255,52 @@ 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"))
};
if variant.attrs.skip_serializing() {
match variant.style {
Style::Unit => {
quote! {
#type_ident::#variant_ident => #skipped_err,
}
},
Style::Newtype => {
quote! {
#type_ident::#variant_ident(ref __simple_value) => #skipped_err,
}
},
Style::Tuple => {
let field_names: Vec<Tokens> = (0 .. variant.fields.len())
.map(|i| {
let id = aster::id(format!("__field{}", i));
quote!(ref #id)
})
.collect();
let pat = quote!(#type_ident::#variant_ident(#(#field_names),*));
quote! {
#pat => #skipped_err,
}
}
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),* });
quote! {
#pat => #skipped_err,
}
}
}
} else { // variant wasn't skipped
match variant.style { match variant.style {
Style::Unit => { Style::Unit => {
quote! { quote! {
@ -329,6 +374,7 @@ fn serialize_variant(
} }
} }
} }
}
} }
fn serialize_newtype_variant( fn serialize_newtype_variant(

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()));
}