Skip to content

Commit

Permalink
Merge pull request #678 from serde-rs/empty
Browse files Browse the repository at this point in the history
Handle various degenerate cases
  • Loading branch information
dtolnay authored Jan 11, 2017
2 parents 3aaf29c + b01c23b commit ca47eb9
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 13 deletions.
42 changes: 29 additions & 13 deletions serde_codegen/src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -509,14 +509,6 @@ fn deserialize_item_enum(
const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ];
};

let ignored_arm = if item_attrs.deny_unknown_fields() {
None
} else {
Some(quote! {
__Field::__ignore => { Err(_serde::de::Error::end_of_stream()) }
})
};

// Match arms to extract a variant from a string
let mut variant_arms = vec![];
for (i, variant) in variants.iter().filter(|variant| !variant.attrs.skip_deserializing()).enumerate() {
Expand All @@ -536,7 +528,23 @@ fn deserialize_item_enum(
};
variant_arms.push(arm);
}
variant_arms.extend(ignored_arm.into_iter());

let match_variant = if variant_arms.is_empty() {
// This is an empty enum like `enum Impossible {}` or an enum in which
// all variants have `#[serde(skip_deserializing)]`.
quote! {
// FIXME: Once we drop support for Rust 1.15:
// let Err(err) = visitor.visit_variant::<__Field>();
// Err(err)
visitor.visit_variant::<__Field>().map(|impossible| match impossible {})
}
} else {
quote! {
match try!(visitor.visit_variant()) {
#(#variant_arms)*
}
}
};

let (visitor_item, visitor_ty, visitor_expr) = deserialize_visitor(impl_generics);

Expand All @@ -551,9 +559,7 @@ fn deserialize_item_enum(
fn visit_enum<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<#ty, __V::Error>
where __V: _serde::de::VariantVisitor,
{
match try!(visitor.visit_variant()) {
#(#variant_arms)*
}
#match_variant
}
}

Expand Down Expand Up @@ -646,7 +652,7 @@ fn deserialize_field_visitor(
.map(|i| aster::id(format!("__field{}", i)))
.collect();

let ignore_variant = if item_attrs.deny_unknown_fields() {
let ignore_variant = if is_variant || item_attrs.deny_unknown_fields() {
None
} else {
Some(quote!(__ignore,))
Expand Down Expand Up @@ -744,6 +750,16 @@ fn deserialize_map(
fields: &[Field],
item_attrs: &attr::Item,
) -> Tokens {
if fields.is_empty() && item_attrs.deny_unknown_fields() {
return quote! {
// FIXME: Once we drop support for Rust 1.15:
// let None::<__Field> = try!(visitor.visit_key());
try!(visitor.visit_key::<__Field>()).map(|impossible| match impossible {});
try!(visitor.end());
Ok(#struct_path {})
};
}

// Create the field names for the fields.
let fields_names = fields.iter()
.enumerate()
Expand Down
79 changes: 79 additions & 0 deletions testing/tests/test_gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,85 @@ fn test_gen() {
struct NonAsciiIdents {
σ: f64
}

#[derive(Serialize, Deserialize)]
struct EmptyBraced {}

#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
struct EmptyBracedDenyUnknown {}

#[derive(Serialize, Deserialize)]
struct BracedSkipAll {
#[serde(skip_deserializing)]
f: u8,
}

#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
struct BracedSkipAllDenyUnknown {
#[serde(skip_deserializing)]
f: u8,
}

#[cfg(feature = "unstable-testing")]
#[cfg_attr(feature = "unstable-testing", derive(Serialize, Deserialize))]
struct EmptyTuple();

#[cfg(feature = "unstable-testing")]
#[cfg_attr(feature = "unstable-testing", derive(Serialize, Deserialize))]
#[serde(deny_unknown_fields)]
struct EmptyTupleDenyUnknown();

#[derive(Serialize, Deserialize)]
struct TupleSkipAll(#[serde(skip_deserializing)] u8);

#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
struct TupleSkipAllDenyUnknown(#[serde(skip_deserializing)] u8);

#[derive(Serialize, Deserialize)]
enum EmptyEnum {}

#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
enum EmptyEnumDenyUnknown {}

#[derive(Serialize, Deserialize)]
enum EnumSkipAll {
#[serde(skip_deserializing)]
#[allow(dead_code)]
Variant,
}

#[cfg(feature = "unstable-testing")]
#[cfg_attr(feature = "unstable-testing", derive(Serialize, Deserialize))]
enum EmptyVariants {
Braced {},
Tuple(),
BracedSkip {
#[serde(skip_deserializing)]
f: u8,
},
TupleSkip(#[serde(skip_deserializing)] u8),
}

#[cfg(feature = "unstable-testing")]
#[cfg_attr(feature = "unstable-testing", derive(Serialize, Deserialize))]
#[serde(deny_unknown_fields)]
enum EmptyVariantsDenyUnknown {
Braced {},
Tuple(),
BracedSkip {
#[serde(skip_deserializing)]
f: u8,
},
TupleSkip(#[serde(skip_deserializing)] u8),
}

#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
struct UnitDenyUnknown;
}

//////////////////////////////////////////////////////////////////////////
Expand Down

0 comments on commit ca47eb9

Please sign in to comment.