xsd_parser/quick_xml/reader/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
//! Defines and implements different helper traits that are needed for the
//! deserialization process with the [`quick_xml`] crate.

mod error_reader;
mod io_reader;
mod slice_reader;

#[cfg(feature = "async")]
mod fut;

#[cfg(feature = "async")]
use std::future::Future;

use quick_xml::{
    events::Event,
    name::{LocalName, PrefixIter, QName, ResolveResult},
};

pub use self::error_reader::ErrorReader;
pub use self::io_reader::IoReader;
pub use self::slice_reader::SliceReader;

#[cfg(feature = "async")]
pub use self::fut::{ReadTag, SkipCurrent};

use super::{DeserializeBytes, Error, ErrorKind, RawByteStr};

/// Trait that defines the basics for an XML reader.
pub trait XmlReader: Sized {
    /// Resolves a qname in the current context of the XML file.
    fn resolve<'n>(&self, name: QName<'n>, attribute: bool) -> (ResolveResult<'_>, LocalName<'n>);

    /// Returns an iterator the walks over all known namespace prefixes for the
    /// current context of the XML file.
    fn prefixes(&self) -> PrefixIter<'_>;

    /// Returns the current position (byte offset) in the current XML file.
    fn current_position(&self) -> u64;

    /// Returns the position (byte offset) of the last detected error.
    fn error_position(&self) -> u64;

    /// Add the error position to the passed error and return it.
    fn extend_error(&self, error: Error) -> Error {
        error.with_pos(self.error_position())
    }

    /// Converts the passed `error` to an [`Error`], adds the error information
    /// using `extend_error` and returns it.
    fn map_error<E>(&self, error: E) -> Error
    where
        Error: From<E>,
    {
        self.extend_error(Error::from(error))
    }

    /// Same as `map_error`, but for the passed `result`.
    #[allow(clippy::missing_errors_doc)]
    fn map_result<T, E>(&self, result: Result<T, E>) -> Result<T, Error>
    where
        Error: From<E>,
    {
        result.map_err(|error| self.map_error(error))
    }

    /// Create a result from the passed `error` using `map_error` and returns it.
    #[allow(clippy::missing_errors_doc)]
    fn err<E>(&self, error: E) -> Result<(), Error>
    where
        Error: From<E>,
    {
        Err(self.map_error(error))
    }

    /// Helper function to convert and store an attribute from the XML event.
    ///
    /// # Errors
    ///
    /// Returns an [`Error`] with [`ErrorKind::DuplicateAttribute`] if `store`
    /// already contained a value.
    fn read_attrib<T>(
        &self,
        store: &mut Option<T>,
        name: &'static [u8],
        value: &[u8],
    ) -> Result<(), Error>
    where
        T: DeserializeBytes,
    {
        if store.is_some() {
            self.err(ErrorKind::DuplicateAttribute(RawByteStr::from(name)))?;
        }

        let value = self.map_result(T::deserialize_bytes(self, value))?;
        *store = Some(value);

        Ok(())
    }

    /// Wraps the current reader in a new [`ErrorReader`].
    fn with_error_info(self) -> ErrorReader<Self> {
        ErrorReader::new(self)
    }

    /// Try to resolve the local name of the passed qname and the expected namespace.
    ///
    /// Checks if the passed [`QName`] `name` matches the expected namespace `ns`
    /// and returns the local name of it. If `name` does not have a namespace prefix
    /// to resolve, the local name is just returned as is.
    fn resolve_local_name<'a>(&self, name: QName<'a>, ns: &[u8]) -> Option<&'a [u8]> {
        match self.resolve(name, true) {
            (ResolveResult::Unbound, local) => Some(local.into_inner()),
            (ResolveResult::Bound(x), local) if x.0 == ns => Some(local.into_inner()),
            (_, _) => None,
        }
    }
}

/// Trait that defines a synchronous XML reader.
pub trait XmlReaderSync<'a>: XmlReader {
    /// Reads the next [`Event`] from the reader.
    ///
    /// # Errors
    ///
    /// Returns an [`Error`] if the event could not been read.
    fn read_event(&mut self) -> Result<Event<'a>, Error>;

    /// Reads a new XML tag ([`Event::Start`], [`Event::Empty`] or [`Event::End`])
    /// from the reader.
    ///
    /// # Errors
    ///
    /// Forwards the errors from `read_event`.
    fn read_tag(&mut self) -> Result<Event<'a>, Error> {
        loop {
            if let e @ (Event::Start(_) | Event::Empty(_) | Event::End(_)) = self.read_event()? {
                break Ok(e);
            }
        }
    }

    /// Skips the current event with respect to the level of the different XML tags.
    ///
    /// # Errors
    ///
    /// Forwards the errors from `read_event`.
    fn skip_current(&mut self) -> Result<(), Error> {
        let mut depth = 0usize;

        loop {
            let event = self.read_event()?;

            match event {
                Event::Start(_) => depth += 1,
                Event::End(_) if depth == 1 => return Ok(()),
                Event::End(_) => depth -= 1,
                Event::Eof => Err(ErrorKind::UnexpectedEof)?,
                _ if depth > 0 => (),
                _ => return Ok(()),
            }
        }
    }
}

/// Trait that defines a asynchronous XML reader.
#[cfg(feature = "async")]
pub trait XmlReaderAsync<'a>: XmlReader {
    /// Future that is returned by the [`read_event_async`] method.
    type ReadEventFut<'x>: Future<Output = Result<Event<'a>, Error>> + Unpin
    where
        Self: 'x;

    /// Reads the next [`Event`] from the reader asynchronously.
    fn read_event_async(&mut self) -> Self::ReadEventFut<'_>;

    /// Reads a new XML tag ([`Event::Start`], [`Event::Empty`] or [`Event::End`])
    /// from the reader asynchronously.
    fn read_tag_async(&mut self) -> ReadTag<'a, '_, Self> {
        ReadTag::new(self)
    }

    /// Skips the current event with respect to the level of the different XML
    /// tags asynchronously.
    fn skip_current_async(&mut self) -> SkipCurrent<'a, '_, Self> {
        SkipCurrent::new(self)
    }
}