xsd_parser/quick_xml/reader/
mod.rs

1//! Defines and implements different helper traits that are needed for the
2//! deserialization process with the [`quick_xml`] crate.
3
4mod error_reader;
5mod io_reader;
6mod slice_reader;
7
8#[cfg(feature = "async")]
9mod fut;
10
11#[cfg(feature = "async")]
12use std::future::Future;
13
14use quick_xml::{
15    events::Event,
16    name::{LocalName, PrefixIter, QName, ResolveResult},
17};
18
19pub use self::error_reader::ErrorReader;
20pub use self::io_reader::IoReader;
21pub use self::slice_reader::SliceReader;
22
23#[cfg(feature = "async")]
24pub use self::fut::{ReadTag, SkipCurrent};
25
26use super::{DeserializeBytes, Error, ErrorKind, RawByteStr};
27
28/// Trait that defines the basics for an XML reader.
29pub trait XmlReader: Sized {
30    /// Resolves a qname in the current context of the XML file.
31    fn resolve<'n>(&self, name: QName<'n>, attribute: bool) -> (ResolveResult<'_>, LocalName<'n>);
32
33    /// Returns an iterator the walks over all known namespace prefixes for the
34    /// current context of the XML file.
35    fn prefixes(&self) -> PrefixIter<'_>;
36
37    /// Returns the current position (byte offset) in the current XML file.
38    fn current_position(&self) -> u64;
39
40    /// Returns the position (byte offset) of the last detected error.
41    fn error_position(&self) -> u64;
42
43    /// Add the error position to the passed error and return it.
44    fn extend_error(&self, error: Error) -> Error {
45        error.with_pos(self.error_position())
46    }
47
48    /// Converts the passed `error` to an [`Error`], adds the error information
49    /// using `extend_error` and returns it.
50    fn map_error<E>(&self, error: E) -> Error
51    where
52        Error: From<E>,
53    {
54        self.extend_error(Error::from(error))
55    }
56
57    /// Same as `map_error`, but for the passed `result`.
58    #[allow(clippy::missing_errors_doc)]
59    fn map_result<T, E>(&self, result: Result<T, E>) -> Result<T, Error>
60    where
61        Error: From<E>,
62    {
63        result.map_err(|error| self.map_error(error))
64    }
65
66    /// Create a result from the passed `error` using `map_error` and returns it.
67    #[allow(clippy::missing_errors_doc)]
68    fn err<E>(&self, error: E) -> Result<(), Error>
69    where
70        Error: From<E>,
71    {
72        Err(self.map_error(error))
73    }
74
75    /// Helper function to convert and store an attribute from the XML event.
76    ///
77    /// # Errors
78    ///
79    /// Returns an [`Error`] with [`ErrorKind::DuplicateAttribute`] if `store`
80    /// already contained a value.
81    fn read_attrib<T>(
82        &self,
83        store: &mut Option<T>,
84        name: &'static [u8],
85        value: &[u8],
86    ) -> Result<(), Error>
87    where
88        T: DeserializeBytes,
89    {
90        if store.is_some() {
91            self.err(ErrorKind::DuplicateAttribute(RawByteStr::from(name)))?;
92        }
93
94        let value = self.map_result(T::deserialize_bytes(self, value))?;
95        *store = Some(value);
96
97        Ok(())
98    }
99
100    /// Wraps the current reader in a new [`ErrorReader`].
101    fn with_error_info(self) -> ErrorReader<Self> {
102        ErrorReader::new(self)
103    }
104
105    /// Try to resolve the local name of the passed qname and the expected namespace.
106    ///
107    /// Checks if the passed [`QName`] `name` matches the expected namespace `ns`
108    /// and returns the local name of it. If `name` does not have a namespace prefix
109    /// to resolve, the local name is just returned as is.
110    fn resolve_local_name<'a>(&self, name: QName<'a>, ns: &[u8]) -> Option<&'a [u8]> {
111        match self.resolve(name, true) {
112            (ResolveResult::Unbound, local) => Some(local.into_inner()),
113            (ResolveResult::Bound(x), local) if x.0 == ns => Some(local.into_inner()),
114            (_, _) => None,
115        }
116    }
117}
118
119/// Trait that defines a synchronous XML reader.
120pub trait XmlReaderSync<'a>: XmlReader {
121    /// Reads the next [`Event`] from the reader.
122    ///
123    /// # Errors
124    ///
125    /// Returns an [`Error`] if the event could not been read.
126    fn read_event(&mut self) -> Result<Event<'a>, Error>;
127
128    /// Reads a new XML tag ([`Event::Start`], [`Event::Empty`] or [`Event::End`])
129    /// from the reader.
130    ///
131    /// # Errors
132    ///
133    /// Forwards the errors from `read_event`.
134    fn read_tag(&mut self) -> Result<Event<'a>, Error> {
135        loop {
136            if let e @ (Event::Start(_) | Event::Empty(_) | Event::End(_)) = self.read_event()? {
137                break Ok(e);
138            }
139        }
140    }
141
142    /// Skips the current event with respect to the level of the different XML tags.
143    ///
144    /// # Errors
145    ///
146    /// Forwards the errors from `read_event`.
147    fn skip_current(&mut self) -> Result<(), Error> {
148        let mut depth = 0usize;
149
150        loop {
151            let event = self.read_event()?;
152
153            match event {
154                Event::Start(_) => depth += 1,
155                Event::End(_) if depth == 1 => return Ok(()),
156                Event::End(_) => depth -= 1,
157                Event::Eof => Err(ErrorKind::UnexpectedEof)?,
158                _ if depth > 0 => (),
159                _ => return Ok(()),
160            }
161        }
162    }
163}
164
165/// Trait that defines a asynchronous XML reader.
166#[cfg(feature = "async")]
167pub trait XmlReaderAsync<'a>: XmlReader {
168    /// Future that is returned by the [`read_event_async`] method.
169    type ReadEventFut<'x>: Future<Output = Result<Event<'a>, Error>> + Unpin
170    where
171        Self: 'x;
172
173    /// Reads the next [`Event`] from the reader asynchronously.
174    fn read_event_async(&mut self) -> Self::ReadEventFut<'_>;
175
176    /// Reads a new XML tag ([`Event::Start`], [`Event::Empty`] or [`Event::End`])
177    /// from the reader asynchronously.
178    fn read_tag_async(&mut self) -> ReadTag<'a, '_, Self> {
179        ReadTag::new(self)
180    }
181
182    /// Skips the current event with respect to the level of the different XML
183    /// tags asynchronously.
184    fn skip_current_async(&mut self) -> SkipCurrent<'a, '_, Self> {
185        SkipCurrent::new(self)
186    }
187}