diff --git a/serde/src/private/de.rs b/serde/src/private/de.rs index 3c0a187a..06b02489 100644 --- a/serde/src/private/de.rs +++ b/serde/src/private/de.rs @@ -207,6 +207,7 @@ mod content { use __private::size_hint; use actually_private; + use de::value::{MapDeserializer, SeqDeserializer}; use de::{ self, Deserialize, DeserializeSeed, Deserializer, EnumAccess, Expected, IgnoredAny, MapAccess, SeqAccess, Unexpected, Visitor, @@ -299,6 +300,17 @@ mod content { } } + impl<'de, E> de::IntoDeserializer<'de, E> for Content<'de> + where + E: de::Error, + { + type Deserializer = ContentDeserializer<'de, E>; + + fn into_deserializer(self) -> Self::Deserializer { + ContentDeserializer::new(self) + } + } + struct ContentVisitor<'de> { value: PhantomData>, } @@ -1074,7 +1086,7 @@ mod content { E: de::Error, { let seq = content.into_iter().map(ContentDeserializer::new); - let mut seq_visitor = de::value::SeqDeserializer::new(seq); + let mut seq_visitor = SeqDeserializer::new(seq); let value = try!(visitor.visit_seq(&mut seq_visitor)); try!(seq_visitor.end()); Ok(value) @@ -1091,7 +1103,7 @@ mod content { let map = content .into_iter() .map(|(k, v)| (ContentDeserializer::new(k), ContentDeserializer::new(v))); - let mut map_visitor = de::value::MapDeserializer::new(map); + let mut map_visitor = MapDeserializer::new(map); let value = try!(visitor.visit_map(&mut map_visitor)); try!(map_visitor.end()); Ok(value) @@ -1569,7 +1581,7 @@ mod content { { match self.value { Some(Content::Seq(v)) => { - de::Deserializer::deserialize_any(SeqDeserializer::new(v), visitor) + de::Deserializer::deserialize_any(SeqDeserializer::new(v.into_iter()), visitor) } Some(other) => Err(de::Error::invalid_type( other.unexpected(), @@ -1592,10 +1604,10 @@ mod content { { match self.value { Some(Content::Map(v)) => { - de::Deserializer::deserialize_any(MapDeserializer::new(v), visitor) + de::Deserializer::deserialize_any(MapDeserializer::new(v.into_iter()), visitor) } Some(Content::Seq(v)) => { - de::Deserializer::deserialize_any(SeqDeserializer::new(v), visitor) + de::Deserializer::deserialize_any(SeqDeserializer::new(v.into_iter()), visitor) } Some(other) => Err(de::Error::invalid_type( other.unexpected(), @@ -1609,156 +1621,6 @@ mod content { } } - struct SeqDeserializer<'de, E> - where - E: de::Error, - { - iter: > as IntoIterator>::IntoIter, - err: PhantomData, - } - - impl<'de, E> SeqDeserializer<'de, E> - where - E: de::Error, - { - fn new(vec: Vec>) -> Self { - SeqDeserializer { - iter: vec.into_iter(), - err: PhantomData, - } - } - } - - impl<'de, E> de::Deserializer<'de> for SeqDeserializer<'de, E> - where - E: de::Error, - { - type Error = E; - - #[inline] - fn deserialize_any(mut self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - let len = self.iter.len(); - if len == 0 { - visitor.visit_unit() - } else { - let ret = try!(visitor.visit_seq(&mut self)); - let remaining = self.iter.len(); - if remaining == 0 { - Ok(ret) - } else { - Err(de::Error::invalid_length(len, &"fewer elements in array")) - } - } - } - - forward_to_deserialize_any! { - bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string - bytes byte_buf option unit unit_struct newtype_struct seq tuple - tuple_struct map struct enum identifier ignored_any - } - } - - impl<'de, E> de::SeqAccess<'de> for SeqDeserializer<'de, E> - where - E: de::Error, - { - type Error = E; - - fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> - where - T: de::DeserializeSeed<'de>, - { - match self.iter.next() { - Some(value) => seed.deserialize(ContentDeserializer::new(value)).map(Some), - None => Ok(None), - } - } - - fn size_hint(&self) -> Option { - size_hint::from_bounds(&self.iter) - } - } - - struct MapDeserializer<'de, E> - where - E: de::Error, - { - iter: , Content<'de>)> as IntoIterator>::IntoIter, - value: Option>, - err: PhantomData, - } - - impl<'de, E> MapDeserializer<'de, E> - where - E: de::Error, - { - fn new(map: Vec<(Content<'de>, Content<'de>)>) -> Self { - MapDeserializer { - iter: map.into_iter(), - value: None, - err: PhantomData, - } - } - } - - impl<'de, E> de::MapAccess<'de> for MapDeserializer<'de, E> - where - E: de::Error, - { - type Error = E; - - fn next_key_seed(&mut self, seed: T) -> Result, Self::Error> - where - T: de::DeserializeSeed<'de>, - { - match self.iter.next() { - Some((key, value)) => { - self.value = Some(value); - seed.deserialize(ContentDeserializer::new(key)).map(Some) - } - None => Ok(None), - } - } - - fn next_value_seed(&mut self, seed: T) -> Result - where - T: de::DeserializeSeed<'de>, - { - match self.value.take() { - Some(value) => seed.deserialize(ContentDeserializer::new(value)), - None => Err(de::Error::custom("value is missing")), - } - } - - fn size_hint(&self) -> Option { - size_hint::from_bounds(&self.iter) - } - } - - impl<'de, E> de::Deserializer<'de> for MapDeserializer<'de, E> - where - E: de::Error, - { - type Error = E; - - #[inline] - fn deserialize_any(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - visitor.visit_map(self) - } - - forward_to_deserialize_any! { - bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string - bytes byte_buf option unit unit_struct newtype_struct seq tuple - tuple_struct map struct enum identifier ignored_any - } - } - /// Not public API. pub struct ContentRefDeserializer<'a, 'de: 'a, E> { content: &'a Content<'de>, @@ -1820,7 +1682,7 @@ mod content { E: de::Error, { let seq = content.iter().map(ContentRefDeserializer::new); - let mut seq_visitor = de::value::SeqDeserializer::new(seq); + let mut seq_visitor = SeqDeserializer::new(seq); let value = try!(visitor.visit_seq(&mut seq_visitor)); try!(seq_visitor.end()); Ok(value) @@ -1840,7 +1702,7 @@ mod content { ContentRefDeserializer::new(v), ) }); - let mut map_visitor = de::value::MapDeserializer::new(map); + let mut map_visitor = MapDeserializer::new(map); let value = try!(visitor.visit_map(&mut map_visitor)); try!(map_visitor.end()); Ok(value) diff --git a/serde/src/private/ser.rs b/serde/src/private/ser.rs index 4dd45eda..a73f259b 100644 --- a/serde/src/private/ser.rs +++ b/serde/src/private/ser.rs @@ -1025,7 +1025,7 @@ where type SerializeTupleStruct = Impossible; type SerializeMap = FlatMapSerializeMap<'a, M>; type SerializeStruct = FlatMapSerializeStruct<'a, M>; - type SerializeTupleVariant = Impossible; + type SerializeTupleVariant = FlatMapSerializeTupleVariantAsMapValue<'a, M>; type SerializeStructVariant = FlatMapSerializeStructVariantAsMapValue<'a, M>; fn serialize_bool(self, _: bool) -> Result { @@ -1157,10 +1157,11 @@ where self, _: &'static str, _: u32, - _: &'static str, + variant: &'static str, _: usize, ) -> Result { - Err(Self::bad_type(Unsupported::Enum)) + try!(self.0.serialize_key(variant)); + Ok(FlatMapSerializeTupleVariantAsMapValue::new(self.0)) } fn serialize_map(self, _: Option) -> Result { @@ -1259,6 +1260,52 @@ where } } +//////////////////////////////////////////////////////////////////////////////////////////////////// + +#[cfg(any(feature = "std", feature = "alloc"))] +pub struct FlatMapSerializeTupleVariantAsMapValue<'a, M: 'a> { + map: &'a mut M, + fields: Vec, +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, M> FlatMapSerializeTupleVariantAsMapValue<'a, M> +where + M: SerializeMap + 'a, +{ + fn new(map: &'a mut M) -> Self { + FlatMapSerializeTupleVariantAsMapValue { + map: map, + fields: Vec::new(), + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, M> ser::SerializeTupleVariant for FlatMapSerializeTupleVariantAsMapValue<'a, M> +where + M: SerializeMap + 'a, +{ + type Ok = (); + type Error = M::Error; + + fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> + where + T: Serialize, + { + let value = try!(value.serialize(ContentSerializer::::new())); + self.fields.push(value); + Ok(()) + } + + fn end(self) -> Result<(), Self::Error> { + try!(self.map.serialize_value(&Content::Seq(self.fields))); + Ok(()) + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + #[cfg(any(feature = "std", feature = "alloc"))] pub struct FlatMapSerializeStructVariantAsMapValue<'a, M: 'a> { map: &'a mut M, diff --git a/test_suite/tests/test_annotations.rs b/test_suite/tests/test_annotations.rs index d4145b2b..d8e4a634 100644 --- a/test_suite/tests/test_annotations.rs +++ b/test_suite/tests/test_annotations.rs @@ -114,42 +114,6 @@ struct CollectOther { extra: HashMap, } -#[derive(Debug, PartialEq, Serialize, Deserialize)] -struct FlattenStructEnumWrapper { - #[serde(flatten)] - data: FlattenStructEnum, - #[serde(flatten)] - extra: HashMap, -} - -#[derive(Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -enum FlattenStructEnum { - InsertInteger { index: u32, value: u32 }, -} - -#[derive(Debug, PartialEq, Serialize, Deserialize)] -struct FlattenStructTagContentEnumWrapper { - outer: u32, - #[serde(flatten)] - data: FlattenStructTagContentEnumNewtype, -} - -#[derive(Debug, PartialEq, Serialize, Deserialize)] -struct FlattenStructTagContentEnumNewtype(pub FlattenStructTagContentEnum); - -#[derive(Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "snake_case", tag = "type", content = "value")] -enum FlattenStructTagContentEnum { - InsertInteger { index: u32, value: u32 }, - NewtypeVariant(FlattenStructTagContentEnumNewtypeVariant), -} - -#[derive(Debug, PartialEq, Serialize, Deserialize)] -struct FlattenStructTagContentEnumNewtypeVariant { - value: u32, -} - #[test] fn test_default_struct() { assert_de_tokens( @@ -1643,149 +1607,6 @@ fn test_collect_other() { ); } -#[test] -fn test_flatten_struct_enum() { - let mut extra = HashMap::new(); - extra.insert("extra_key".into(), "extra value".into()); - let change_request = FlattenStructEnumWrapper { - data: FlattenStructEnum::InsertInteger { - index: 0, - value: 42, - }, - extra, - }; - assert_de_tokens( - &change_request, - &[ - Token::Map { len: None }, - Token::Str("insert_integer"), - Token::Map { len: None }, - Token::Str("index"), - Token::U32(0), - Token::Str("value"), - Token::U32(42), - Token::MapEnd, - Token::Str("extra_key"), - Token::Str("extra value"), - Token::MapEnd, - ], - ); - assert_ser_tokens( - &change_request, - &[ - Token::Map { len: None }, - Token::Str("insert_integer"), - Token::Struct { - len: 2, - name: "insert_integer", - }, - Token::Str("index"), - Token::U32(0), - Token::Str("value"), - Token::U32(42), - Token::StructEnd, - Token::Str("extra_key"), - Token::Str("extra value"), - Token::MapEnd, - ], - ); -} - -#[test] -fn test_flatten_struct_tag_content_enum() { - let change_request = FlattenStructTagContentEnumWrapper { - outer: 42, - data: FlattenStructTagContentEnumNewtype(FlattenStructTagContentEnum::InsertInteger { - index: 0, - value: 42, - }), - }; - assert_de_tokens( - &change_request, - &[ - Token::Map { len: None }, - Token::Str("outer"), - Token::U32(42), - Token::Str("type"), - Token::Str("insert_integer"), - Token::Str("value"), - Token::Map { len: None }, - Token::Str("index"), - Token::U32(0), - Token::Str("value"), - Token::U32(42), - Token::MapEnd, - Token::MapEnd, - ], - ); - assert_ser_tokens( - &change_request, - &[ - Token::Map { len: None }, - Token::Str("outer"), - Token::U32(42), - Token::Str("type"), - Token::Str("insert_integer"), - Token::Str("value"), - Token::Struct { - len: 2, - name: "insert_integer", - }, - Token::Str("index"), - Token::U32(0), - Token::Str("value"), - Token::U32(42), - Token::StructEnd, - Token::MapEnd, - ], - ); -} - -#[test] -fn test_flatten_struct_tag_content_enum_newtype() { - let change_request = FlattenStructTagContentEnumWrapper { - outer: 42, - data: FlattenStructTagContentEnumNewtype(FlattenStructTagContentEnum::NewtypeVariant( - FlattenStructTagContentEnumNewtypeVariant { value: 23 }, - )), - }; - assert_de_tokens( - &change_request, - &[ - Token::Map { len: None }, - Token::Str("outer"), - Token::U32(42), - Token::Str("type"), - Token::Str("newtype_variant"), - Token::Str("value"), - Token::Map { len: None }, - Token::Str("value"), - Token::U32(23), - Token::MapEnd, - Token::MapEnd, - ], - ); - assert_ser_tokens( - &change_request, - &[ - Token::Map { len: None }, - Token::Str("outer"), - Token::U32(42), - Token::Str("type"), - Token::Str("newtype_variant"), - Token::Str("value"), - Token::Struct { - len: 1, - name: "FlattenStructTagContentEnumNewtypeVariant", - }, - Token::Str("value"), - Token::U32(23), - Token::StructEnd, - Token::MapEnd, - ], - ); -} - #[test] fn test_unknown_field_in_flatten() { #[derive(Debug, PartialEq, Serialize, Deserialize)] @@ -2142,86 +1963,6 @@ fn test_lifetime_propagation_for_flatten() { ); } -#[test] -fn test_flatten_enum_newtype() { - #[derive(Serialize, Deserialize, PartialEq, Debug)] - struct S { - #[serde(flatten)] - flat: E, - } - - #[derive(Serialize, Deserialize, PartialEq, Debug)] - enum E { - Q(HashMap), - } - - let e = E::Q({ - let mut map = HashMap::new(); - map.insert("k".to_owned(), "v".to_owned()); - map - }); - let s = S { flat: e }; - - assert_tokens( - &s, - &[ - Token::Map { len: None }, - Token::Str("Q"), - Token::Map { len: Some(1) }, - Token::Str("k"), - Token::Str("v"), - Token::MapEnd, - Token::MapEnd, - ], - ); -} - -#[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, - ], - ); -} - #[test] fn test_externally_tagged_enum_containing_flatten() { #[derive(Serialize, Deserialize, PartialEq, Debug)] @@ -2630,35 +2371,6 @@ fn test_partially_untagged_enum_desugared() { ); } -#[test] -fn test_flatten_untagged_enum() { - #[derive(Serialize, Deserialize, PartialEq, Debug)] - struct Outer { - #[serde(flatten)] - inner: Inner, - } - - #[derive(Serialize, Deserialize, PartialEq, Debug)] - #[serde(untagged)] - enum Inner { - Variant { a: i32 }, - } - - let data = Outer { - inner: Inner::Variant { a: 0 }, - }; - - assert_tokens( - &data, - &[ - Token::Map { len: None }, - Token::Str("a"), - Token::I32(0), - Token::MapEnd, - ], - ); -} - #[test] fn test_flatten_option() { #[derive(Serialize, Deserialize, PartialEq, Debug)] @@ -2815,48 +2527,6 @@ fn test_internally_tagged_unit_enum_with_unknown_fields() { ); } -#[test] -fn test_flattened_internally_tagged_unit_enum_with_unknown_fields() { - #[derive(Deserialize, PartialEq, Debug)] - struct S { - #[serde(flatten)] - x: X, - #[serde(flatten)] - y: Y, - } - - #[derive(Deserialize, PartialEq, Debug)] - #[serde(tag = "typeX")] - enum X { - A, - } - - #[derive(Deserialize, PartialEq, Debug)] - #[serde(tag = "typeY")] - enum Y { - B { c: u32 }, - } - - let s = S { - x: X::A, - y: Y::B { c: 0 }, - }; - - assert_de_tokens( - &s, - &[ - Token::Map { len: None }, - Token::Str("typeX"), - Token::Str("A"), - Token::Str("typeY"), - Token::Str("B"), - Token::Str("c"), - Token::I32(0), - Token::MapEnd, - ], - ); -} - #[test] fn test_flatten_any_after_flatten_struct() { #[derive(PartialEq, Debug)] @@ -3149,3 +2819,339 @@ fn test_expecting_message_identifier_enum() { r#"invalid type: map, expected something strange..."#, ); } + +mod flatten { + use super::*; + + mod enum_ { + use super::*; + + mod externally_tagged { + use super::*; + use std::iter::FromIterator; + + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct Flatten { + #[serde(flatten)] + data: Enum, + + #[serde(flatten)] + extra: HashMap, + } + + #[derive(Debug, PartialEq, Serialize, Deserialize)] + enum Enum { + Newtype(HashMap), + Tuple(u32, u32), + Struct { index: u32, value: u32 }, + } + + #[test] + fn newtype() { + assert_tokens( + &Flatten { + data: Enum::Newtype(HashMap::from_iter([("key".into(), "value".into())])), + extra: HashMap::from_iter([("extra_key".into(), "extra value".into())]), + }, + &[ + Token::Map { len: None }, + Token::Str("Newtype"), // variant + Token::Map { len: Some(1) }, + Token::Str("key"), + Token::Str("value"), + Token::MapEnd, + Token::Str("extra_key"), + Token::Str("extra value"), + Token::MapEnd, + ], + ); + } + + /// Reaches crate::private::de::content::VariantDeserializer::tuple_variant + /// Content::Seq case + /// via FlatMapDeserializer::deserialize_enum + #[test] + fn tuple() { + assert_tokens( + &Flatten { + data: Enum::Tuple(0, 42), + extra: HashMap::from_iter([("extra_key".into(), "extra value".into())]), + }, + &[ + Token::Map { len: None }, + Token::Str("Tuple"), // variant + Token::Seq { len: Some(2) }, + Token::U32(0), + Token::U32(42), + Token::SeqEnd, + Token::Str("extra_key"), + Token::Str("extra value"), + Token::MapEnd, + ], + ); + } + + /// Reaches crate::private::de::content::VariantDeserializer::struct_variant + /// Content::Seq case + /// via FlatMapDeserializer::deserialize_enum + #[test] + fn struct_from_seq() { + assert_de_tokens( + &Flatten { + data: Enum::Struct { + index: 0, + value: 42, + }, + extra: HashMap::from_iter([("extra_key".into(), "extra value".into())]), + }, + &[ + Token::Map { len: None }, + Token::Str("Struct"), // variant + Token::Seq { len: Some(2) }, + Token::U32(0), // index + Token::U32(42), // value + Token::SeqEnd, + Token::Str("extra_key"), + Token::Str("extra value"), + Token::MapEnd, + ], + ); + } + + /// Reaches crate::private::de::content::VariantDeserializer::struct_variant + /// Content::Map case + /// via FlatMapDeserializer::deserialize_enum + #[test] + fn struct_from_map() { + assert_tokens( + &Flatten { + data: Enum::Struct { + index: 0, + value: 42, + }, + extra: HashMap::from_iter([("extra_key".into(), "extra value".into())]), + }, + &[ + Token::Map { len: None }, + Token::Str("Struct"), // variant + Token::Struct { + len: 2, + name: "Struct", + }, + Token::Str("index"), + Token::U32(0), + Token::Str("value"), + Token::U32(42), + Token::StructEnd, + Token::Str("extra_key"), + Token::Str("extra value"), + Token::MapEnd, + ], + ); + } + } + + mod adjacently_tagged { + use super::*; + + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct Flatten { + outer: u32, + + #[serde(flatten)] + data: NewtypeWrapper, + } + + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct NewtypeWrapper(pub Enum); + + #[derive(Debug, PartialEq, Serialize, Deserialize)] + #[serde(tag = "tag", content = "content")] + enum Enum { + Newtype(NewtypeVariant), + Struct { index: u32, value: u32 }, + } + + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct NewtypeVariant { + value: u32, + } + + #[test] + fn struct_() { + assert_tokens( + &Flatten { + outer: 42, + data: NewtypeWrapper(Enum::Struct { + index: 0, + value: 42, + }), + }, + &[ + Token::Map { len: None }, + Token::Str("outer"), + Token::U32(42), + Token::Str("tag"), + Token::Str("Struct"), + Token::Str("content"), + Token::Struct { + len: 2, + name: "Struct", + }, + Token::Str("index"), + Token::U32(0), + Token::Str("value"), + Token::U32(42), + Token::StructEnd, + Token::MapEnd, + ], + ); + } + + #[test] + fn newtype() { + assert_tokens( + &Flatten { + outer: 42, + data: NewtypeWrapper(Enum::Newtype(NewtypeVariant { value: 23 })), + }, + &[ + Token::Map { len: None }, + Token::Str("outer"), + Token::U32(42), + Token::Str("tag"), + Token::Str("Newtype"), + Token::Str("content"), + Token::Struct { + len: 1, + name: "NewtypeVariant", + }, + Token::Str("value"), + Token::U32(23), + Token::StructEnd, + Token::MapEnd, + ], + ); + } + } + + mod internally_tagged { + use super::*; + + #[test] + fn structs() { + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct Flatten { + #[serde(flatten)] + x: X, + #[serde(flatten)] + y: Y, + } + + #[derive(Debug, PartialEq, Serialize, Deserialize)] + #[serde(tag = "typeX")] + enum X { + A { a: i32 }, + B { b: i32 }, + } + + #[derive(Debug, PartialEq, Serialize, Deserialize)] + #[serde(tag = "typeY")] + enum Y { + C { c: i32 }, + D { d: i32 }, + } + + assert_tokens( + &Flatten { + x: X::B { b: 1 }, + y: Y::D { d: 2 }, + }, + &[ + 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, + ], + ); + } + + #[test] + fn unit_enum_with_unknown_fields() { + #[derive(Debug, PartialEq, Deserialize)] + struct Flatten { + #[serde(flatten)] + x: X, + #[serde(flatten)] + y: Y, + } + + #[derive(Debug, PartialEq, Deserialize)] + #[serde(tag = "typeX")] + enum X { + A, + } + + #[derive(Debug, PartialEq, Deserialize)] + #[serde(tag = "typeY")] + enum Y { + B { c: u32 }, + } + + assert_de_tokens( + &Flatten { + x: X::A, + y: Y::B { c: 0 }, + }, + &[ + Token::Map { len: None }, + Token::Str("typeX"), + Token::Str("A"), + Token::Str("typeY"), + Token::Str("B"), + Token::Str("c"), + Token::I32(0), + Token::MapEnd, + ], + ); + } + } + + mod untagged { + use super::*; + + #[derive(Debug, PartialEq, Serialize, Deserialize)] + struct Flatten { + #[serde(flatten)] + data: Enum, + } + + #[derive(Debug, PartialEq, Serialize, Deserialize)] + #[serde(untagged)] + enum Enum { + Struct { a: i32 }, + } + + #[test] + fn struct_() { + assert_tokens( + &Flatten { + data: Enum::Struct { a: 0 }, + }, + &[ + Token::Map { len: None }, + Token::Str("a"), + Token::I32(0), + Token::MapEnd, + ], + ); + } + } + } +} diff --git a/test_suite/tests/test_macros.rs b/test_suite/tests/test_macros.rs index ac12b806..99a78ab4 100644 --- a/test_suite/tests/test_macros.rs +++ b/test_suite/tests/test_macros.rs @@ -1429,6 +1429,9 @@ fn test_enum_in_internally_tagged_enum() { ], ); + // Reaches crate::private::de::content::VariantDeserializer::tuple_variant + // Content::Seq case + // via ContentDeserializer::deserialize_enum assert_tokens( &Outer::Inner(Inner::Tuple(1, 1)), &[ @@ -1447,6 +1450,9 @@ fn test_enum_in_internally_tagged_enum() { ], ); + // Reaches crate::private::de::content::VariantDeserializer::struct_variant + // Content::Map case + // via ContentDeserializer::deserialize_enum assert_tokens( &Outer::Inner(Inner::Struct { f: 1 }), &[ @@ -1464,6 +1470,23 @@ fn test_enum_in_internally_tagged_enum() { Token::MapEnd, ], ); + + // Reaches crate::private::de::content::VariantDeserializer::struct_variant + // Content::Seq case + // via ContentDeserializer::deserialize_enum + assert_de_tokens( + &Outer::Inner(Inner::Struct { f: 1 }), + &[ + Token::Map { len: Some(2) }, + Token::Str("type"), + Token::Str("Inner"), + Token::Str("Struct"), + Token::Seq { len: Some(1) }, + Token::U8(1), // f + Token::SeqEnd, + Token::MapEnd, + ], + ); } #[test]