Support deserializing internally tagged enum from seq

During serialization, internally tagged enums invoke the Serializer's
serialize_struct. In JSON this turns into a map which uses visit_map
when deserialized. But some formats employ visit_seq when
deserializing a struct. One example is rmp-serde. Such formats were
previously unable to deserialize an internally tagged enum. This
change fixes it by adding visit_seq for internally tagged enums.
This commit is contained in:
David Tolnay
2017-09-17 13:45:07 -07:00
parent 4b00de0e22
commit b98a9a8f9b
3 changed files with 130 additions and 60 deletions
+33 -9
View File
@@ -834,26 +834,43 @@ mod content {
type Value = TaggedContent<'de, T>;
fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str("any value")
fmt.write_str("internally tagged enum")
}
fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
fn visit_seq<S>(self, mut seq: S) -> Result<Self::Value, S::Error>
where
V: MapAccess<'de>,
S: SeqAccess<'de>,
{
let tag = match try!(seq.next_element()) {
Some(tag) => tag,
None => {
return Err(de::Error::missing_field(self.tag_name));
}
};
let rest = de::value::SeqAccessDeserializer::new(seq);
Ok(TaggedContent {
tag: tag,
content: try!(Content::deserialize(rest)),
})
}
fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let mut tag = None;
let mut vec = Vec::with_capacity(size_hint::cautious(visitor.size_hint()));
let mut vec = Vec::with_capacity(size_hint::cautious(map.size_hint()));
while let Some(k) =
try!(visitor.next_key_seed(TagOrContentVisitor::new(self.tag_name))) {
try!(map.next_key_seed(TagOrContentVisitor::new(self.tag_name))) {
match k {
TagOrContent::Tag => {
if tag.is_some() {
return Err(de::Error::duplicate_field(self.tag_name));
}
tag = Some(try!(visitor.next_value()));
tag = Some(try!(map.next_value()));
}
TagOrContent::Content(k) => {
let v = try!(visitor.next_value());
let v = try!(map.next_value());
vec.push((k, v));
}
}
@@ -1802,9 +1819,16 @@ mod content {
write!(formatter, "unit variant {}::{}", self.type_name, self.variant_name)
}
fn visit_map<V>(self, _: V) -> Result<(), V::Error>
fn visit_seq<S>(self, _: S) -> Result<(), S::Error>
where
V: MapAccess<'de>,
S: SeqAccess<'de>,
{
Ok(())
}
fn visit_map<M>(self, _: M) -> Result<(), M::Error>
where
M: MapAccess<'de>,
{
Ok(())
}