1use std::future::Future;
10use std::result::Result as StdResult;
11
12use tokio::io::{AsyncWrite, AsyncWriteExt};
13
14use crate::errors::{Error, Result};
15use crate::events::{BytesCData, BytesPI, BytesText, Event};
16use crate::{ElementWriter, Writer};
17
18impl<W: AsyncWrite + Unpin> Writer<W> {
19 #[cfg_attr(docsrs, doc(cfg(feature = "async-tokio")))]
22 pub async fn write_event_async<'a, E: Into<Event<'a>>>(&mut self, event: E) -> Result<()> {
23 let mut next_should_line_break = true;
24 let result = match event.into() {
25 Event::Start(e) => {
26 let result = self.write_wrapped_async(b"<", &e, b">").await;
27 if let Some(i) = self.indent.as_mut() {
28 i.grow();
29 }
30 result
31 }
32 Event::End(e) => {
33 if let Some(i) = self.indent.as_mut() {
34 i.shrink();
35 }
36 self.write_wrapped_async(b"</", &e, b">").await
37 }
38 Event::Empty(e) => self.write_wrapped_async(b"<", &e, b"/>").await,
39 Event::Text(e) => {
40 next_should_line_break = false;
41 self.write_async(&e).await
42 }
43 Event::Comment(e) => self.write_wrapped_async(b"<!--", &e, b"-->").await,
44 Event::CData(e) => {
45 next_should_line_break = false;
46 self.write_async(b"<![CDATA[").await?;
47 self.write_async(&e).await?;
48 self.write_async(b"]]>").await
49 }
50 Event::Decl(e) => self.write_wrapped_async(b"<?", &e, b"?>").await,
51 Event::PI(e) => self.write_wrapped_async(b"<?", &e, b"?>").await,
52 Event::DocType(e) => self.write_wrapped_async(b"<!DOCTYPE ", &e, b">").await,
53 Event::GeneralRef(e) => self.write_wrapped_async(b"&", &e, b";").await,
54 Event::Eof => Ok(()),
55 };
56 if let Some(i) = self.indent.as_mut() {
57 i.should_line_break = next_should_line_break;
58 }
59 result
60 }
61
62 #[cfg_attr(docsrs, doc(cfg(feature = "async-tokio")))]
68 pub async fn write_indent_async(&mut self) -> Result<()> {
69 if let Some(ref i) = self.indent {
70 self.writer.write_all(b"\n").await?;
71 self.writer.write_all(i.current()).await?;
72 }
73 Ok(())
74 }
75
76 #[inline]
77 async fn write_async(&mut self, value: &[u8]) -> Result<()> {
78 self.writer.write_all(value).await.map_err(Error::from)
79 }
80
81 #[inline]
82 async fn write_wrapped_async(
83 &mut self,
84 before: &[u8],
85 value: &[u8],
86 after: &[u8],
87 ) -> Result<()> {
88 if let Some(ref i) = self.indent {
89 if i.should_line_break {
90 self.writer.write_all(b"\n").await?;
91 self.writer.write_all(i.current()).await?;
92 }
93 }
94 self.write_async(before).await?;
95 self.write_async(value).await?;
96 self.write_async(after).await?;
97 Ok(())
98 }
99}
100
101impl<'a, W: AsyncWrite + Unpin> ElementWriter<'a, W> {
102 #[cfg_attr(docsrs, doc(cfg(feature = "async-tokio")))]
134 pub async fn write_text_content_async(self, text: BytesText<'_>) -> Result<&'a mut Writer<W>> {
135 self.writer
136 .write_event_async(Event::Start(self.start_tag.borrow()))
137 .await?;
138 self.writer.write_event_async(Event::Text(text)).await?;
139 self.writer
140 .write_event_async(Event::End(self.start_tag.to_end()))
141 .await?;
142 Ok(self.writer)
143 }
144
145 #[cfg_attr(docsrs, doc(cfg(feature = "async-tokio")))]
148 pub async fn write_cdata_content_async(
149 self,
150 text: BytesCData<'_>,
151 ) -> Result<&'a mut Writer<W>> {
152 self.writer
153 .write_event_async(Event::Start(self.start_tag.borrow()))
154 .await?;
155 self.writer.write_event_async(Event::CData(text)).await?;
156 self.writer
157 .write_event_async(Event::End(self.start_tag.to_end()))
158 .await?;
159 Ok(self.writer)
160 }
161
162 #[cfg_attr(docsrs, doc(cfg(feature = "async-tokio")))]
165 pub async fn write_pi_content_async(self, pi: BytesPI<'_>) -> Result<&'a mut Writer<W>> {
166 self.writer
167 .write_event_async(Event::Start(self.start_tag.borrow()))
168 .await?;
169 self.writer.write_event_async(Event::PI(pi)).await?;
170 self.writer
171 .write_event_async(Event::End(self.start_tag.to_end()))
172 .await?;
173 Ok(self.writer)
174 }
175
176 #[cfg_attr(docsrs, doc(cfg(feature = "async-tokio")))]
179 pub async fn write_empty_async(self) -> Result<&'a mut Writer<W>> {
180 self.writer
181 .write_event_async(Event::Empty(self.start_tag))
182 .await?;
183 Ok(self.writer)
184 }
185
186 #[cfg_attr(docsrs, doc(cfg(feature = "async-tokio")))]
242 pub async fn write_inner_content_async<F, Fut, E>(
243 mut self,
244 closure: F,
245 ) -> StdResult<&'a mut Writer<W>, E>
246 where
247 F: FnOnce(&'a mut Writer<W>) -> Fut,
248 Fut: Future<Output = StdResult<&'a mut Writer<W>, E>>,
249 E: From<Error>,
250 {
251 self.writer
252 .write_event_async(Event::Start(self.start_tag.borrow()))
253 .await?;
254 self.writer = closure(self.writer).await?;
255 self.writer
256 .write_event_async(Event::End(self.start_tag.to_end()))
257 .await?;
258 Ok(self.writer)
259 }
260}
261
262#[cfg(test)]
263mod tests {
264 use super::*;
265 use crate::events::*;
266
267 macro_rules! test {
268 ($name: ident, $event: expr, $expected: expr) => {
269 #[tokio::test]
270 async fn $name() -> Result<()> {
271 let mut buffer = Vec::new();
272 let mut writer = Writer::new(&mut buffer);
273
274 writer.write_event_async($event).await?;
275
276 assert_eq!(std::str::from_utf8(&buffer).expect("utf-8"), $expected);
277 Ok(())
278 }
279 };
280 }
281
282 test!(
283 xml_header,
284 Event::Decl(BytesDecl::new("1.0", Some("UTF-8"), Some("no"))),
285 r#"<?xml version="1.0" encoding="UTF-8" standalone="no"?>"#
286 );
287
288 test!(empty_tag, Event::Empty(BytesStart::new("tag")), r#"<tag/>"#);
289
290 test!(
291 comment,
292 Event::Comment(BytesText::new("this is a comment")),
293 r#"<!--this is a comment-->"#
294 );
295
296 test!(
297 cdata,
298 Event::CData(BytesCData::new("this is a cdata")),
299 r#"<![CDATA[this is a cdata]]>"#
300 );
301
302 test!(
303 pi,
304 Event::PI(BytesPI::new("this is a processing instruction")),
305 r#"<?this is a processing instruction?>"#
306 );
307
308 test!(
309 doctype,
310 Event::DocType(BytesText::new("this is a doctype")),
311 r#"<!DOCTYPE this is a doctype>"#
312 );
313
314 #[tokio::test]
315 async fn full_tag() -> Result<()> {
316 let mut buffer = Vec::new();
317 let mut writer = Writer::new(&mut buffer);
318
319 let start = Event::Start(BytesStart::new("tag"));
320 let text = Event::Text(BytesText::new("inner text"));
321 let end = Event::End(BytesEnd::new("tag"));
322 for i in [start, text, end] {
323 writer.write_event_async(i).await?;
324 }
325
326 assert_eq!(
327 std::str::from_utf8(&buffer).expect("utf-8"),
328 r#"<tag>inner text</tag>"#
329 );
330 Ok(())
331 }
332}
333
334#[cfg(test)]
335mod indentation_async {
336 use super::*;
337 use crate::events::*;
338
339 #[tokio::test]
340 async fn self_closed() -> Result<()> {
341 let mut buffer = Vec::new();
342 let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
343
344 let tag = BytesStart::new("self-closed")
345 .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
346 writer.write_event_async(Event::Empty(tag)).await?;
347
348 assert_eq!(
349 std::str::from_utf8(&buffer).expect("utf-8"),
350 r#"<self-closed attr1="value1" attr2="value2"/>"#
351 );
352 Ok(())
353 }
354
355 #[tokio::test]
356 async fn empty_paired() -> Result<()> {
357 let mut buffer = Vec::new();
358 let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
359
360 let start = BytesStart::new("paired")
361 .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
362 let end = start.to_end();
363 writer
364 .write_event_async(Event::Start(start.clone()))
365 .await?;
366 writer.write_event_async(Event::End(end)).await?;
367
368 assert_eq!(
369 std::str::from_utf8(&buffer).expect("utf-8"),
370 "<paired attr1=\"value1\" attr2=\"value2\">\n</paired>"
371 );
372 Ok(())
373 }
374
375 #[tokio::test]
376 async fn paired_with_inner() -> Result<()> {
377 let mut buffer = Vec::new();
378 let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
379
380 let start = BytesStart::new("paired")
381 .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
382 let end = start.to_end();
383 let inner = BytesStart::new("inner");
384
385 writer
386 .write_event_async(Event::Start(start.clone()))
387 .await?;
388 writer.write_event_async(Event::Empty(inner)).await?;
389 writer.write_event_async(Event::End(end)).await?;
390
391 assert_eq!(
392 std::str::from_utf8(&buffer).expect("utf-8"),
393 "<paired attr1=\"value1\" attr2=\"value2\">\n <inner/>\n</paired>"
394 );
395 Ok(())
396 }
397
398 #[tokio::test]
399 async fn paired_with_text() -> Result<()> {
400 let mut buffer = Vec::new();
401 let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
402
403 let start = BytesStart::new("paired")
404 .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
405 let end = start.to_end();
406 let text = BytesText::new("text");
407
408 writer
409 .write_event_async(Event::Start(start.clone()))
410 .await?;
411 writer.write_event_async(Event::Text(text)).await?;
412 writer.write_event_async(Event::End(end)).await?;
413
414 assert_eq!(
415 std::str::from_utf8(&buffer).expect("utf-8"),
416 r#"<paired attr1="value1" attr2="value2">text</paired>"#
417 );
418 Ok(())
419 }
420
421 #[tokio::test]
422 async fn mixed_content() -> Result<()> {
423 let mut buffer = Vec::new();
424 let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
425
426 let start = BytesStart::new("paired")
427 .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
428 let end = start.to_end();
429 let text = BytesText::new("text");
430 let inner = BytesStart::new("inner");
431
432 writer
433 .write_event_async(Event::Start(start.clone()))
434 .await?;
435 writer.write_event_async(Event::Text(text)).await?;
436 writer.write_event_async(Event::Empty(inner)).await?;
437 writer.write_event_async(Event::End(end)).await?;
438
439 assert_eq!(
440 std::str::from_utf8(&buffer).expect("utf-8"),
441 "<paired attr1=\"value1\" attr2=\"value2\">text<inner/>\n</paired>"
442 );
443 Ok(())
444 }
445
446 #[tokio::test]
447 async fn nested() -> Result<()> {
448 let mut buffer = Vec::new();
449 let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
450
451 let start = BytesStart::new("paired")
452 .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
453 let end = start.to_end();
454 let inner = BytesStart::new("inner");
455
456 writer
457 .write_event_async(Event::Start(start.clone()))
458 .await?;
459 writer
460 .write_event_async(Event::Start(start.clone()))
461 .await?;
462 writer.write_event_async(Event::Empty(inner)).await?;
463 writer.write_event_async(Event::End(end.clone())).await?;
464 writer.write_event_async(Event::End(end)).await?;
465
466 assert_eq!(
467 std::str::from_utf8(&buffer).expect("utf-8"),
468 "<paired attr1=\"value1\" attr2=\"value2\">\n \
469 <paired attr1=\"value1\" attr2=\"value2\">\n \
470 <inner/>\n </paired>\n</paired>"
471 );
472 Ok(())
473 }
474}