Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 38 additions & 5 deletions src/de/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Comment on lines +326 to +328
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it failed here, your code contains logical error.

// Consume End
self.de.next()?;
Ok(None)
Expand Down Expand Up @@ -645,16 +647,45 @@ where
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
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;
}
}
Comment on lines +658 to +663
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code conveys intent more clearly:

Suggested change
let mut has_text_key = false;
for variant in variants {
if *variant == "$text" {
has_text_key = true;
}
}
let has_text_key = variants.contains(TEXT_KEY);


match self.map.de.next()? {
// Handles <field>UnitEnumVariant</field>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That commend should be updated to show what XML shape processed here. This is required because the code became much more complicated

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() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is wrong check. buf is in t.decoder() encoding, while variant is in UTF-8.

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 <field>, read text after it and ensure that it is ended by </field>
let text = self.map.de.read_text(e.name())?;
if text.is_empty() {
Expand Down Expand Up @@ -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::<DeError>::new(TEXT_KEY))?,
true,
),
// SAFETY: we use that deserializer only when we peeked `Start` or `Text` event
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SAFETY markers shouldn't be removed. They should be updated with the explanation, why that code is unreachable.

_ => unreachable!(),
};
Ok((
Expand Down Expand Up @@ -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"),
}
Expand Down
34 changes: 20 additions & 14 deletions src/se/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T: ?Sized + Serialize>(
self,
name: &'static str,
mut self,
_name: &'static str,
_variant_index: u32,
variant: &'static str,
_value: &T,
value: &T,
) -> Result<Self::Ok, Self::Error> {
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]
Expand Down Expand Up @@ -733,8 +738,7 @@ mod tests {
serialize_as!(enum_unit_escaped: Enum::UnitEscaped => "<root>&lt;&quot;&amp;&apos;&gt;</root>");

serialize_as!(newtype: Newtype(42) => "<root>42</root>");
err!(enum_newtype: Enum::Newtype(42)
=> Unsupported("cannot serialize enum newtype variant `Enum::Newtype`"));
serialize_as!(enum_newtype: Enum::Newtype(42) => "<root><Newtype>42</Newtype></root>");

serialize_as!(seq: vec![1, 2, 3]
=> "<root>1</root>\
Expand Down Expand Up @@ -1447,8 +1451,10 @@ mod tests {
serialize_as!(enum_unit_escaped: Enum::UnitEscaped => "<root>&lt;&quot;&amp;&apos;&gt;</root>");

serialize_as!(newtype: Newtype(42) => "<root>42</root>");
err!(enum_newtype: Enum::Newtype(42)
=> Unsupported("cannot serialize enum newtype variant `Enum::Newtype`"));
serialize_as!(enum_newtype: Enum::Newtype(42)
=> "<root>\n \
<Newtype>42</Newtype>\n\
</root>");

serialize_as!(seq: vec![1, 2, 3]
=> "<root>1</root>\n\
Expand Down
23 changes: 14 additions & 9 deletions tests/serde-se.rs
Original file line number Diff line number Diff line change
Expand Up @@ -498,10 +498,11 @@ mod without_root {
// `Root::field` contains text content, and because text content is empty,
// `<field/>` is written
serialize_as!(unit: Root { field: Unit::Text } => "<Root><field/></Root>");
err!(newtype:
serialize_as!(newtype:
Root { field: Newtype::Text("newtype text") }
=> Unsupported("cannot serialize enum newtype variant `Newtype::$text`"),
"<Root");
=> "<Root>\
<field>newtype text</field>\
</Root>");
err!(tuple:
Root { field: Tuple::Text(42.0, "tuple-text".into()) }
=> Unsupported("cannot serialize enum tuple variant `Tuple::$text`"),
Expand Down Expand Up @@ -645,10 +646,9 @@ mod without_root {
=> "<Root>\
<field>Unit</field>\
</Root>");
err!(newtype:
serialize_as!(newtype:
Root { field: ExternallyTagged::Newtype(true) }
=> Unsupported("cannot serialize enum newtype variant `ExternallyTagged::Newtype`"),
"<Root");
=> "<Root><field><Newtype>true</Newtype></field></Root>");
err!(tuple:
Root { field: ExternallyTagged::Tuple(42.0, "answer") }
=> Unsupported("cannot serialize enum tuple variant `ExternallyTagged::Tuple`"),
Expand Down Expand Up @@ -689,10 +689,15 @@ mod without_root {
<inner>Unit</inner>\
</field>\
</Root>");
err!(newtype:
serialize_as!(newtype:
Root { field: Inner { inner: ExternallyTagged::Newtype(true) } }
=> Unsupported("cannot serialize enum newtype variant `ExternallyTagged::Newtype`"),
"<Root");
=> "<Root>\
<field>\
<inner>\
<Newtype>true</Newtype>\
</inner>\
</field>\
</Root>");
err!(tuple:
Root { field: Inner { inner: ExternallyTagged::Tuple(42.0, "answer") } }
=> Unsupported("cannot serialize enum tuple variant `ExternallyTagged::Tuple`"),
Expand Down
Loading