Merge pull request #1085 from serde-rs/internally-unit-struct

Allow internally tagged newtype variant containing unit struct
This commit is contained in:
David Tolnay 2017-11-06 23:44:29 -08:00 committed by GitHub
commit 66e8b0a0cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 78 additions and 5 deletions

View File

@ -1114,10 +1114,38 @@ mod content {
) )
} }
fn deserialize_unit_struct<V>(
self,
_name: &'static str,
visitor: V
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
match self.content {
// As a special case, allow deserializing untagged newtype
// variant containing unit struct.
//
// #[derive(Deserialize)]
// struct Info;
//
// #[derive(Deserialize)]
// #[serde(tag = "topic")]
// enum Message {
// Info(Info),
// }
//
// We want {"topic":"Info"} to deserialize even though
// ordinarily unit structs do not deserialize from empty map.
Content::Map(ref v) if v.is_empty() => visitor.visit_unit(),
_ => self.deserialize_any(visitor),
}
}
forward_to_deserialize_any! { forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
byte_buf unit unit_struct seq tuple tuple_struct map struct byte_buf unit seq tuple tuple_struct map struct identifier
identifier ignored_any ignored_any
} }
} }

View File

@ -60,7 +60,6 @@ enum Unsupported {
ByteArray, ByteArray,
Optional, Optional,
Unit, Unit,
UnitStruct,
Sequence, Sequence,
Tuple, Tuple,
TupleStruct, TupleStruct,
@ -79,7 +78,6 @@ impl Display for Unsupported {
Unsupported::ByteArray => formatter.write_str("a byte array"), Unsupported::ByteArray => formatter.write_str("a byte array"),
Unsupported::Optional => formatter.write_str("an optional"), Unsupported::Optional => formatter.write_str("an optional"),
Unsupported::Unit => formatter.write_str("unit"), Unsupported::Unit => formatter.write_str("unit"),
Unsupported::UnitStruct => formatter.write_str("a unit struct"),
Unsupported::Sequence => formatter.write_str("a sequence"), Unsupported::Sequence => formatter.write_str("a sequence"),
Unsupported::Tuple => formatter.write_str("a tuple"), Unsupported::Tuple => formatter.write_str("a tuple"),
Unsupported::TupleStruct => formatter.write_str("a tuple struct"), Unsupported::TupleStruct => formatter.write_str("a tuple struct"),
@ -199,7 +197,9 @@ where
} }
fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> { fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
Err(self.bad_type(Unsupported::UnitStruct)) let mut map = try!(self.delegate.serialize_map(Some(1)));
try!(map.serialize_entry(self.tag, self.variant_name));
map.end()
} }
fn serialize_unit_variant( fn serialize_unit_variant(

View File

@ -1267,3 +1267,48 @@ fn test_rename_all() {
] ]
); );
} }
#[test]
fn test_untagged_newtype_variant_containing_unit_struct_not_map() {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Unit;
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
enum Message {
Unit(Unit),
Map(BTreeMap<String, String>),
}
assert_tokens(
&Message::Map(BTreeMap::new()),
&[
Token::Map { len: Some(0) },
Token::MapEnd,
],
);
}
#[test]
fn test_internally_tagged_newtype_variant_containing_unit_struct() {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct Info;
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "topic")]
enum Message {
Info(Info),
}
assert_tokens(
&Message::Info(Info),
&[
Token::Map { len: Some(1) },
Token::Str("topic"),
Token::Str("Info"),
Token::MapEnd,
],
);
}