use serde::serde_if_integer128;
macro_rules! forward_to_simple_type {
($deserialize:ident, $($mut:tt)?) => {
#[inline]
fn $deserialize<V>($($mut)? self, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
SimpleTypeDeserializer::from_text(self.read_string()?).$deserialize(visitor)
}
};
}
macro_rules! deserialize_primitives {
($($mut:tt)?) => {
forward_to_simple_type!(deserialize_i8, $($mut)?);
forward_to_simple_type!(deserialize_i16, $($mut)?);
forward_to_simple_type!(deserialize_i32, $($mut)?);
forward_to_simple_type!(deserialize_i64, $($mut)?);
forward_to_simple_type!(deserialize_u8, $($mut)?);
forward_to_simple_type!(deserialize_u16, $($mut)?);
forward_to_simple_type!(deserialize_u32, $($mut)?);
forward_to_simple_type!(deserialize_u64, $($mut)?);
serde_if_integer128! {
forward_to_simple_type!(deserialize_i128, $($mut)?);
forward_to_simple_type!(deserialize_u128, $($mut)?);
}
forward_to_simple_type!(deserialize_f32, $($mut)?);
forward_to_simple_type!(deserialize_f64, $($mut)?);
forward_to_simple_type!(deserialize_bool, $($mut)?);
forward_to_simple_type!(deserialize_char, $($mut)?);
forward_to_simple_type!(deserialize_str, $($mut)?);
forward_to_simple_type!(deserialize_string, $($mut)?);
#[inline]
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
self.deserialize_any(visitor)
}
#[inline]
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
self.deserialize_bytes(visitor)
}
#[inline]
fn deserialize_unit_struct<V>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
self.deserialize_unit(visitor)
}
#[inline]
fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
self.deserialize_seq(visitor)
}
#[inline]
fn deserialize_tuple_struct<V>(
self,
_name: &'static str,
len: usize,
visitor: V,
) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
self.deserialize_tuple(len, visitor)
}
#[inline]
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
self.deserialize_struct("", &[], visitor)
}
#[inline]
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
self.deserialize_str(visitor)
}
#[inline]
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
self.deserialize_unit(visitor)
}
};
}
mod attributes;
mod key;
mod map;
mod resolver;
mod simple_type;
mod text;
mod var;
pub use self::attributes::AttributesDeserializer;
pub use self::resolver::{EntityResolver, PredefinedEntityResolver};
pub use self::simple_type::SimpleTypeDeserializer;
pub use crate::errors::serialize::DeError;
use crate::{
de::map::ElementMapAccess,
encoding::Decoder,
errors::Error,
escape::{parse_number, EscapeError},
events::{BytesCData, BytesEnd, BytesRef, BytesStart, BytesText, Event},
name::QName,
reader::NsReader,
};
use serde::de::{
self, Deserialize, DeserializeOwned, DeserializeSeed, IntoDeserializer, SeqAccess, Visitor,
};
use std::borrow::Cow;
#[cfg(feature = "overlapped-lists")]
use std::collections::VecDeque;
use std::io::BufRead;
use std::mem::replace;
#[cfg(feature = "overlapped-lists")]
use std::num::NonZeroUsize;
use std::ops::{Deref, Range};
pub(crate) const TEXT_KEY: &str = "$text";
pub(crate) const VALUE_KEY: &str = "$value";
#[inline]
const fn is_non_whitespace(ch: char) -> bool {
!matches!(ch, ' ' | '\r' | '\n' | '\t')
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Text<'a> {
text: Cow<'a, str>,
content: Range<usize>,
}
impl<'a> Text<'a> {
fn new(text: Cow<'a, str>) -> Self {
let start = text.find(is_non_whitespace).unwrap_or(0);
let end = text.rfind(is_non_whitespace).map_or(0, |i| i + 1);
let content = if start >= end { 0..0 } else { start..end };
Self { text, content }
}
pub fn trimmed(&self) -> Cow<'a, str> {
match self.text {
Cow::Borrowed(text) => Cow::Borrowed(&text[self.content.clone()]),
Cow::Owned(ref text) => Cow::Owned(text[self.content.clone()].to_string()),
}
}
pub fn is_blank(&self) -> bool {
self.content.is_empty()
}
}
impl<'a> Deref for Text<'a> {
type Target = str;
#[inline]
fn deref(&self) -> &Self::Target {
self.text.deref()
}
}
impl<'a> From<&'a str> for Text<'a> {
#[inline]
fn from(text: &'a str) -> Self {
Self::new(Cow::Borrowed(text))
}
}
impl<'a> From<String> for Text<'a> {
#[inline]
fn from(text: String) -> Self {
Self::new(Cow::Owned(text))
}
}
impl<'a> From<Cow<'a, str>> for Text<'a> {
#[inline]
fn from(text: Cow<'a, str>) -> Self {
Self::new(text)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum DeEvent<'a> {
Start(BytesStart<'a>),
End(BytesEnd<'a>),
Text(Text<'a>),
Eof,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum PayloadEvent<'a> {
Start(BytesStart<'a>),
End(BytesEnd<'a>),
Text(BytesText<'a>),
CData(BytesCData<'a>),
DocType(BytesText<'a>),
GeneralRef(BytesRef<'a>),
Eof,
}
impl<'a> PayloadEvent<'a> {
#[inline]
fn into_owned(self) -> PayloadEvent<'static> {
match self {
PayloadEvent::Start(e) => PayloadEvent::Start(e.into_owned()),
PayloadEvent::End(e) => PayloadEvent::End(e.into_owned()),
PayloadEvent::Text(e) => PayloadEvent::Text(e.into_owned()),
PayloadEvent::CData(e) => PayloadEvent::CData(e.into_owned()),
PayloadEvent::DocType(e) => PayloadEvent::DocType(e.into_owned()),
PayloadEvent::GeneralRef(e) => PayloadEvent::GeneralRef(e.into_owned()),
PayloadEvent::Eof => PayloadEvent::Eof,
}
}
}
struct XmlReader<'i, R: XmlRead<'i>, E: EntityResolver = PredefinedEntityResolver> {
reader: R,
lookahead: Result<PayloadEvent<'i>, DeError>,
entity_resolver: E,
}
impl<'i, R: XmlRead<'i>, E: EntityResolver> XmlReader<'i, R, E> {
fn new(mut reader: R, entity_resolver: E) -> Self {
let lookahead = reader.next();
Self {
reader,
lookahead,
entity_resolver,
}
}
const fn is_empty(&self) -> bool {
matches!(self.lookahead, Ok(PayloadEvent::Eof))
}
#[inline(always)]
fn next_impl(&mut self) -> Result<PayloadEvent<'i>, DeError> {
replace(&mut self.lookahead, self.reader.next())
}
#[inline(always)]
const fn current_event_is_last_text(&self) -> bool {
!matches!(
self.lookahead,
Ok(PayloadEvent::Text(_)) | Ok(PayloadEvent::CData(_) | PayloadEvent::GeneralRef(_))
)
}
fn drain_text(&mut self, mut result: Cow<'i, str>) -> Result<DeEvent<'i>, DeError> {
loop {
if self.current_event_is_last_text() {
break;
}
match self.next_impl()? {
PayloadEvent::Text(e) => result.to_mut().push_str(&e.xml_content()?),
PayloadEvent::CData(e) => result.to_mut().push_str(&e.xml_content()?),
PayloadEvent::GeneralRef(e) => self.resolve_reference(result.to_mut(), e)?,
_ => unreachable!("Only `Text`, `CData` or `GeneralRef` events can come here"),
}
}
Ok(DeEvent::Text(Text::new(result)))
}
fn next(&mut self) -> Result<DeEvent<'i>, DeError> {
loop {
return match self.next_impl()? {
PayloadEvent::Start(e) => Ok(DeEvent::Start(e)),
PayloadEvent::End(e) => Ok(DeEvent::End(e)),
PayloadEvent::Text(e) => self.drain_text(e.xml_content()?),
PayloadEvent::CData(e) => self.drain_text(e.xml_content()?),
PayloadEvent::DocType(e) => {
self.entity_resolver
.capture(e)
.map_err(|err| DeError::Custom(format!("cannot parse DTD: {}", err)))?;
continue;
}
PayloadEvent::GeneralRef(e) => {
let mut text = String::new();
self.resolve_reference(&mut text, e)?;
self.drain_text(text.into())
}
PayloadEvent::Eof => Ok(DeEvent::Eof),
};
}
}
fn resolve_reference(&mut self, result: &mut String, event: BytesRef) -> Result<(), DeError> {
let len = event.len();
let reference = self.decoder().decode(&event)?;
if let Some(num) = reference.strip_prefix('#') {
let codepoint = parse_number(num).map_err(EscapeError::InvalidCharRef)?;
result.push_str(codepoint.encode_utf8(&mut [0u8; 4]));
return Ok(());
}
if let Some(value) = self.entity_resolver.resolve(reference.as_ref()) {
result.push_str(value);
return Ok(());
}
Err(EscapeError::UnrecognizedEntity(0..len, reference.to_string()).into())
}
#[inline]
fn read_to_end(&mut self, name: QName) -> Result<(), DeError> {
match self.lookahead {
Ok(PayloadEvent::Start(ref e)) if e.name() == name => {
let result1 = self.reader.read_to_end(name);
let result2 = self.reader.read_to_end(name);
let _ = self.next_impl();
result1?;
result2?;
}
Ok(PayloadEvent::End(ref e)) if e.name() == name => {
let _ = self.next_impl();
}
Ok(_) => {
let result = self.reader.read_to_end(name);
let _ = self.next_impl();
result?;
}
Err(_) => {
self.next_impl()?;
}
}
Ok(())
}
#[inline]
fn decoder(&self) -> Decoder {
self.reader.decoder()
}
}
pub fn from_str<'de, T>(s: &'de str) -> Result<T, DeError>
where
T: Deserialize<'de>,
{
let mut de = Deserializer::from_str(s);
T::deserialize(&mut de)
}
pub fn from_reader<R, T>(reader: R) -> Result<T, DeError>
where
R: BufRead,
T: DeserializeOwned,
{
let mut de = Deserializer::from_reader(reader);
T::deserialize(&mut de)
}
pub struct Deserializer<'de, R, E: EntityResolver = PredefinedEntityResolver>
where
R: XmlRead<'de>,
{
reader: XmlReader<'de, R, E>,
#[cfg(feature = "overlapped-lists")]
read: VecDeque<DeEvent<'de>>,
#[cfg(feature = "overlapped-lists")]
write: VecDeque<DeEvent<'de>>,
#[cfg(feature = "overlapped-lists")]
limit: Option<NonZeroUsize>,
#[cfg(not(feature = "overlapped-lists"))]
peek: Option<DeEvent<'de>>,
key_buf: String,
}
impl<'de, R, E> Deserializer<'de, R, E>
where
R: XmlRead<'de>,
E: EntityResolver,
{
fn new(reader: R, entity_resolver: E) -> Self {
Self {
reader: XmlReader::new(reader, entity_resolver),
#[cfg(feature = "overlapped-lists")]
read: VecDeque::new(),
#[cfg(feature = "overlapped-lists")]
write: VecDeque::new(),
#[cfg(feature = "overlapped-lists")]
limit: None,
#[cfg(not(feature = "overlapped-lists"))]
peek: None,
key_buf: String::new(),
}
}
pub fn is_empty(&self) -> bool {
#[cfg(feature = "overlapped-lists")]
let event = self.read.front();
#[cfg(not(feature = "overlapped-lists"))]
let event = self.peek.as_ref();
match event {
None | Some(DeEvent::Eof) => self.reader.is_empty(),
_ => false,
}
}
pub const fn get_ref(&self) -> &R {
&self.reader.reader
}
#[cfg(feature = "overlapped-lists")]
pub fn event_buffer_size(&mut self, limit: Option<NonZeroUsize>) -> &mut Self {
self.limit = limit;
self
}
#[cfg(feature = "overlapped-lists")]
fn peek(&mut self) -> Result<&DeEvent<'de>, DeError> {
if self.read.is_empty() {
self.read.push_front(self.reader.next()?);
}
if let Some(event) = self.read.front() {
return Ok(event);
}
unreachable!()
}
#[cfg(not(feature = "overlapped-lists"))]
fn peek(&mut self) -> Result<&DeEvent<'de>, DeError> {
match &mut self.peek {
Some(event) => Ok(event),
empty_peek @ None => Ok(empty_peek.insert(self.reader.next()?)),
}
}
#[inline]
fn last_peeked(&self) -> &DeEvent<'de> {
#[cfg(feature = "overlapped-lists")]
{
self.read
.front()
.expect("`Deserializer::peek()` should be called")
}
#[cfg(not(feature = "overlapped-lists"))]
{
self.peek
.as_ref()
.expect("`Deserializer::peek()` should be called")
}
}
fn next(&mut self) -> Result<DeEvent<'de>, DeError> {
#[cfg(feature = "overlapped-lists")]
if let Some(event) = self.read.pop_front() {
return Ok(event);
}
#[cfg(not(feature = "overlapped-lists"))]
if let Some(e) = self.peek.take() {
return Ok(e);
}
self.reader.next()
}
fn skip_whitespaces(&mut self) -> Result<(), DeError> {
loop {
match self.peek()? {
DeEvent::Text(e) if e.is_blank() => {
self.next()?;
}
_ => break,
}
}
Ok(())
}
#[cfg(feature = "overlapped-lists")]
#[inline]
#[must_use = "returned checkpoint should be used in `start_replay`"]
fn skip_checkpoint(&self) -> usize {
self.write.len()
}
#[cfg(feature = "overlapped-lists")]
fn skip(&mut self) -> Result<(), DeError> {
let event = self.next()?;
self.skip_event(event)?;
if let Some(DeEvent::Start(e)) = self.write.back() {
let end = e.name().as_ref().to_owned();
let mut depth = 0;
loop {
let event = self.next()?;
match event {
DeEvent::Start(ref e) if e.name().as_ref() == end => {
self.skip_event(event)?;
depth += 1;
}
DeEvent::End(ref e) if e.name().as_ref() == end => {
self.skip_event(event)?;
if depth == 0 {
break;
}
depth -= 1;
}
DeEvent::Eof => {
self.skip_event(event)?;
break;
}
_ => self.skip_event(event)?,
}
}
}
Ok(())
}
#[cfg(feature = "overlapped-lists")]
#[inline]
fn skip_event(&mut self, event: DeEvent<'de>) -> Result<(), DeError> {
if let Some(max) = self.limit {
if self.write.len() >= max.get() {
return Err(DeError::TooManyEvents(max));
}
}
self.write.push_back(event);
Ok(())
}
#[cfg(feature = "overlapped-lists")]
fn start_replay(&mut self, checkpoint: usize) {
if checkpoint == 0 {
self.write.append(&mut self.read);
std::mem::swap(&mut self.read, &mut self.write);
} else {
let mut read = self.write.split_off(checkpoint);
read.append(&mut self.read);
self.read = read;
}
}
#[inline]
fn read_string(&mut self) -> Result<Cow<'de, str>, DeError> {
self.read_string_impl(true)
}
fn read_string_impl(&mut self, allow_start: bool) -> Result<Cow<'de, str>, DeError> {
match self.next()? {
DeEvent::Text(e) => Ok(e.text),
DeEvent::Start(e) if allow_start => self.read_text(e.name()),
DeEvent::Start(e) => Err(DeError::UnexpectedStart(e.name().as_ref().to_owned())),
DeEvent::End(e) => unreachable!("{:?}", e),
DeEvent::Eof => Err(DeError::UnexpectedEof),
}
}
fn read_text(&mut self, name: QName) -> Result<Cow<'de, str>, DeError> {
match self.next()? {
DeEvent::Text(e) => match self.next()? {
DeEvent::End(_) => Ok(e.text),
DeEvent::Text(_) => unreachable!(),
DeEvent::Start(e) => Err(DeError::UnexpectedStart(e.name().as_ref().to_owned())),
DeEvent::Eof => Err(Error::missed_end(name, self.reader.decoder()).into()),
},
DeEvent::End(_) => Ok("".into()),
DeEvent::Start(s) => Err(DeError::UnexpectedStart(s.name().as_ref().to_owned())),
DeEvent::Eof => Err(Error::missed_end(name, self.reader.decoder()).into()),
}
}
#[cfg(feature = "overlapped-lists")]
fn read_to_end(&mut self, name: QName) -> Result<(), DeError> {
let mut depth = 0;
loop {
match self.read.pop_front() {
Some(DeEvent::Start(e)) if e.name() == name => {
depth += 1;
}
Some(DeEvent::End(e)) if e.name() == name => {
if depth == 0 {
break;
}
depth -= 1;
}
Some(_) => continue,
None => {
loop {
self.reader.read_to_end(name)?;
if depth == 0 {
break;
}
depth -= 1;
}
break;
}
}
}
Ok(())
}
#[cfg(not(feature = "overlapped-lists"))]
fn read_to_end(&mut self, name: QName) -> Result<(), DeError> {
match self.next()? {
DeEvent::Start(e) => self.reader.read_to_end(e.name())?,
DeEvent::End(e) if e.name() == name => return Ok(()),
_ => (),
}
self.reader.read_to_end(name)
}
fn skip_next_tree(&mut self) -> Result<(), DeError> {
let DeEvent::Start(start) = self.next()? else {
unreachable!("Only call this if the next event is a start event")
};
let name = start.name();
self.read_to_end(name)
}
#[doc(hidden)]
#[track_caller]
pub fn check_eof_reached(&mut self) {
self.skip_whitespaces().expect("cannot skip whitespaces");
let event = self.peek().expect("cannot peek event");
assert_eq!(
*event,
DeEvent::Eof,
"the whole XML document should be consumed, expected `Eof`",
);
}
}
impl<'de> Deserializer<'de, SliceReader<'de>> {
#[allow(clippy::should_implement_trait)]
pub fn from_str(source: &'de str) -> Self {
Self::from_str_with_resolver(source, PredefinedEntityResolver)
}
#[inline]
pub fn borrowing(reader: NsReader<&'de [u8]>) -> Self {
Self::borrowing_with_resolver(reader, PredefinedEntityResolver)
}
}
impl<'de, E> Deserializer<'de, SliceReader<'de>, E>
where
E: EntityResolver,
{
pub fn from_str_with_resolver(source: &'de str, entity_resolver: E) -> Self {
Self::borrowing_with_resolver(NsReader::from_str(source), entity_resolver)
}
pub fn borrowing_with_resolver(mut reader: NsReader<&'de [u8]>, entity_resolver: E) -> Self {
let config = reader.config_mut();
config.expand_empty_elements = true;
Self::new(SliceReader { reader }, entity_resolver)
}
}
impl<'de, R> Deserializer<'de, IoReader<R>>
where
R: BufRead,
{
pub fn from_reader(reader: R) -> Self {
Self::with_resolver(reader, PredefinedEntityResolver)
}
#[inline]
pub fn buffering(reader: NsReader<R>) -> Self {
Self::buffering_with_resolver(reader, PredefinedEntityResolver)
}
}
impl<'de, R, E> Deserializer<'de, IoReader<R>, E>
where
R: BufRead,
E: EntityResolver,
{
pub fn with_resolver(reader: R, entity_resolver: E) -> Self {
let mut reader = NsReader::from_reader(reader);
let config = reader.config_mut();
config.expand_empty_elements = true;
Self::new(
IoReader {
reader,
buf: Vec::new(),
},
entity_resolver,
)
}
pub fn buffering_with_resolver(mut reader: NsReader<R>, entity_resolver: E) -> Self {
let config = reader.config_mut();
config.expand_empty_elements = true;
Self::new(
IoReader {
reader,
buf: Vec::new(),
},
entity_resolver,
)
}
}
impl<'de, R, E> de::Deserializer<'de> for &mut Deserializer<'de, R, E>
where
R: XmlRead<'de>,
E: EntityResolver,
{
type Error = DeError;
deserialize_primitives!();
fn deserialize_struct<V>(
self,
_name: &'static str,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
self.skip_whitespaces()?;
match self.next()? {
DeEvent::Start(e) => visitor.visit_map(ElementMapAccess::new(self, e, fields)),
DeEvent::End(e) => unreachable!("{:?}", e),
DeEvent::Text(e) => match e.text {
Cow::Borrowed(s) => visitor.visit_borrowed_str(s),
Cow::Owned(s) => visitor.visit_string(s),
},
DeEvent::Eof => Err(DeError::UnexpectedEof),
}
}
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
match self.next()? {
DeEvent::Start(s) => {
self.read_to_end(s.name())?;
visitor.visit_unit()
}
DeEvent::Text(_) => visitor.visit_unit(),
DeEvent::End(e) => unreachable!("{:?}", e),
DeEvent::Eof => Err(DeError::UnexpectedEof),
}
}
fn deserialize_newtype_struct<V>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
visitor.visit_newtype_struct(self)
}
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
self.skip_whitespaces()?;
visitor.visit_enum(var::EnumAccess::new(self))
}
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
visitor.visit_seq(self)
}
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
let _ = self.peek()?;
match self.last_peeked() {
DeEvent::Text(t) if t.is_empty() => visitor.visit_none(),
DeEvent::Eof => visitor.visit_none(),
DeEvent::Start(start) if self.reader.reader.has_nil_attr(start) => {
self.skip_next_tree()?;
visitor.visit_none()
}
_ => visitor.visit_some(self),
}
}
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, DeError>
where
V: Visitor<'de>,
{
match self.peek()? {
DeEvent::Text(_) => self.deserialize_str(visitor),
_ => self.deserialize_map(visitor),
}
}
}
impl<'de, R, E> SeqAccess<'de> for &mut Deserializer<'de, R, E>
where
R: XmlRead<'de>,
E: EntityResolver,
{
type Error = DeError;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where
T: DeserializeSeed<'de>,
{
self.skip_whitespaces()?;
match self.peek()? {
DeEvent::Eof => Ok(None),
_ => seed.deserialize(&mut **self).map(Some),
}
}
}
impl<'de, R, E> IntoDeserializer<'de, DeError> for &mut Deserializer<'de, R, E>
where
R: XmlRead<'de>,
E: EntityResolver,
{
type Deserializer = Self;
#[inline]
fn into_deserializer(self) -> Self {
self
}
}
#[inline(always)]
fn skip_uninterested<'a>(event: Event<'a>) -> Option<PayloadEvent<'a>> {
let event = match event {
Event::DocType(e) => PayloadEvent::DocType(e),
Event::Start(e) => PayloadEvent::Start(e),
Event::End(e) => PayloadEvent::End(e),
Event::Eof => PayloadEvent::Eof,
Event::CData(e) => PayloadEvent::CData(e),
Event::Text(e) => PayloadEvent::Text(e),
Event::GeneralRef(e) => PayloadEvent::GeneralRef(e),
_ => return None,
};
Some(event)
}
pub trait XmlRead<'i> {
fn next(&mut self) -> Result<PayloadEvent<'i>, DeError>;
fn read_to_end(&mut self, name: QName) -> Result<(), DeError>;
fn decoder(&self) -> Decoder;
fn has_nil_attr(&self, start: &BytesStart) -> bool;
}
pub struct IoReader<R: BufRead> {
reader: NsReader<R>,
buf: Vec<u8>,
}
impl<R: BufRead> IoReader<R> {
pub const fn get_ref(&self) -> &NsReader<R> {
&self.reader
}
}
impl<'i, R: BufRead> XmlRead<'i> for IoReader<R> {
fn next(&mut self) -> Result<PayloadEvent<'static>, DeError> {
loop {
self.buf.clear();
let event = self.reader.read_event_into(&mut self.buf)?;
if let Some(event) = skip_uninterested(event) {
return Ok(event.into_owned());
}
}
}
fn read_to_end(&mut self, name: QName) -> Result<(), DeError> {
match self.reader.read_to_end_into(name, &mut self.buf) {
Err(e) => Err(e.into()),
Ok(_) => Ok(()),
}
}
fn decoder(&self) -> Decoder {
self.reader.decoder()
}
fn has_nil_attr(&self, start: &BytesStart) -> bool {
start.attributes().has_nil(&self.reader)
}
}
pub struct SliceReader<'de> {
reader: NsReader<&'de [u8]>,
}
impl<'de> SliceReader<'de> {
pub const fn get_ref(&self) -> &NsReader<&'de [u8]> {
&self.reader
}
}
impl<'de> XmlRead<'de> for SliceReader<'de> {
fn next(&mut self) -> Result<PayloadEvent<'de>, DeError> {
loop {
let event = self.reader.read_event()?;
if let Some(event) = skip_uninterested(event) {
return Ok(event);
}
}
}
fn read_to_end(&mut self, name: QName) -> Result<(), DeError> {
match self.reader.read_to_end(name) {
Err(e) => Err(e.into()),
Ok(_) => Ok(()),
}
}
fn decoder(&self) -> Decoder {
self.reader.decoder()
}
fn has_nil_attr(&self, start: &BytesStart) -> bool {
start.attributes().has_nil(&self.reader)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::errors::IllFormedError;
use pretty_assertions::assert_eq;
fn make_de<'de>(source: &'de str) -> Deserializer<'de, SliceReader<'de>> {
dbg!(source);
Deserializer::from_str(source)
}
#[cfg(feature = "overlapped-lists")]
mod skip {
use super::*;
use crate::de::DeEvent::*;
use crate::events::BytesEnd;
use pretty_assertions::assert_eq;
#[test]
fn read_and_peek() {
let mut de = make_de(
"\
<root>\
<inner>\
text\
<inner/>\
</inner>\
<next/>\
<target/>\
</root>\
",
);
assert_eq!(de.read, vec![]);
assert_eq!(de.write, vec![]);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("root")));
assert_eq!(de.peek().unwrap(), &Start(BytesStart::new("inner")));
let checkpoint = de.skip_checkpoint();
assert_eq!(checkpoint, 0);
de.skip().unwrap();
assert_eq!(de.read, vec![]);
assert_eq!(
de.write,
vec![
Start(BytesStart::new("inner")),
Text("text".into()),
Start(BytesStart::new("inner")),
End(BytesEnd::new("inner")),
End(BytesEnd::new("inner")),
]
);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("next")));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("next")));
de.start_replay(checkpoint);
assert_eq!(
de.read,
vec![
Start(BytesStart::new("inner")),
Text("text".into()),
Start(BytesStart::new("inner")),
End(BytesEnd::new("inner")),
End(BytesEnd::new("inner")),
]
);
assert_eq!(de.write, vec![]);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("inner")));
let checkpoint = de.skip_checkpoint();
assert_eq!(checkpoint, 0);
de.skip().unwrap();
assert_eq!(
de.read,
vec![
Start(BytesStart::new("inner")),
End(BytesEnd::new("inner")),
End(BytesEnd::new("inner")),
]
);
assert_eq!(
de.write,
vec![
Text("text".into()),
]
);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("inner")));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("inner")));
de.start_replay(checkpoint);
assert_eq!(
de.read,
vec![
Text("text".into()),
End(BytesEnd::new("inner")),
]
);
assert_eq!(de.write, vec![]);
assert_eq!(de.next().unwrap(), Text("text".into()));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("inner")));
assert_eq!(de.next().unwrap(), Start(BytesStart::new("target")));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("target")));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("root")));
assert_eq!(de.next().unwrap(), Eof);
}
#[test]
fn read_to_end() {
let mut de = make_de(
"\
<root>\
<skip>\
text\
<skip/>\
</skip>\
<target>\
<target/>\
</target>\
</root>\
",
);
assert_eq!(de.read, vec![]);
assert_eq!(de.write, vec![]);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("root")));
let checkpoint = de.skip_checkpoint();
assert_eq!(checkpoint, 0);
de.skip().unwrap();
assert_eq!(de.read, vec![]);
assert_eq!(
de.write,
vec![
Start(BytesStart::new("skip")),
Text("text".into()),
Start(BytesStart::new("skip")),
End(BytesEnd::new("skip")),
End(BytesEnd::new("skip")),
]
);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("target")));
de.read_to_end(QName(b"target")).unwrap();
assert_eq!(de.read, vec![]);
assert_eq!(
de.write,
vec![
Start(BytesStart::new("skip")),
Text("text".into()),
Start(BytesStart::new("skip")),
End(BytesEnd::new("skip")),
End(BytesEnd::new("skip")),
]
);
de.start_replay(checkpoint);
assert_eq!(
de.read,
vec![
Start(BytesStart::new("skip")),
Text("text".into()),
Start(BytesStart::new("skip")),
End(BytesEnd::new("skip")),
End(BytesEnd::new("skip")),
]
);
assert_eq!(de.write, vec![]);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("skip")));
de.read_to_end(QName(b"skip")).unwrap();
assert_eq!(de.next().unwrap(), End(BytesEnd::new("root")));
assert_eq!(de.next().unwrap(), Eof);
}
#[test]
fn partial_replay() {
let mut de = make_de(
"\
<root>\
<skipped-1/>\
<skipped-2/>\
<inner>\
<skipped-3/>\
<skipped-4/>\
<target-2/>\
</inner>\
<target-1/>\
</root>\
",
);
assert_eq!(de.read, vec![]);
assert_eq!(de.write, vec![]);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("root")));
let checkpoint1 = de.skip_checkpoint();
assert_eq!(checkpoint1, 0);
de.skip().unwrap(); de.skip().unwrap(); assert_eq!(de.read, vec![]);
assert_eq!(
de.write,
vec![
Start(BytesStart::new("skipped-1")),
End(BytesEnd::new("skipped-1")),
Start(BytesStart::new("skipped-2")),
End(BytesEnd::new("skipped-2")),
]
);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("inner")));
assert_eq!(de.peek().unwrap(), &Start(BytesStart::new("skipped-3")));
assert_eq!(
de.read,
vec![
Start(BytesStart::new("skipped-3")),
]
);
assert_eq!(
de.write,
vec![
Start(BytesStart::new("skipped-1")),
End(BytesEnd::new("skipped-1")),
Start(BytesStart::new("skipped-2")),
End(BytesEnd::new("skipped-2")),
]
);
let checkpoint2 = de.skip_checkpoint();
assert_eq!(checkpoint2, 4);
de.skip().unwrap(); de.skip().unwrap(); assert_eq!(de.read, vec![]);
assert_eq!(
de.write,
vec![
Start(BytesStart::new("skipped-1")),
End(BytesEnd::new("skipped-1")),
Start(BytesStart::new("skipped-2")),
End(BytesEnd::new("skipped-2")),
Start(BytesStart::new("skipped-3")),
End(BytesEnd::new("skipped-3")),
Start(BytesStart::new("skipped-4")),
End(BytesEnd::new("skipped-4")),
]
);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("target-2")));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("target-2")));
assert_eq!(de.peek().unwrap(), &End(BytesEnd::new("inner")));
assert_eq!(
de.read,
vec![
End(BytesEnd::new("inner")),
]
);
assert_eq!(
de.write,
vec![
Start(BytesStart::new("skipped-1")),
End(BytesEnd::new("skipped-1")),
Start(BytesStart::new("skipped-2")),
End(BytesEnd::new("skipped-2")),
Start(BytesStart::new("skipped-3")),
End(BytesEnd::new("skipped-3")),
Start(BytesStart::new("skipped-4")),
End(BytesEnd::new("skipped-4")),
]
);
de.start_replay(checkpoint2);
assert_eq!(
de.read,
vec![
Start(BytesStart::new("skipped-3")),
End(BytesEnd::new("skipped-3")),
Start(BytesStart::new("skipped-4")),
End(BytesEnd::new("skipped-4")),
End(BytesEnd::new("inner")),
]
);
assert_eq!(
de.write,
vec![
Start(BytesStart::new("skipped-1")),
End(BytesEnd::new("skipped-1")),
Start(BytesStart::new("skipped-2")),
End(BytesEnd::new("skipped-2")),
]
);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("skipped-3")));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("skipped-3")));
assert_eq!(de.next().unwrap(), Start(BytesStart::new("skipped-4")));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("skipped-4")));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("inner")));
assert_eq!(de.read, vec![]);
assert_eq!(
de.write,
vec![
Start(BytesStart::new("skipped-1")),
End(BytesEnd::new("skipped-1")),
Start(BytesStart::new("skipped-2")),
End(BytesEnd::new("skipped-2")),
]
);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("target-1")));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("target-1")));
assert_eq!(de.read, vec![]);
assert_eq!(
de.write,
vec![
Start(BytesStart::new("skipped-1")),
End(BytesEnd::new("skipped-1")),
Start(BytesStart::new("skipped-2")),
End(BytesEnd::new("skipped-2")),
]
);
de.start_replay(checkpoint1);
assert_eq!(
de.read,
vec![
Start(BytesStart::new("skipped-1")),
End(BytesEnd::new("skipped-1")),
Start(BytesStart::new("skipped-2")),
End(BytesEnd::new("skipped-2")),
]
);
assert_eq!(de.write, vec![]);
assert_eq!(de.next().unwrap(), Start(BytesStart::new("skipped-1")));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("skipped-1")));
assert_eq!(de.next().unwrap(), Start(BytesStart::new("skipped-2")));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("skipped-2")));
assert_eq!(de.read, vec![]);
assert_eq!(de.write, vec![]);
assert_eq!(de.next().unwrap(), End(BytesEnd::new("root")));
assert_eq!(de.next().unwrap(), Eof);
}
#[test]
fn limit() {
use serde::Deserialize;
#[derive(Debug, Deserialize)]
#[allow(unused)]
struct List {
item: Vec<()>,
}
let mut de = make_de(
"\
<any-name>\
<item/>\
<another-item>\
<some-element>with text</some-element>\
<yet-another-element/>\
</another-item>\
<item/>\
<item/>\
</any-name>\
",
);
de.event_buffer_size(NonZeroUsize::new(3));
match List::deserialize(&mut de) {
Err(DeError::TooManyEvents(count)) => assert_eq!(count.get(), 3),
e => panic!("Expected `Err(TooManyEvents(3))`, but got `{:?}`", e),
}
}
#[test]
fn invalid_xml() {
use crate::de::DeEvent::*;
let mut de = make_de("<root>");
let checkpoint = de.skip_checkpoint();
de.skip().unwrap();
de.start_replay(checkpoint);
assert_eq!(de.read, vec![Start(BytesStart::new("root")), Eof]);
}
}
mod read_to_end {
use super::*;
use crate::de::DeEvent::*;
use pretty_assertions::assert_eq;
#[test]
fn complex() {
let mut de = make_de(
r#"
<root>
<tag a="1"><tag>text</tag>content</tag>
<tag a="2"><![CDATA[cdata content]]></tag>
<self-closed/>
</root>
"#,
);
assert_eq!(de.next().unwrap(), Text("\n ".into()));
assert_eq!(de.next().unwrap(), Start(BytesStart::new("root")));
assert_eq!(de.next().unwrap(), Text("\n ".into()));
assert_eq!(
de.next().unwrap(),
Start(BytesStart::from_content(r#"tag a="1""#, 3))
);
assert_eq!(de.read_to_end(QName(b"tag")).unwrap(), ());
assert_eq!(de.next().unwrap(), Text("\n ".into()));
assert_eq!(
de.next().unwrap(),
Start(BytesStart::from_content(r#"tag a="2""#, 3))
);
assert_eq!(de.next().unwrap(), Text("cdata content".into()));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("tag")));
assert_eq!(de.next().unwrap(), Text("\n ".into()));
assert_eq!(de.next().unwrap(), Start(BytesStart::new("self-closed")));
assert_eq!(de.read_to_end(QName(b"self-closed")).unwrap(), ());
assert_eq!(de.next().unwrap(), Text("\n ".into()));
assert_eq!(de.next().unwrap(), End(BytesEnd::new("root")));
assert_eq!(de.next().unwrap(), Text("\n ".into()));
assert_eq!(de.next().unwrap(), Eof);
}
#[test]
fn invalid_xml1() {
let mut de = make_de("<tag><tag></tag>");
assert_eq!(de.next().unwrap(), Start(BytesStart::new("tag")));
assert_eq!(de.peek().unwrap(), &Start(BytesStart::new("tag")));
match de.read_to_end(QName(b"tag")) {
Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
assert_eq!(cause, IllFormedError::MissingEndTag("tag".into()))
}
x => panic!(
"Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
x
),
}
assert_eq!(de.next().unwrap(), Eof);
}
#[test]
fn invalid_xml2() {
let mut de = make_de("<tag><![CDATA[]]><tag></tag>");
assert_eq!(de.next().unwrap(), Start(BytesStart::new("tag")));
assert_eq!(de.peek().unwrap(), &Text("".into()));
match de.read_to_end(QName(b"tag")) {
Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
assert_eq!(cause, IllFormedError::MissingEndTag("tag".into()))
}
x => panic!(
"Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
x
),
}
assert_eq!(de.next().unwrap(), Eof);
}
}
#[test]
fn borrowing_reader_parity() {
let s = r#"
<item name="hello" source="world.rs">Some text</item>
<item2/>
<item3 value="world" />
"#;
let mut reader1 = IoReader {
reader: NsReader::from_reader(s.as_bytes()),
buf: Vec::new(),
};
let mut reader2 = SliceReader {
reader: NsReader::from_str(s),
};
loop {
let event1 = reader1.next().unwrap();
let event2 = reader2.next().unwrap();
if let (PayloadEvent::Eof, PayloadEvent::Eof) = (&event1, &event2) {
break;
}
assert_eq!(event1, event2);
}
}
#[test]
fn borrowing_reader_events() {
let s = r#"
<item name="hello" source="world.rs">Some text</item>
<item2></item2>
<item3/>
<item4 value="world" />
"#;
let mut reader = SliceReader {
reader: NsReader::from_str(s),
};
let config = reader.reader.config_mut();
config.expand_empty_elements = true;
let mut events = Vec::new();
loop {
let event = reader.next().unwrap();
if let PayloadEvent::Eof = event {
break;
}
events.push(event);
}
use crate::de::PayloadEvent::*;
assert_eq!(
events,
vec![
Text(BytesText::from_escaped("\n ")),
Start(BytesStart::from_content(
r#"item name="hello" source="world.rs""#,
4
)),
Text(BytesText::from_escaped("Some text")),
End(BytesEnd::new("item")),
Text(BytesText::from_escaped("\n ")),
Start(BytesStart::from_content("item2", 5)),
End(BytesEnd::new("item2")),
Text(BytesText::from_escaped("\n ")),
Start(BytesStart::from_content("item3", 5)),
End(BytesEnd::new("item3")),
Text(BytesText::from_escaped("\n ")),
Start(BytesStart::from_content(r#"item4 value="world" "#, 5)),
End(BytesEnd::new("item4")),
Text(BytesText::from_escaped("\n ")),
]
)
}
#[test]
fn read_string() {
match from_str::<String>(r#"</root>"#) {
Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
assert_eq!(cause, IllFormedError::UnmatchedEndTag("root".into()));
}
x => panic!(
"Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
x
),
}
let s: String = from_str(r#"<root></root>"#).unwrap();
assert_eq!(s, "");
match from_str::<String>(r#"<root></other>"#) {
Err(DeError::InvalidXml(Error::IllFormed(cause))) => assert_eq!(
cause,
IllFormedError::MismatchedEndTag {
expected: "root".into(),
found: "other".into(),
}
),
x => panic!("Expected `Err(InvalidXml(IllFormed(_))`, but got `{:?}`", x),
}
}
mod merge_text {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn text() {
let mut de = make_de("text");
assert_eq!(de.next().unwrap(), DeEvent::Text("text".into()));
}
#[test]
fn cdata() {
let mut de = make_de("<![CDATA[cdata]]>");
assert_eq!(de.next().unwrap(), DeEvent::Text("cdata".into()));
}
#[test]
fn text_and_cdata() {
let mut de = make_de("text and <![CDATA[cdata]]>");
assert_eq!(de.next().unwrap(), DeEvent::Text("text and cdata".into()));
}
#[test]
fn text_and_empty_cdata() {
let mut de = make_de("text and <![CDATA[]]>");
assert_eq!(de.next().unwrap(), DeEvent::Text("text and ".into()));
}
#[test]
fn cdata_and_text() {
let mut de = make_de("<![CDATA[cdata]]> and text");
assert_eq!(de.next().unwrap(), DeEvent::Text("cdata and text".into()));
}
#[test]
fn empty_cdata_and_text() {
let mut de = make_de("<![CDATA[]]> and text");
assert_eq!(de.next().unwrap(), DeEvent::Text(" and text".into()));
}
#[test]
fn cdata_and_cdata() {
let mut de = make_de(
"\
<![CDATA[cdata]]]]>\
<![CDATA[>cdata]]>\
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("cdata]]>cdata".into()));
}
mod comment_between {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn text() {
let mut de = make_de(
"\
text \
<!--comment 1--><!--comment 2--> \
text\
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("text text".into()));
}
#[test]
fn cdata() {
let mut de = make_de(
"\
<![CDATA[cdata]]]]>\
<!--comment 1--><!--comment 2-->\
<![CDATA[>cdata]]>\
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("cdata]]>cdata".into()));
}
#[test]
fn text_and_cdata() {
let mut de = make_de(
"\
text \
<!--comment 1--><!--comment 2-->\
<![CDATA[ cdata]]>\
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("text cdata".into()));
}
#[test]
fn text_and_empty_cdata() {
let mut de = make_de(
"\
text \
<!--comment 1--><!--comment 2-->\
<![CDATA[]]>\
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("text ".into()));
}
#[test]
fn cdata_and_text() {
let mut de = make_de(
"\
<![CDATA[cdata ]]>\
<!--comment 1--><!--comment 2--> \
text \
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("cdata text ".into()));
}
#[test]
fn empty_cdata_and_text() {
let mut de = make_de(
"\
<![CDATA[]]>\
<!--comment 1--><!--comment 2--> \
text \
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text(" text ".into()));
}
#[test]
fn cdata_and_cdata() {
let mut de = make_de(
"\
<![CDATA[cdata]]]>\
<!--comment 1--><!--comment 2-->\
<![CDATA[]>cdata]]>\
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("cdata]]>cdata".into()));
}
}
mod pi_between {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn text() {
let mut de = make_de(
"\
text \
<?pi 1?><?pi 2?> \
text\
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("text text".into()));
}
#[test]
fn cdata() {
let mut de = make_de(
"\
<![CDATA[cdata]]]]>\
<?pi 1?><?pi 2?>\
<![CDATA[>cdata]]>\
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("cdata]]>cdata".into()));
}
#[test]
fn text_and_cdata() {
let mut de = make_de(
"\
text \
<?pi 1?><?pi 2?>\
<![CDATA[ cdata]]>\
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("text cdata".into()));
}
#[test]
fn text_and_empty_cdata() {
let mut de = make_de(
"\
text \
<?pi 1?><?pi 2?>\
<![CDATA[]]>\
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("text ".into()));
}
#[test]
fn cdata_and_text() {
let mut de = make_de(
"\
<![CDATA[cdata ]]>\
<?pi 1?><?pi 2?> \
text \
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("cdata text ".into()));
}
#[test]
fn empty_cdata_and_text() {
let mut de = make_de(
"\
<![CDATA[]]>\
<?pi 1?><?pi 2?> \
text \
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text(" text ".into()));
}
#[test]
fn cdata_and_cdata() {
let mut de = make_de(
"\
<![CDATA[cdata]]]>\
<?pi 1?><?pi 2?>\
<![CDATA[]>cdata]]>\
",
);
assert_eq!(de.next().unwrap(), DeEvent::Text("cdata]]>cdata".into()));
}
}
}
mod triples {
use super::*;
use pretty_assertions::assert_eq;
mod start {
use super::*;
#[allow(clippy::module_inception)]
mod start {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn start() {
let mut de = make_de("<tag1><tag2><tag3>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag1")));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag2")));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag3")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn end() {
let mut de = make_de("<tag1><tag2></tag2>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag1")));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag2")));
assert_eq!(de.next().unwrap(), DeEvent::End(BytesEnd::new("tag2")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn text() {
let mut de = make_de("<tag1><tag2> text ");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag1")));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag2")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" text ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn cdata() {
let mut de = make_de("<tag1><tag2><![CDATA[ cdata ]]>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag1")));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag2")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn eof() {
let mut de = make_de("<tag1><tag2>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag1")));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag2")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
}
mod end {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn start() {
let mut de = make_de("<tag></tag><tag2>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::End(BytesEnd::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag2")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn end() {
let mut de = make_de("<tag></tag></tag2>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::End(BytesEnd::new("tag")));
match de.next() {
Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
assert_eq!(cause, IllFormedError::UnmatchedEndTag("tag2".into()));
}
x => panic!(
"Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
x
),
}
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn text() {
let mut de = make_de("<tag></tag> text ");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::End(BytesEnd::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" text ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn cdata() {
let mut de = make_de("<tag></tag><![CDATA[ cdata ]]>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::End(BytesEnd::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn eof() {
let mut de = make_de("<tag></tag>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::End(BytesEnd::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
}
mod text {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn start() {
let mut de = make_de("<tag> text <tag2>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" text ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag2")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn end() {
let mut de = make_de("<tag> text </tag>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" text ".into()));
assert_eq!(de.next().unwrap(), DeEvent::End(BytesEnd::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn cdata() {
let mut de = make_de("<tag> text <![CDATA[ cdata ]]>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" text cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn eof() {
let mut de = make_de("<tag> text ");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" text ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
}
mod cdata {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn start() {
let mut de = make_de("<tag><![CDATA[ cdata ]]><tag2>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag2")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn end() {
let mut de = make_de("<tag><![CDATA[ cdata ]]></tag>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::End(BytesEnd::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn text() {
let mut de = make_de("<tag><![CDATA[ cdata ]]> text ");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata text ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn cdata() {
let mut de = make_de("<tag><![CDATA[ cdata ]]><![CDATA[ cdata2 ]]>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata cdata2 ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn eof() {
let mut de = make_de("<tag><![CDATA[ cdata ]]>");
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
}
}
#[test]
fn end() {
let mut de = make_de("</tag>");
match de.next() {
Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
assert_eq!(cause, IllFormedError::UnmatchedEndTag("tag".into()));
}
x => panic!(
"Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
x
),
}
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
mod text {
use super::*;
use pretty_assertions::assert_eq;
mod start {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn start() {
let mut de = make_de(" text <tag1><tag2>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" text ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag1")));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag2")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn end() {
let mut de = make_de(" text <tag></tag>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" text ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::End(BytesEnd::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn text() {
let mut de = make_de(" text <tag> text2 ");
assert_eq!(de.next().unwrap(), DeEvent::Text(" text ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" text2 ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn cdata() {
let mut de = make_de(" text <tag><![CDATA[ cdata ]]>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" text ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn eof() {
let mut de = make_de(" text <tag>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" text ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
}
#[test]
fn end() {
let mut de = make_de(" text </tag>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" text ".into()));
match de.next() {
Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
assert_eq!(cause, IllFormedError::UnmatchedEndTag("tag".into()));
}
x => panic!(
"Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
x
),
}
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
mod cdata {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn start() {
let mut de = make_de(" text <![CDATA[ cdata ]]><tag>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" text cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn end() {
let mut de = make_de(" text <![CDATA[ cdata ]]></tag>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" text cdata ".into()));
match de.next() {
Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
assert_eq!(cause, IllFormedError::UnmatchedEndTag("tag".into()));
}
x => panic!(
"Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
x
),
}
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn text() {
let mut de = make_de(" text <![CDATA[ cdata ]]> text2 ");
assert_eq!(
de.next().unwrap(),
DeEvent::Text(" text cdata text2 ".into())
);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn cdata() {
let mut de = make_de(" text <![CDATA[ cdata ]]><![CDATA[ cdata2 ]]>");
assert_eq!(
de.next().unwrap(),
DeEvent::Text(" text cdata cdata2 ".into())
);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn eof() {
let mut de = make_de(" text <![CDATA[ cdata ]]>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" text cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
}
}
mod cdata {
use super::*;
use pretty_assertions::assert_eq;
mod start {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn start() {
let mut de = make_de("<![CDATA[ cdata ]]><tag1><tag2>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag1")));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag2")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn end() {
let mut de = make_de("<![CDATA[ cdata ]]><tag></tag>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::End(BytesEnd::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn text() {
let mut de = make_de("<![CDATA[ cdata ]]><tag> text ");
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" text ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn cdata() {
let mut de = make_de("<![CDATA[ cdata ]]><tag><![CDATA[ cdata2 ]]>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata2 ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn eof() {
let mut de = make_de("<![CDATA[ cdata ]]><tag>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
}
#[test]
fn end() {
let mut de = make_de("<![CDATA[ cdata ]]></tag>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata ".into()));
match de.next() {
Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
assert_eq!(cause, IllFormedError::UnmatchedEndTag("tag".into()));
}
x => panic!(
"Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
x
),
}
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
mod text {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn start() {
let mut de = make_de("<![CDATA[ cdata ]]> text <tag>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata text ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn end() {
let mut de = make_de("<![CDATA[ cdata ]]> text </tag>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata text ".into()));
match de.next() {
Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
assert_eq!(cause, IllFormedError::UnmatchedEndTag("tag".into()));
}
x => panic!(
"Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
x
),
}
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn cdata() {
let mut de = make_de("<![CDATA[ cdata ]]> text <![CDATA[ cdata2 ]]>");
assert_eq!(
de.next().unwrap(),
DeEvent::Text(" cdata text cdata2 ".into())
);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn eof() {
let mut de = make_de("<![CDATA[ cdata ]]> text ");
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata text ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
}
#[allow(clippy::module_inception)]
mod cdata {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn start() {
let mut de = make_de("<![CDATA[ cdata ]]><![CDATA[ cdata2 ]]><tag>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata cdata2 ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Start(BytesStart::new("tag")));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn end() {
let mut de = make_de("<![CDATA[ cdata ]]><![CDATA[ cdata2 ]]></tag>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata cdata2 ".into()));
match de.next() {
Err(DeError::InvalidXml(Error::IllFormed(cause))) => {
assert_eq!(cause, IllFormedError::UnmatchedEndTag("tag".into()));
}
x => panic!(
"Expected `Err(InvalidXml(IllFormed(_)))`, but got `{:?}`",
x
),
}
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn text() {
let mut de = make_de("<![CDATA[ cdata ]]><![CDATA[ cdata2 ]]> text ");
assert_eq!(
de.next().unwrap(),
DeEvent::Text(" cdata cdata2 text ".into())
);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn cdata() {
let mut de =
make_de("<![CDATA[ cdata ]]><![CDATA[ cdata2 ]]><![CDATA[ cdata3 ]]>");
assert_eq!(
de.next().unwrap(),
DeEvent::Text(" cdata cdata2 cdata3 ".into())
);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
#[test]
fn eof() {
let mut de = make_de("<![CDATA[ cdata ]]><![CDATA[ cdata2 ]]>");
assert_eq!(de.next().unwrap(), DeEvent::Text(" cdata cdata2 ".into()));
assert_eq!(de.next().unwrap(), DeEvent::Eof);
assert_eq!(de.next().unwrap(), DeEvent::Eof);
}
}
}
}
}