Merge pull request #1245 from serde-rs/flat
Support deserializing a flattened internally tagged enum
This commit is contained in:
commit
6374467f02
@ -1132,6 +1132,18 @@ pub trait Deserializer<'de>: Sized {
|
||||
fn is_human_readable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
// Not public API.
|
||||
#[doc(hidden)]
|
||||
fn private_deserialize_internally_tagged_enum<V>(
|
||||
self,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
self.deserialize_any(visitor)
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -2715,6 +2715,20 @@ where
|
||||
byte_buf option unit unit_struct seq tuple tuple_struct identifier
|
||||
ignored_any
|
||||
}
|
||||
|
||||
fn private_deserialize_internally_tagged_enum<V>(
|
||||
self,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
visitor.visit_map(FlatInternallyTaggedAccess {
|
||||
iter: self.0.iter_mut(),
|
||||
pending: None,
|
||||
_marker: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
@ -2786,3 +2800,44 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
pub struct FlatInternallyTaggedAccess<'a, 'de: 'a, E> {
|
||||
iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>,
|
||||
pending: Option<&'a Content<'de>>,
|
||||
_marker: PhantomData<E>,
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
impl<'a, 'de, E> MapAccess<'de> for FlatInternallyTaggedAccess<'a, 'de, E>
|
||||
where
|
||||
E: Error,
|
||||
{
|
||||
type Error = E;
|
||||
|
||||
fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
|
||||
where
|
||||
T: DeserializeSeed<'de>,
|
||||
{
|
||||
while let Some(item) = self.iter.next() {
|
||||
// Do not take(), instead borrow this entry. The internally tagged
|
||||
// enum does its own buffering so we can't tell whether this entry
|
||||
// is going to be consumed. Borrowing here leaves the entry
|
||||
// available for later flattened fields.
|
||||
let (ref key, ref content) = *item.as_ref().unwrap();
|
||||
self.pending = Some(content);
|
||||
return seed.deserialize(ContentRefDeserializer::new(key)).map(Some);
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error>
|
||||
where
|
||||
T: DeserializeSeed<'de>,
|
||||
{
|
||||
match self.pending.take() {
|
||||
Some(value) => seed.deserialize(ContentRefDeserializer::new(value)),
|
||||
None => panic!("value is missing"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1193,7 +1193,7 @@ fn deserialize_internally_tagged_enum(
|
||||
|
||||
#variants_stmt
|
||||
|
||||
let __tagged = try!(_serde::Deserializer::deserialize_any(
|
||||
let __tagged = try!(_serde::Deserializer::private_deserialize_internally_tagged_enum(
|
||||
__deserializer,
|
||||
_serde::private::de::TaggedContentVisitor::<__Field>::new(#tag)));
|
||||
|
||||
|
@ -1793,3 +1793,49 @@ fn test_flatten_enum_newtype() {
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_flatten_internally_tagged() {
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
struct S {
|
||||
#[serde(flatten)]
|
||||
x: X,
|
||||
#[serde(flatten)]
|
||||
y: Y,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
#[serde(tag = "typeX")]
|
||||
enum X {
|
||||
A { a: i32 },
|
||||
B { b: i32 },
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
#[serde(tag = "typeY")]
|
||||
enum Y {
|
||||
C { c: i32 },
|
||||
D { d: i32 },
|
||||
}
|
||||
|
||||
let s = S {
|
||||
x: X::B { b: 1 },
|
||||
y: Y::D { d: 2 },
|
||||
};
|
||||
|
||||
assert_tokens(
|
||||
&s,
|
||||
&[
|
||||
Token::Map { len: None },
|
||||
Token::Str("typeX"),
|
||||
Token::Str("B"),
|
||||
Token::Str("b"),
|
||||
Token::I32(1),
|
||||
Token::Str("typeY"),
|
||||
Token::Str("D"),
|
||||
Token::Str("d"),
|
||||
Token::I32(2),
|
||||
Token::MapEnd,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user