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}