quick_xml/writer/
async_tokio.rs

1use std::future::Future;
2use std::result::Result as StdResult;
3
4use tokio::io::{AsyncWrite, AsyncWriteExt};
5
6use crate::errors::{Error, Result};
7use crate::events::{BytesCData, BytesPI, BytesText, Event};
8use crate::{ElementWriter, Writer};
9
10impl<W: AsyncWrite + Unpin> Writer<W> {
11    /// Writes the given event to the underlying writer. Async version of [`Writer::write_event`].
12    pub async fn write_event_async<'a, E: Into<Event<'a>>>(&mut self, event: E) -> Result<()> {
13        let mut next_should_line_break = true;
14        let result = match event.into() {
15            Event::Start(e) => {
16                let result = self.write_wrapped_async(b"<", &e, b">").await;
17                if let Some(i) = self.indent.as_mut() {
18                    i.grow();
19                }
20                result
21            }
22            Event::End(e) => {
23                if let Some(i) = self.indent.as_mut() {
24                    i.shrink();
25                }
26                self.write_wrapped_async(b"</", &e, b">").await
27            }
28            Event::Empty(e) => self.write_wrapped_async(b"<", &e, b"/>").await,
29            Event::Text(e) => {
30                next_should_line_break = false;
31                self.write_async(&e).await
32            }
33            Event::Comment(e) => self.write_wrapped_async(b"<!--", &e, b"-->").await,
34            Event::CData(e) => {
35                next_should_line_break = false;
36                self.write_async(b"<![CDATA[").await?;
37                self.write_async(&e).await?;
38                self.write_async(b"]]>").await
39            }
40            Event::Decl(e) => self.write_wrapped_async(b"<?", &e, b"?>").await,
41            Event::PI(e) => self.write_wrapped_async(b"<?", &e, b"?>").await,
42            Event::DocType(e) => self.write_wrapped_async(b"<!DOCTYPE ", &e, b">").await,
43            Event::Eof => Ok(()),
44        };
45        if let Some(i) = self.indent.as_mut() {
46            i.should_line_break = next_should_line_break;
47        }
48        result
49    }
50
51    /// Manually write a newline and indentation at the proper level. Async version of
52    /// [`Writer::write_indent`].
53    ///
54    /// This method will do nothing if `Writer` was not constructed with [`Writer::new_with_indent`].
55    pub async fn write_indent_async(&mut self) -> Result<()> {
56        if let Some(ref i) = self.indent {
57            self.writer.write_all(b"\n").await?;
58            self.writer.write_all(i.current()).await?;
59        }
60        Ok(())
61    }
62
63    #[inline]
64    async fn write_async(&mut self, value: &[u8]) -> Result<()> {
65        self.writer.write_all(value).await.map_err(Into::into)
66    }
67
68    #[inline]
69    async fn write_wrapped_async(
70        &mut self,
71        before: &[u8],
72        value: &[u8],
73        after: &[u8],
74    ) -> Result<()> {
75        if let Some(ref i) = self.indent {
76            if i.should_line_break {
77                self.writer.write_all(b"\n").await?;
78                self.writer.write_all(i.current()).await?;
79            }
80        }
81        self.write_async(before).await?;
82        self.write_async(value).await?;
83        self.write_async(after).await?;
84        Ok(())
85    }
86}
87
88impl<'a, W: AsyncWrite + Unpin> ElementWriter<'a, W> {
89    /// Write some text inside the current element.
90    ///
91    /// # Example
92    ///
93    /// ```
94    /// # use quick_xml::writer::Writer;
95    /// # use quick_xml::events::BytesText;
96    /// # use tokio::io::AsyncWriteExt;
97    /// # #[tokio::main(flavor = "current_thread")] async fn main() {
98    /// let mut buffer = Vec::new();
99    /// let mut tokio_buffer = tokio::io::BufWriter::new(&mut buffer);
100    /// let mut writer = Writer::new_with_indent(&mut tokio_buffer, b' ', 4);
101    ///
102    /// writer
103    ///     .create_element("paired")
104    ///     .with_attribute(("attr1", "value1"))
105    ///     .with_attribute(("attr2", "value2"))
106    ///     .write_text_content_async(BytesText::new("text"))
107    ///     .await
108    ///     .expect("cannot write content");
109    ///
110    /// tokio_buffer.flush().await.expect("flush failed");
111    ///
112    /// assert_eq!(
113    ///     std::str::from_utf8(&buffer).unwrap(),
114    ///     r#"<paired attr1="value1" attr2="value2">text</paired>"#
115    /// );
116    /// # }
117    pub async fn write_text_content_async(self, text: BytesText<'_>) -> Result<&'a mut Writer<W>> {
118        self.writer
119            .write_event_async(Event::Start(self.start_tag.borrow()))
120            .await?;
121        self.writer.write_event_async(Event::Text(text)).await?;
122        self.writer
123            .write_event_async(Event::End(self.start_tag.to_end()))
124            .await?;
125        Ok(self.writer)
126    }
127
128    /// Write a CData event `<![CDATA[...]]>` inside the current element.
129    ///
130    /// # Example
131    ///
132    /// ```
133    /// # use quick_xml::writer::Writer;
134    /// # use quick_xml::events::BytesCData;
135    /// # use tokio::io::AsyncWriteExt;
136    /// # #[tokio::main(flavor = "current_thread")] async fn main() {
137    /// let mut buffer = Vec::new();
138    /// let mut tokio_buffer = tokio::io::BufWriter::new(&mut buffer);
139    /// let mut writer = Writer::new_with_indent(&mut tokio_buffer, b' ', 4);
140    ///
141    /// writer
142    ///     .create_element("paired")
143    ///     .with_attribute(("attr1", "value1"))
144    ///     .with_attribute(("attr2", "value2"))
145    ///     .write_cdata_content_async(BytesCData::new("text & content"))
146    ///     .await
147    ///     .expect("cannot write content");
148    ///
149    /// tokio_buffer.flush().await.expect("flush failed");
150    ///
151    /// assert_eq!(
152    ///     std::str::from_utf8(&buffer).unwrap(),
153    ///     r#"<paired attr1="value1" attr2="value2"><![CDATA[text & content]]></paired>"#
154    /// );
155    /// # }
156    pub async fn write_cdata_content_async(
157        self,
158        text: BytesCData<'_>,
159    ) -> Result<&'a mut Writer<W>> {
160        self.writer
161            .write_event_async(Event::Start(self.start_tag.borrow()))
162            .await?;
163        self.writer.write_event_async(Event::CData(text)).await?;
164        self.writer
165            .write_event_async(Event::End(self.start_tag.to_end()))
166            .await?;
167        Ok(self.writer)
168    }
169
170    /// Write a processing instruction `<?...?>` inside the current element.
171    ///
172    /// # Example
173    ///
174    /// ```
175    /// # use quick_xml::writer::Writer;
176    /// # use quick_xml::events::BytesPI;
177    /// # use tokio::io::AsyncWriteExt;
178    /// # #[tokio::main(flavor = "current_thread")] async fn main() {
179    /// let mut buffer = Vec::new();
180    /// let mut tokio_buffer = tokio::io::BufWriter::new(&mut buffer);
181    /// let mut writer = Writer::new_with_indent(&mut tokio_buffer, b' ', 4);
182    ///
183    /// writer
184    ///     .create_element("paired")
185    ///     .with_attribute(("attr1", "value1"))
186    ///     .with_attribute(("attr2", "value2"))
187    ///     .write_pi_content_async(BytesPI::new(r#"xml-stylesheet href="style.css""#))
188    ///     .await
189    ///     .expect("cannot write content");
190    ///
191    /// tokio_buffer.flush().await.expect("flush failed");
192    ///
193    /// assert_eq!(
194    ///     std::str::from_utf8(&buffer).unwrap(),
195    ///     r#"<paired attr1="value1" attr2="value2">
196    ///     <?xml-stylesheet href="style.css"?>
197    /// </paired>"#
198    /// );
199    /// # }
200    pub async fn write_pi_content_async(self, text: BytesPI<'_>) -> Result<&'a mut Writer<W>> {
201        self.writer
202            .write_event_async(Event::Start(self.start_tag.borrow()))
203            .await?;
204        self.writer.write_event_async(Event::PI(text)).await?;
205        self.writer
206            .write_event_async(Event::End(self.start_tag.to_end()))
207            .await?;
208        Ok(self.writer)
209    }
210
211    /// Write an empty (self-closing) tag.
212    ///
213    /// # Example
214    ///
215    /// ```
216    /// # use quick_xml::writer::Writer;
217    /// # use quick_xml::events::BytesText;
218    /// # use tokio::io::AsyncWriteExt;
219    /// # #[tokio::main(flavor = "current_thread")] async fn main() {
220    /// let mut buffer = Vec::new();
221    /// let mut tokio_buffer = tokio::io::BufWriter::new(&mut buffer);
222    /// let mut writer = Writer::new_with_indent(&mut tokio_buffer, b' ', 4);
223    ///
224    /// writer
225    ///     .create_element("empty")
226    ///     .with_attribute(("attr1", "value1"))
227    ///     .with_attribute(("attr2", "value2"))
228    ///     .write_empty_async()
229    ///     .await
230    ///     .expect("cannot write content");
231    ///
232    /// tokio_buffer.flush().await.expect("flush failed");
233    ///
234    /// assert_eq!(
235    ///     std::str::from_utf8(&buffer).unwrap(),
236    ///     r#"<empty attr1="value1" attr2="value2"/>"#
237    /// );
238    /// # }
239    pub async fn write_empty_async(self) -> Result<&'a mut Writer<W>> {
240        self.writer
241            .write_event_async(Event::Empty(self.start_tag))
242            .await?;
243        Ok(self.writer)
244    }
245
246    /// Create a new scope for writing XML inside the current element.
247    ///
248    /// # Example
249    ///
250    /// ```
251    /// # use quick_xml::writer::Writer;
252    /// # use quick_xml::events::BytesText;
253    /// # use tokio::io::AsyncWriteExt;
254    /// use quick_xml::Error;
255    ///
256    /// # #[tokio::main(flavor = "current_thread")] async fn main() {
257    /// let mut buffer = Vec::new();
258    /// let mut tokio_buffer = tokio::io::BufWriter::new(&mut buffer);
259    /// let mut writer = Writer::new_with_indent(&mut tokio_buffer, b' ', 4);
260    ///
261    /// writer
262    ///     .create_element("outer")
263    ///     .with_attributes([("attr1", "value1"), ("attr2", "value2")])
264    ///     // We need to provide error type, because it is not named somewhere explicitly
265    ///     .write_inner_content_async::<_, _, Error>(|writer| async move {
266    ///         let fruits = ["apple", "orange", "banana"];
267    ///         for (quant, item) in fruits.iter().enumerate() {
268    ///             writer
269    ///                 .create_element("fruit")
270    ///                 .with_attributes([("quantity", quant.to_string().as_str())])
271    ///                 .write_text_content_async(BytesText::new(item))
272    ///                 .await?;
273    ///         }
274    ///         writer
275    ///             .create_element("inner")
276    ///             .write_inner_content_async(|writer| async move {
277    ///                 writer.create_element("empty").write_empty_async().await
278    ///             })
279    ///             .await?;
280    ///
281    ///         Ok(writer)
282    ///     })
283    ///     .await
284    ///     .expect("cannot write content");
285    ///
286    /// tokio_buffer.flush().await.expect("flush failed");
287    /// assert_eq!(
288    ///     std::str::from_utf8(&buffer).unwrap(),
289    ///     r#"<outer attr1="value1" attr2="value2">
290    ///     <fruit quantity="0">apple</fruit>
291    ///     <fruit quantity="1">orange</fruit>
292    ///     <fruit quantity="2">banana</fruit>
293    ///     <inner>
294    ///         <empty/>
295    ///     </inner>
296    /// </outer>"#
297    /// );
298    /// # }
299    pub async fn write_inner_content_async<F, Fut, E>(
300        mut self,
301        closure: F,
302    ) -> StdResult<&'a mut Writer<W>, E>
303    where
304        F: FnOnce(&'a mut Writer<W>) -> Fut,
305        Fut: Future<Output = StdResult<&'a mut Writer<W>, E>>,
306        E: From<Error>,
307    {
308        self.writer
309            .write_event_async(Event::Start(self.start_tag.borrow()))
310            .await?;
311        self.writer = closure(self.writer).await?;
312        self.writer
313            .write_event_async(Event::End(self.start_tag.to_end()))
314            .await?;
315        Ok(self.writer)
316    }
317}
318
319#[cfg(test)]
320mod tests {
321    use super::*;
322    use crate::events::*;
323    use pretty_assertions::assert_eq;
324
325    macro_rules! test {
326        ($name: ident, $event: expr, $expected: expr) => {
327            #[tokio::test]
328            async fn $name() {
329                let mut buffer = Vec::new();
330                let mut writer = Writer::new(&mut buffer);
331
332                writer
333                    .write_event_async($event)
334                    .await
335                    .expect("write event failed");
336
337                assert_eq!(std::str::from_utf8(&buffer).unwrap(), $expected,);
338            }
339        };
340    }
341
342    test!(
343        xml_header,
344        Event::Decl(BytesDecl::new("1.0", Some("UTF-8"), Some("no"))),
345        r#"<?xml version="1.0" encoding="UTF-8" standalone="no"?>"#
346    );
347
348    test!(empty_tag, Event::Empty(BytesStart::new("tag")), r#"<tag/>"#);
349
350    test!(
351        comment,
352        Event::Comment(BytesText::new("this is a comment")),
353        r#"<!--this is a comment-->"#
354    );
355
356    test!(
357        cdata,
358        Event::CData(BytesCData::new("this is a cdata")),
359        r#"<![CDATA[this is a cdata]]>"#
360    );
361
362    test!(
363        pi,
364        Event::PI(BytesPI::new("this is a processing instruction")),
365        r#"<?this is a processing instruction?>"#
366    );
367
368    test!(
369        doctype,
370        Event::DocType(BytesText::new("this is a doctype")),
371        r#"<!DOCTYPE this is a doctype>"#
372    );
373
374    #[tokio::test]
375    async fn full_tag() {
376        let mut buffer = Vec::new();
377        let mut writer = Writer::new(&mut buffer);
378
379        let start = Event::Start(BytesStart::new("tag"));
380        let text = Event::Text(BytesText::new("inner text"));
381        let end = Event::End(BytesEnd::new("tag"));
382        for i in [start, text, end] {
383            writer.write_event_async(i).await.expect("write tag failed");
384        }
385
386        assert_eq!(
387            std::str::from_utf8(&buffer).unwrap(),
388            r#"<tag>inner text</tag>"#
389        );
390    }
391}
392
393#[cfg(test)]
394mod indentation_async {
395    use super::*;
396    use crate::events::*;
397    use pretty_assertions::assert_eq;
398
399    #[tokio::test]
400    async fn self_closed() {
401        let mut buffer = Vec::new();
402        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
403
404        let tag = BytesStart::new("self-closed")
405            .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
406        writer
407            .write_event_async(Event::Empty(tag))
408            .await
409            .expect("write tag failed");
410
411        assert_eq!(
412            std::str::from_utf8(&buffer).unwrap(),
413            r#"<self-closed attr1="value1" attr2="value2"/>"#
414        );
415    }
416
417    #[tokio::test]
418    async fn empty_paired() {
419        let mut buffer = Vec::new();
420        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
421
422        let start = BytesStart::new("paired")
423            .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
424        let end = start.to_end();
425        writer
426            .write_event_async(Event::Start(start.clone()))
427            .await
428            .expect("write start tag failed");
429        writer
430            .write_event_async(Event::End(end))
431            .await
432            .expect("write end tag failed");
433
434        assert_eq!(
435            std::str::from_utf8(&buffer).unwrap(),
436            r#"<paired attr1="value1" attr2="value2">
437</paired>"#
438        );
439    }
440
441    #[tokio::test]
442    async fn paired_with_inner() {
443        let mut buffer = Vec::new();
444        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
445
446        let start = BytesStart::new("paired")
447            .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
448        let end = start.to_end();
449        let inner = BytesStart::new("inner");
450
451        writer
452            .write_event_async(Event::Start(start.clone()))
453            .await
454            .expect("write start tag failed");
455        writer
456            .write_event_async(Event::Empty(inner))
457            .await
458            .expect("write inner tag failed");
459        writer
460            .write_event_async(Event::End(end))
461            .await
462            .expect("write end tag failed");
463
464        assert_eq!(
465            std::str::from_utf8(&buffer).unwrap(),
466            r#"<paired attr1="value1" attr2="value2">
467    <inner/>
468</paired>"#
469        );
470    }
471
472    #[tokio::test]
473    async fn paired_with_text() {
474        let mut buffer = Vec::new();
475        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
476
477        let start = BytesStart::new("paired")
478            .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
479        let end = start.to_end();
480        let text = BytesText::new("text");
481
482        writer
483            .write_event_async(Event::Start(start.clone()))
484            .await
485            .expect("write start tag failed");
486        writer
487            .write_event_async(Event::Text(text))
488            .await
489            .expect("write text failed");
490        writer
491            .write_event_async(Event::End(end))
492            .await
493            .expect("write end tag failed");
494
495        assert_eq!(
496            std::str::from_utf8(&buffer).unwrap(),
497            r#"<paired attr1="value1" attr2="value2">text</paired>"#
498        );
499    }
500
501    #[tokio::test]
502    async fn mixed_content() {
503        let mut buffer = Vec::new();
504        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
505
506        let start = BytesStart::new("paired")
507            .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
508        let end = start.to_end();
509        let text = BytesText::new("text");
510        let inner = BytesStart::new("inner");
511
512        writer
513            .write_event_async(Event::Start(start.clone()))
514            .await
515            .expect("write start tag failed");
516        writer
517            .write_event_async(Event::Text(text))
518            .await
519            .expect("write text failed");
520        writer
521            .write_event_async(Event::Empty(inner))
522            .await
523            .expect("write inner tag failed");
524        writer
525            .write_event_async(Event::End(end))
526            .await
527            .expect("write end tag failed");
528
529        assert_eq!(
530            std::str::from_utf8(&buffer).unwrap(),
531            r#"<paired attr1="value1" attr2="value2">text<inner/>
532</paired>"#
533        );
534    }
535
536    #[tokio::test]
537    async fn nested() {
538        let mut buffer = Vec::new();
539        let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
540
541        let start = BytesStart::new("paired")
542            .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
543        let end = start.to_end();
544        let inner = BytesStart::new("inner");
545
546        writer
547            .write_event_async(Event::Start(start.clone()))
548            .await
549            .expect("write start 1 tag failed");
550        writer
551            .write_event_async(Event::Start(start.clone()))
552            .await
553            .expect("write start 2 tag failed");
554        writer
555            .write_event_async(Event::Empty(inner))
556            .await
557            .expect("write inner tag failed");
558        writer
559            .write_event_async(Event::End(end.clone()))
560            .await
561            .expect("write end tag 2 failed");
562        writer
563            .write_event_async(Event::End(end))
564            .await
565            .expect("write end tag 1 failed");
566
567        assert_eq!(
568            std::str::from_utf8(&buffer).unwrap(),
569            r#"<paired attr1="value1" attr2="value2">
570    <paired attr1="value1" attr2="value2">
571        <inner/>
572    </paired>
573</paired>"#
574        );
575    }
576}