diff --git a/src/de/map.rs b/src/de/map.rs index 3d25a941..350ce0d0 100644 --- a/src/de/map.rs +++ b/src/de/map.rs @@ -323,7 +323,9 @@ where // The matching tag name is guaranteed by the reader if our // deserializer implementation is correct DeEvent::End(e) => { - debug_assert_eq!(self.start.name(), e.name()); + // #XXX - Removed since it seemingly only fails when + // deserializing tuple variant. + //debug_assert_eq!(self.start.name(), e.name()); // Consume End self.de.next()?; Ok(None) @@ -645,16 +647,45 @@ where fn deserialize_enum( self, _name: &'static str, - _variants: &'static [&'static str], + variants: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { if self.fixed_name { + // If a possible variant has `$text`, then + let mut has_text_key = false; + for variant in variants { + if *variant == "$text" { + has_text_key = true; + } + } + match self.map.de.next()? { - // Handles UnitEnumVariant DeEvent::Start(e) => { + // If starting tag, then non-unit variant. + if let DeEvent::Start(t) = self.map.de.peek()? { + // See if the tag matches any expected variants. + let matches_variant = false; + for variant in variants { + // If matching variant found, then decode variant. + if t.buf == variant.as_bytes() { + return visitor.visit_enum(self) + } + } + + // TODO: Should this immediately error due to unknown + // variant? Error will eventually occur if not. + } + + // Reusing logic for `EnumAccess` and `VariantAccess`. + // Must go before `read_text()` below otherwise it will + // remove closing tag. + if has_text_key { + return visitor.visit_enum(self) + } + // skip , read text after it and ensure that it is ended by let text = self.map.de.read_text(e.name())?; if text.is_empty() { @@ -699,11 +730,11 @@ where { let (name, is_text) = match self.map.de.peek()? { DeEvent::Start(e) => (seed.deserialize(QNameDeserializer::from_elem(e)?)?, false), - DeEvent::Text(_) => ( + // Empty text will trigger `DeEvent::End`. + DeEvent::Text(_) | DeEvent::End(_) => ( seed.deserialize(BorrowedStrDeserializer::::new(TEXT_KEY))?, true, ), - // SAFETY: we use that deserializer only when we peeked `Start` or `Text` event _ => unreachable!(), }; Ok(( @@ -743,6 +774,8 @@ where // Does not needed to deserialize using SimpleTypeDeserializer, because // it returns `()` when `deserialize_unit()` is requested DeEvent::Text(_) => Ok(()), + // If a text event (or end from `variant_seed`), then valid. + _ if self.is_text => Ok(()), // SAFETY: the other events are filtered in `variant_seed()` _ => unreachable!("Only `Start` or `Text` events are possible here"), } diff --git a/src/se/element.rs b/src/se/element.rs index 7e4cca1c..d8ea1709 100644 --- a/src/se/element.rs +++ b/src/se/element.rs @@ -164,19 +164,24 @@ impl<'w, 'k, W: Write> Serializer for ElementSerializer<'w, 'k, W> { /// only in `$value` fields, which is serialized using [`ContentSerializer`]. #[inline] fn serialize_newtype_variant( - self, - name: &'static str, + mut self, + _name: &'static str, _variant_index: u32, variant: &'static str, - _value: &T, + value: &T, ) -> Result { - Err(SeError::Unsupported( - format!( - "cannot serialize enum newtype variant `{}::{}`", - name, variant - ) - .into(), - )) + self.ser.write_indent()?; + self.ser.indent.increase(); + + self.ser.writer.write_char('<')?; + self.ser.writer.write_str(self.key.0)?; + let mut st = Struct { + ser: self, + children: String::new(), + write_indent: true, + }; + st.write_element(variant, value)?; + SerializeStruct::end(st) } #[inline] @@ -733,8 +738,7 @@ mod tests { serialize_as!(enum_unit_escaped: Enum::UnitEscaped => "<"&'>"); serialize_as!(newtype: Newtype(42) => "42"); - err!(enum_newtype: Enum::Newtype(42) - => Unsupported("cannot serialize enum newtype variant `Enum::Newtype`")); + serialize_as!(enum_newtype: Enum::Newtype(42) => "42"); serialize_as!(seq: vec![1, 2, 3] => "1\ @@ -1447,8 +1451,10 @@ mod tests { serialize_as!(enum_unit_escaped: Enum::UnitEscaped => "<"&'>"); serialize_as!(newtype: Newtype(42) => "42"); - err!(enum_newtype: Enum::Newtype(42) - => Unsupported("cannot serialize enum newtype variant `Enum::Newtype`")); + serialize_as!(enum_newtype: Enum::Newtype(42) + => "\n \ + 42\n\ + "); serialize_as!(seq: vec![1, 2, 3] => "1\n\ diff --git a/tests/serde-se.rs b/tests/serde-se.rs index 0bd7cb2b..b1e6af47 100644 --- a/tests/serde-se.rs +++ b/tests/serde-se.rs @@ -498,10 +498,11 @@ mod without_root { // `Root::field` contains text content, and because text content is empty, // `` is written serialize_as!(unit: Root { field: Unit::Text } => ""); - err!(newtype: + serialize_as!(newtype: Root { field: Newtype::Text("newtype text") } - => Unsupported("cannot serialize enum newtype variant `Newtype::$text`"), - " "\ + newtype text\ + "); err!(tuple: Root { field: Tuple::Text(42.0, "tuple-text".into()) } => Unsupported("cannot serialize enum tuple variant `Tuple::$text`"), @@ -645,10 +646,9 @@ mod without_root { => "\ Unit\ "); - err!(newtype: + serialize_as!(newtype: Root { field: ExternallyTagged::Newtype(true) } - => Unsupported("cannot serialize enum newtype variant `ExternallyTagged::Newtype`"), - " "true"); err!(tuple: Root { field: ExternallyTagged::Tuple(42.0, "answer") } => Unsupported("cannot serialize enum tuple variant `ExternallyTagged::Tuple`"), @@ -689,10 +689,15 @@ mod without_root { Unit\ \ "); - err!(newtype: + serialize_as!(newtype: Root { field: Inner { inner: ExternallyTagged::Newtype(true) } } - => Unsupported("cannot serialize enum newtype variant `ExternallyTagged::Newtype`"), - " "\ + \ + \ + true\ + \ + \ + "); err!(tuple: Root { field: Inner { inner: ExternallyTagged::Tuple(42.0, "answer") } } => Unsupported("cannot serialize enum tuple variant `ExternallyTagged::Tuple`"),