Skip to content

Commit

Permalink
Fix tafia#500: deserialize top-level sequence correctly as if it is a…
Browse files Browse the repository at this point in the history
… field annotated with `#[serde(rename = "$value")]`
  • Loading branch information
Mingun authored and Joseph Gilby committed Nov 5, 2022
1 parent 7db34f5 commit b96a7e9
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 54 deletions.
9 changes: 9 additions & 0 deletions Changelog.md
Expand Up @@ -18,6 +18,14 @@
In particular, that means that maps with numeric and numeric-like keys (for
example, `"42"`) no longer can be serialized because [XML name] cannot start
from a digit
- [#500]: Fix deserialization of top-level sequences of enums, like
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- list of enum Enum { A, B, С } -->
<A/>
<B/>
<C/>
```

### Misc Changes

Expand All @@ -44,6 +52,7 @@
Refer to [documentation] for details.

[#490]: https://github.com/tafia/quick-xml/pull/490
[#500]: https://github.com/tafia/quick-xml/issues/500
[XML name]: https://www.w3.org/TR/xml11/#NT-Name
[documentation]: https://docs.rs/quick-xml/0.27.0/quick_xml/de/index.html#difference-between-text-and-value-special-names

Expand Down
59 changes: 5 additions & 54 deletions src/de/seq.rs
Expand Up @@ -74,20 +74,6 @@ where
{
/// Deserializer used to deserialize sequence items
de: &'a mut Deserializer<'de, R>,
/// Filter that determines whether a tag is a part of this sequence.
///
/// When feature `overlapped-lists` is not activated, iteration will stop
/// when found a tag that does not pass this filter.
///
/// When feature `overlapped-lists` is activated, all tags, that not pass
/// this check, will be skipped.
filter: TagFilter<'de>,

/// Checkpoint after which all skipped events should be returned. All events,
/// that was skipped before creating this checkpoint, will still stay buffered
/// and will not be returned
#[cfg(feature = "overlapped-lists")]
checkpoint: usize,
}

impl<'a, 'de, R> TopLevelSeqAccess<'de, 'a, R>
Expand All @@ -96,29 +82,7 @@ where
{
/// Creates a new accessor to a top-level sequence of XML elements.
pub fn new(de: &'a mut Deserializer<'de, R>) -> Result<Self, DeError> {
let filter = if let DeEvent::Start(e) = de.peek()? {
// Clone is cheap if event borrows from the input
TagFilter::Include(e.clone())
} else {
TagFilter::Exclude(&[])
};
Ok(Self {
#[cfg(feature = "overlapped-lists")]
checkpoint: de.skip_checkpoint(),

de,
filter,
})
}
}

#[cfg(feature = "overlapped-lists")]
impl<'de, 'a, R> Drop for TopLevelSeqAccess<'de, 'a, R>
where
R: XmlRead<'de>,
{
fn drop(&mut self) {
self.de.start_replay(self.checkpoint);
Ok(Self { de })
}
}

Expand All @@ -132,24 +96,11 @@ where
where
T: DeserializeSeed<'de>,
{
let decoder = self.de.reader.decoder();
loop {
break match self.de.peek()? {
// If we see a tag that we not interested, skip it
#[cfg(feature = "overlapped-lists")]
DeEvent::Start(e) if !self.filter.is_suitable(e, decoder)? => {
self.de.skip()?;
continue;
}
// Stop iteration when list elements ends
#[cfg(not(feature = "overlapped-lists"))]
DeEvent::Start(e) if !self.filter.is_suitable(e, decoder)? => Ok(None),
DeEvent::End(_) => Ok(None),
DeEvent::Eof => Ok(None),
match self.de.peek()? {
DeEvent::Eof => Ok(None),

// Start(tag), Text, CData
_ => seed.deserialize(&mut *self.de).map(Some),
};
// Start(tag), End(tag), Text, CData
_ => seed.deserialize(&mut *self.de).map(Some),
}
}
}
Expand Down
20 changes: 20 additions & 0 deletions tests/serde-de.rs
Expand Up @@ -609,6 +609,26 @@ mod seq {
]
);
}

/// Test for https://github.com/tafia/quick-xml/issues/500
#[test]
fn list_of_enum() {
#[derive(Debug, PartialEq, Deserialize)]
enum Enum {
One,
Two,
}

let data: Vec<Enum> = from_str(
r#"
<One/>
<Two/>
<One/>
"#,
)
.unwrap();
assert_eq!(data, vec![Enum::One, Enum::Two, Enum::One]);
}
}

/// Tests where each sequence item have an identical name in an XML.
Expand Down

0 comments on commit b96a7e9

Please sign in to comment.