Skip to main content

oxixml_xml/reader/
async_tokio.rs

1//! Asynchronous reading from a [`tokio::io::AsyncBufRead`] source.
2//!
3//! This is an implementation of [`Reader`] and [`NsReader`] for reading from an
4//! [`AsyncBufRead`] as underlying byte stream. This reader fully implements
5//! async/await so reading can use non-blocking I/O. It mirrors quick-xml 0.41's
6//! `reader::async_tokio` module: the byte-scanning logic is shared with the
7//! synchronous [`BufRead`](std::io::BufRead) implementation through the
8//! [`impl_buffered_source!`](crate::reader::buffered_reader) macro (reused here
9//! via [`TokioAdapter`]), so the sansio parser core in [`state`](super::state)
10//! stays the single source of truth for both.
11
12use std::pin::Pin;
13use std::task::{Context, Poll};
14
15use tokio::io::{self, AsyncBufRead, AsyncBufReadExt, AsyncRead, ReadBuf};
16
17use crate::encoding;
18use crate::errors::{Error, IllFormedError, Result, SyntaxError};
19use crate::events::{BytesRef, BytesText, Event};
20use crate::name::{QName, ResolveResult};
21use crate::parser::{ElementParser, Parser, PiParser};
22use crate::reader::buffered_reader::impl_buffered_source;
23use crate::reader::{
24    BangType, BinaryStream, NsReader, ParseState, ReadRefResult, ReadTextResult, Reader, Span,
25};
26use crate::utils::is_whitespace;
27
28/// A struct that reads XML asynchronously from an [`AsyncBufRead`].
29///
30/// Having its own struct lets us implement anything without risk of name
31/// conflicts with the synchronous [`XmlSource`](crate::reader::XmlSource)
32/// implementation, and sidesteps the impossibility of having `async` methods
33/// directly in that trait.
34struct TokioAdapter<'a, R>(&'a mut R);
35
36impl<'a, R: AsyncBufRead + Unpin> TokioAdapter<'a, R> {
37    impl_buffered_source!('b, 0, async, await);
38}
39
40////////////////////////////////////////////////////////////////////////////////////////////////////
41
42impl<R> AsyncRead for BinaryStream<'_, R>
43where
44    R: AsyncRead + Unpin,
45{
46    fn poll_read(
47        self: Pin<&mut Self>,
48        cx: &mut Context<'_>,
49        buf: &mut ReadBuf<'_>,
50    ) -> Poll<io::Result<()>> {
51        let start = buf.remaining();
52        let this = self.get_mut();
53        let poll = Pin::new(&mut *this.inner).poll_read(cx, buf);
54
55        // If something was read, update offset
56        if let Poll::Ready(Ok(())) = poll {
57            let amt = start - buf.remaining();
58            *this.offset += amt as u64;
59        }
60        poll
61    }
62}
63
64impl<R> AsyncBufRead for BinaryStream<'_, R>
65where
66    R: AsyncBufRead + Unpin,
67{
68    #[inline]
69    fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
70        Pin::new(&mut *self.get_mut().inner).poll_fill_buf(cx)
71    }
72
73    #[inline]
74    fn consume(self: Pin<&mut Self>, amt: usize) {
75        let this = self.get_mut();
76        this.inner.consume(amt);
77        *this.offset += amt as u64;
78    }
79}
80
81////////////////////////////////////////////////////////////////////////////////////////////////////
82
83impl<R: AsyncBufRead + Unpin> Reader<R> {
84    /// An asynchronous version of [`read_event_into()`]. Reads the next event
85    /// into the given buffer.
86    ///
87    /// This is the main entry point for reading XML `Event`s when using an
88    /// async reader.
89    ///
90    /// See the documentation of [`read_event_into()`] for more information.
91    ///
92    /// # Examples
93    ///
94    /// ```
95    /// # use oxixml_xml::events::Event;
96    /// # use oxixml_xml::reader::Reader;
97    /// # #[tokio::main(flavor = "current_thread")]
98    /// # async fn main() {
99    /// // This explicitly uses `from_reader("...".as_bytes())` to use a buffered
100    /// // reader instead of relying on the zero-copy optimizations for reading
101    /// // from byte slices, which provides the sync interface anyway.
102    /// let mut reader = Reader::from_reader(
103    ///     r#"
104    ///     <tag1 att1 = "test">
105    ///        <tag2><!--Test comment-->Test</tag2>
106    ///        <tag2>Test 2</tag2>
107    ///     </tag1>
108    /// "#
109    ///     .as_bytes(),
110    /// );
111    /// reader.config_mut().trim_text(true);
112    ///
113    /// let mut count = 0;
114    /// let mut buf = Vec::new();
115    /// let mut txt = Vec::new();
116    /// loop {
117    ///     match reader.read_event_into_async(&mut buf).await {
118    ///         Ok(Event::Start(_)) => count += 1,
119    ///         Ok(Event::Text(e)) => txt.push(e.decode().expect("utf-8").into_owned()),
120    ///         Err(e) => panic!("Error at position {}: {:?}", reader.error_position(), e),
121    ///         Ok(Event::Eof) => break,
122    ///         _ => (),
123    ///     }
124    ///     buf.clear();
125    /// }
126    /// assert_eq!(count, 3);
127    /// assert_eq!(txt, vec!["Test".to_string(), "Test 2".to_string()]);
128    /// # }
129    /// ```
130    ///
131    /// [`read_event_into()`]: Reader::read_event_into
132    #[cfg_attr(docsrs, doc(cfg(feature = "async-tokio")))]
133    pub async fn read_event_into_async<'b>(
134        &mut self,
135        mut buf: &'b mut Vec<u8>,
136    ) -> Result<Event<'b>> {
137        read_event_impl!(
138            self,
139            buf,
140            TokioAdapter(&mut self.reader),
141            read_until_close_async,
142            await
143        )
144    }
145
146    /// An asynchronous version of [`read_to_end_into()`]. Reads asynchronously
147    /// until the matching end element is found, using the provided buffer as
148    /// intermediate storage for events content. This function is supposed to be
149    /// called after you already read a [`Start`] event.
150    ///
151    /// See the documentation of [`read_to_end_into()`] for more information.
152    ///
153    /// # Examples
154    ///
155    /// This example shows how you can skip XML content after you read the start
156    /// event.
157    ///
158    /// ```
159    /// # use oxixml_xml::events::{BytesStart, Event};
160    /// # use oxixml_xml::reader::Reader;
161    /// # #[tokio::main(flavor = "current_thread")]
162    /// # async fn main() {
163    /// let mut reader = Reader::from_reader(
164    ///     r#"
165    ///     <outer>
166    ///         <inner>
167    ///             <inner></inner>
168    ///             <inner/>
169    ///             <outer></outer>
170    ///             <outer/>
171    ///         </inner>
172    ///     </outer>
173    /// "#
174    ///     .as_bytes(),
175    /// );
176    /// reader.config_mut().trim_text(true);
177    /// let mut buf = Vec::new();
178    ///
179    /// let start = BytesStart::new("outer");
180    /// let end = start.to_end().into_owned();
181    ///
182    /// // First, we read a start event...
183    /// assert_eq!(
184    ///     reader.read_event_into_async(&mut buf).await.expect("start"),
185    ///     Event::Start(start)
186    /// );
187    ///
188    /// // ...then, we could skip all events to the corresponding end event.
189    /// // This call will correctly handle nested <outer> elements.
190    /// // Note, however, that this method does not handle namespaces.
191    /// reader
192    ///     .read_to_end_into_async(end.name(), &mut buf)
193    ///     .await
194    ///     .expect("end");
195    ///
196    /// // At the end we should get an Eof event, because we ate the whole XML
197    /// assert_eq!(
198    ///     reader.read_event_into_async(&mut buf).await.expect("eof"),
199    ///     Event::Eof
200    /// );
201    /// # }
202    /// ```
203    ///
204    /// [`read_to_end_into()`]: Self::read_to_end_into
205    /// [`Start`]: Event::Start
206    #[cfg_attr(docsrs, doc(cfg(feature = "async-tokio")))]
207    pub async fn read_to_end_into_async<'n>(
208        &mut self,
209        // We should name that lifetime due to https://github.com/rust-lang/rust/issues/63033
210        end: QName<'n>,
211        buf: &mut Vec<u8>,
212    ) -> Result<Span> {
213        Ok(read_to_end!(
214            self,
215            end,
216            buf,
217            read_event_into_async,
218            {
219                buf.clear();
220            },
221            await
222        ))
223    }
224
225    /// An asynchronous version of [`read_text_into()`]. Reads asynchronously
226    /// content between start and end tags, including any markup, using the
227    /// provided buffer as intermediate storage for events content. This
228    /// function is supposed to be called after you already read a [`Start`]
229    /// event.
230    ///
231    /// See the documentation of [`read_text_into()`] for more information.
232    ///
233    /// [`read_text_into()`]: Self::read_text_into
234    /// [`Start`]: Event::Start
235    #[cfg_attr(docsrs, doc(cfg(feature = "async-tokio")))]
236    pub async fn read_text_into_async<'n, 'b>(
237        &mut self,
238        // We should name that lifetime due to https://github.com/rust-lang/rust/issues/63033
239        end: QName<'n>,
240        buf: &'b mut Vec<u8>,
241    ) -> Result<BytesText<'b>> {
242        let start = buf.len();
243        let span = read_to_end!(self, end, buf, read_event_into_async, {}, await);
244
245        let len = span.end - span.start;
246        // `buf` may contain not more than isize::MAX bytes and because it is
247        // not cleared when reading event, length of the returned span should fit
248        // into usize (because otherwise we panic at appending to the buffer
249        // before that point)
250        let end = start + len as usize;
251
252        Ok(BytesText::wrap(&buf[start..end], self.decoder()))
253    }
254
255    /// Private function to read until `>` is found. This function expects that
256    /// it was called just after encounter a `<` symbol.
257    async fn read_until_close_async<'b>(&mut self, buf: &'b mut Vec<u8>) -> Result<Event<'b>> {
258        read_until_close!(self, buf, TokioAdapter(&mut self.reader), await)
259    }
260}
261
262////////////////////////////////////////////////////////////////////////////////////////////////////
263
264impl<R: AsyncBufRead + Unpin> NsReader<R> {
265    /// An asynchronous version of [`read_event_into()`]. Reads the next event
266    /// into the given buffer.
267    ///
268    /// This method manages namespaces but doesn't resolve them automatically.
269    /// You should call [`resolve_element()`] if you want to get a namespace.
270    ///
271    /// You also can use [`read_resolved_event_into_async()`] instead if you want
272    /// to resolve namespaces as soon as you get an event.
273    ///
274    /// [`read_event_into()`]: NsReader::read_event_into
275    /// [`resolve_element()`]: NsReader::resolve_element
276    /// [`read_resolved_event_into_async()`]: Self::read_resolved_event_into_async
277    #[cfg_attr(docsrs, doc(cfg(feature = "async-tokio")))]
278    pub async fn read_event_into_async<'b>(&mut self, buf: &'b mut Vec<u8>) -> Result<Event<'b>> {
279        self.pop();
280        let event = self.reader.read_event_into_async(buf).await;
281        self.process_event(event)
282    }
283
284    /// An asynchronous version of [`read_to_end_into()`]. Reads asynchronously
285    /// until the matching end element is found, using the provided buffer as
286    /// intermediate storage for events content. This function is supposed to be
287    /// called after you already read a [`Start`] event.
288    ///
289    /// See the documentation of [`read_to_end_into()`] for more information.
290    ///
291    /// [`read_to_end_into()`]: Self::read_to_end_into
292    /// [`Start`]: Event::Start
293    #[cfg_attr(docsrs, doc(cfg(feature = "async-tokio")))]
294    pub async fn read_to_end_into_async<'n>(
295        &mut self,
296        // We should name that lifetime due to https://github.com/rust-lang/rust/issues/63033
297        end: QName<'n>,
298        buf: &mut Vec<u8>,
299    ) -> Result<Span> {
300        // According to https://www.w3.org/TR/xml11/#dt-etag the end name should
301        // match the start name literally. See `Config::check_end_names`.
302        let result = self.reader.read_to_end_into_async(end, buf).await?;
303        // `read_to_end_into_async` consumed the closing tag. Because nobody can
304        // access its content anymore, we directly pop the opening tag's
305        // namespace scope.
306        self.resolver_mut().pop();
307        Ok(result)
308    }
309
310    /// An asynchronous version of [`read_text_into()`]. Reads asynchronously
311    /// content between start and end tags, including any markup, using the
312    /// provided buffer as intermediate storage for events content. This
313    /// function is supposed to be called after you already read a [`Start`]
314    /// event.
315    ///
316    /// See the documentation of [`read_text_into()`] for more information.
317    ///
318    /// [`read_text_into()`]: Self::read_text_into
319    /// [`Start`]: Event::Start
320    #[cfg_attr(docsrs, doc(cfg(feature = "async-tokio")))]
321    pub async fn read_text_into_async<'n, 'b>(
322        &mut self,
323        // We should name that lifetime due to https://github.com/rust-lang/rust/issues/63033
324        end: QName<'n>,
325        buf: &'b mut Vec<u8>,
326    ) -> Result<BytesText<'b>> {
327        let result = self.reader.read_text_into_async(end, buf).await?;
328        // `read_text_into_async` consumed the closing tag, so pop its namespace
329        // scope.
330        self.resolver_mut().pop();
331        Ok(result)
332    }
333
334    /// An asynchronous version of [`read_resolved_event_into()`]. Reads the next
335    /// event into the given buffer asynchronously and resolves its namespace
336    /// (if applicable).
337    ///
338    /// Namespace is resolved only for [`Start`], [`Empty`] and [`End`] events.
339    /// For all other events the concept of namespace is not defined, so a
340    /// [`ResolveResult::Unbound`] is returned.
341    ///
342    /// If you are not interested in namespaces, you can use
343    /// [`read_event_into_async()`] which will not automatically resolve
344    /// namespaces for you.
345    ///
346    /// [`read_resolved_event_into()`]: NsReader::read_resolved_event_into
347    /// [`Start`]: Event::Start
348    /// [`Empty`]: Event::Empty
349    /// [`End`]: Event::End
350    /// [`read_event_into_async()`]: Self::read_event_into_async
351    #[cfg_attr(docsrs, doc(cfg(feature = "async-tokio")))]
352    pub async fn read_resolved_event_into_async<'ns, 'b>(
353        // Name 'ns lifetime, because otherwise we get an error
354        // "implicit elided lifetime not allowed here" on ResolveResult
355        &'ns mut self,
356        buf: &'b mut Vec<u8>,
357    ) -> Result<(ResolveResult<'ns>, Event<'b>)> {
358        let event = self.read_event_into_async(buf).await?;
359        Ok(self.resolver().resolve_event(event))
360    }
361}
362
363#[cfg(test)]
364mod test {
365    use super::TokioAdapter;
366    use crate::reader::check_tests::check;
367
368    check!(
369        #[tokio::test]
370        read_event_into_async,
371        TokioAdapter,
372        1,
373        &mut Vec::new(),
374        async,
375        await
376    );
377
378    #[test]
379    fn test_future_is_send() {
380        // This test should just compile, no actual runtime checks are performed here.
381        use super::*;
382        use tokio::io::BufReader;
383
384        fn check_send<T: Send>(_: T) {}
385
386        let input: Vec<u8> = vec![];
387        let mut reading_buf = vec![];
388        let mut reader = Reader::from_reader(BufReader::new(input.as_slice()));
389
390        check_send(reader.read_event_into_async(&mut reading_buf));
391    }
392}