1use crate::errors::{Error, Result};
4use crate::events::{attributes::Attribute, BytesCData, BytesStart, BytesText, Event};
5use std::io::Write;
6
7#[derive(Clone)]
57pub struct Writer<W: Write> {
58 writer: W,
60 indent: Option<Indentation>,
61}
62
63impl<W: Write> Writer<W> {
64 pub fn new(inner: W) -> Writer<W> {
66 Writer {
67 writer: inner,
68 indent: None,
69 }
70 }
71
72 pub fn new_with_indent(inner: W, indent_char: u8, indent_size: usize) -> Writer<W> {
74 Writer {
75 writer: inner,
76 indent: Some(Indentation::new(indent_char, indent_size)),
77 }
78 }
79
80 pub fn into_inner(self) -> W {
82 self.writer
83 }
84
85 pub fn inner(&mut self) -> &mut W {
87 &mut self.writer
88 }
89
90 pub fn write_event<'a, E: AsRef<Event<'a>>>(&mut self, event: E) -> Result<()> {
92 let mut next_should_line_break = true;
93 let result = match *event.as_ref() {
94 Event::Start(ref e) => {
95 let result = self.write_wrapped(b"<", e, b">");
96 if let Some(i) = self.indent.as_mut() {
97 i.grow();
98 }
99 result
100 }
101 Event::End(ref e) => {
102 if let Some(i) = self.indent.as_mut() {
103 i.shrink();
104 }
105 self.write_wrapped(b"</", e, b">")
106 }
107 Event::Empty(ref e) => self.write_wrapped(b"<", e, b"/>"),
108 Event::Text(ref e) => {
109 next_should_line_break = false;
110 self.write(&e.escaped())
111 }
112 Event::Comment(ref e) => self.write_wrapped(b"<!--", e, b"-->"),
113 Event::CData(ref e) => {
114 next_should_line_break = false;
115 self.write(b"<![CDATA[")?;
116 self.write(e)?;
117 self.write(b"]]>")
118 }
119 Event::Decl(ref e) => self.write_wrapped(b"<?", e, b"?>"),
120 Event::PI(ref e) => self.write_wrapped(b"<?", e, b"?>"),
121 Event::DocType(ref e) => self.write_wrapped(b"<!DOCTYPE ", e, b">"),
122 Event::Eof => Ok(()),
123 };
124 if let Some(i) = self.indent.as_mut() {
125 i.should_line_break = next_should_line_break;
126 }
127 result
128 }
129
130 #[inline]
132 pub fn write(&mut self, value: &[u8]) -> Result<()> {
133 self.writer.write_all(value).map_err(Error::Io)
134 }
135
136 #[inline]
137 fn write_wrapped(&mut self, before: &[u8], value: &[u8], after: &[u8]) -> Result<()> {
138 if let Some(ref i) = self.indent {
139 if i.should_line_break {
140 self.writer.write_all(b"\n").map_err(Error::Io)?;
141 self.writer
142 .write_all(&i.indents[..i.indents_len])
143 .map_err(Error::Io)?;
144 }
145 }
146 self.write(before)?;
147 self.write(value)?;
148 self.write(after)?;
149 Ok(())
150 }
151
152 pub fn write_indent(&mut self) -> Result<()> {
162 if let Some(ref i) = self.indent {
163 self.writer.write_all(b"\n").map_err(Error::Io)?;
164 self.writer
165 .write_all(&i.indents[..i.indents_len])
166 .map_err(Error::Io)?;
167 }
168 Ok(())
169 }
170
171 #[must_use]
212 pub fn create_element<'a, N>(&'a mut self, name: &'a N) -> ElementWriter<W>
213 where
214 N: 'a + AsRef<[u8]> + ?Sized,
215 {
216 ElementWriter {
217 writer: self,
218 start_tag: BytesStart::borrowed_name(name.as_ref()),
219 }
220 }
221}
222
223pub struct ElementWriter<'a, W: Write> {
226 writer: &'a mut Writer<W>,
227 start_tag: BytesStart<'a>,
228}
229
230impl<'a, W: Write> ElementWriter<'a, W> {
231 pub fn with_attribute<'b, I>(mut self, attr: I) -> Self
233 where
234 I: Into<Attribute<'b>>,
235 {
236 self.start_tag.push_attribute(attr);
237 self
238 }
239
240 pub fn with_attributes<'b, I>(mut self, attributes: I) -> Self
244 where
245 I: IntoIterator,
246 I::Item: Into<Attribute<'b>>,
247 {
248 self.start_tag.extend_attributes(attributes);
249 self
250 }
251
252 pub fn write_text_content(self, text: BytesText) -> Result<&'a mut Writer<W>> {
254 self.writer
255 .write_event(Event::Start(self.start_tag.to_borrowed()))?;
256 self.writer.write_event(Event::Text(text))?;
257 self.writer
258 .write_event(Event::End(self.start_tag.to_end()))?;
259 Ok(self.writer)
260 }
261
262 pub fn write_cdata_content(self, text: BytesCData) -> Result<&'a mut Writer<W>> {
264 self.writer
265 .write_event(Event::Start(self.start_tag.to_borrowed()))?;
266 self.writer.write_event(Event::CData(text))?;
267 self.writer
268 .write_event(Event::End(self.start_tag.to_end()))?;
269 Ok(self.writer)
270 }
271
272 pub fn write_pi_content(self, text: BytesText) -> Result<&'a mut Writer<W>> {
274 self.writer
275 .write_event(Event::Start(self.start_tag.to_borrowed()))?;
276 self.writer.write_event(Event::PI(text))?;
277 self.writer
278 .write_event(Event::End(self.start_tag.to_end()))?;
279 Ok(self.writer)
280 }
281
282 pub fn write_empty(self) -> Result<&'a mut Writer<W>> {
284 self.writer.write_event(Event::Empty(self.start_tag))?;
285 Ok(self.writer)
286 }
287
288 pub fn write_inner_content<F>(mut self, closure: F) -> Result<&'a mut Writer<W>>
290 where
291 F: Fn(&mut Writer<W>) -> Result<()>,
292 {
293 self.writer
294 .write_event(Event::Start(self.start_tag.to_borrowed()))?;
295 closure(&mut self.writer)?;
296 self.writer
297 .write_event(Event::End(self.start_tag.to_end()))?;
298 Ok(self.writer)
299 }
300}
301
302#[derive(Clone)]
303struct Indentation {
304 should_line_break: bool,
305 indent_char: u8,
306 indent_size: usize,
307 indents: Vec<u8>,
308 indents_len: usize,
309}
310
311impl Indentation {
312 fn new(indent_char: u8, indent_size: usize) -> Indentation {
313 Indentation {
314 should_line_break: false,
315 indent_char,
316 indent_size,
317 indents: vec![indent_char; 128],
318 indents_len: 0,
319 }
320 }
321
322 fn grow(&mut self) {
323 self.indents_len += self.indent_size;
324 if self.indents_len > self.indents.len() {
325 self.indents.resize(self.indents_len, self.indent_char);
326 }
327 }
328
329 fn shrink(&mut self) {
330 self.indents_len = match self.indents_len.checked_sub(self.indent_size) {
331 Some(result) => result,
332 None => 0,
333 };
334 }
335}
336
337#[cfg(test)]
338mod indentation {
339 use super::*;
340 use crate::events::*;
341 use pretty_assertions::assert_eq;
342
343 #[test]
344 fn self_closed() {
345 let mut buffer = Vec::new();
346 let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
347
348 let tag = BytesStart::borrowed_name(b"self-closed")
349 .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
350 writer
351 .write_event(Event::Empty(tag))
352 .expect("write tag failed");
353
354 assert_eq!(
355 std::str::from_utf8(&buffer).unwrap(),
356 r#"<self-closed attr1="value1" attr2="value2"/>"#
357 );
358 }
359
360 #[test]
361 fn empty_paired() {
362 let mut buffer = Vec::new();
363 let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
364
365 let name = b"paired";
366 let start = BytesStart::borrowed_name(name)
367 .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
368 let end = BytesEnd::borrowed(name);
369 writer
370 .write_event(Event::Start(start))
371 .expect("write start tag failed");
372 writer
373 .write_event(Event::End(end))
374 .expect("write end tag failed");
375
376 assert_eq!(
377 std::str::from_utf8(&buffer).unwrap(),
378 r#"<paired attr1="value1" attr2="value2">
379</paired>"#
380 );
381 }
382
383 #[test]
384 fn paired_with_inner() {
385 let mut buffer = Vec::new();
386 let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
387
388 let name = b"paired";
389 let start = BytesStart::borrowed_name(name)
390 .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
391 let end = BytesEnd::borrowed(name);
392 let inner = BytesStart::borrowed_name(b"inner");
393
394 writer
395 .write_event(Event::Start(start))
396 .expect("write start tag failed");
397 writer
398 .write_event(Event::Empty(inner))
399 .expect("write inner tag failed");
400 writer
401 .write_event(Event::End(end))
402 .expect("write end tag failed");
403
404 assert_eq!(
405 std::str::from_utf8(&buffer).unwrap(),
406 r#"<paired attr1="value1" attr2="value2">
407 <inner/>
408</paired>"#
409 );
410 }
411
412 #[test]
413 fn paired_with_text() {
414 let mut buffer = Vec::new();
415 let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
416
417 let name = b"paired";
418 let start = BytesStart::borrowed_name(name)
419 .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
420 let end = BytesEnd::borrowed(name);
421 let text = BytesText::from_plain(b"text");
422
423 writer
424 .write_event(Event::Start(start))
425 .expect("write start tag failed");
426 writer
427 .write_event(Event::Text(text))
428 .expect("write text failed");
429 writer
430 .write_event(Event::End(end))
431 .expect("write end tag failed");
432
433 assert_eq!(
434 std::str::from_utf8(&buffer).unwrap(),
435 r#"<paired attr1="value1" attr2="value2">text</paired>"#
436 );
437 }
438
439 #[test]
440 fn mixed_content() {
441 let mut buffer = Vec::new();
442 let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
443
444 let name = b"paired";
445 let start = BytesStart::borrowed_name(name)
446 .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
447 let end = BytesEnd::borrowed(name);
448 let text = BytesText::from_plain(b"text");
449 let inner = BytesStart::borrowed_name(b"inner");
450
451 writer
452 .write_event(Event::Start(start))
453 .expect("write start tag failed");
454 writer
455 .write_event(Event::Text(text))
456 .expect("write text failed");
457 writer
458 .write_event(Event::Empty(inner))
459 .expect("write inner tag failed");
460 writer
461 .write_event(Event::End(end))
462 .expect("write end tag failed");
463
464 assert_eq!(
465 std::str::from_utf8(&buffer).unwrap(),
466 r#"<paired attr1="value1" attr2="value2">text<inner/>
467</paired>"#
468 );
469 }
470
471 #[test]
472 fn nested() {
473 let mut buffer = Vec::new();
474 let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
475
476 let name = b"paired";
477 let start = BytesStart::borrowed_name(name)
478 .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter());
479 let end = BytesEnd::borrowed(name);
480 let inner = BytesStart::borrowed_name(b"inner");
481
482 writer
483 .write_event(Event::Start(start.clone()))
484 .expect("write start 1 tag failed");
485 writer
486 .write_event(Event::Start(start))
487 .expect("write start 2 tag failed");
488 writer
489 .write_event(Event::Empty(inner))
490 .expect("write inner tag failed");
491 writer
492 .write_event(Event::End(end.clone()))
493 .expect("write end tag 2 failed");
494 writer
495 .write_event(Event::End(end))
496 .expect("write end tag 1 failed");
497
498 assert_eq!(
499 std::str::from_utf8(&buffer).unwrap(),
500 r#"<paired attr1="value1" attr2="value2">
501 <paired attr1="value1" attr2="value2">
502 <inner/>
503 </paired>
504</paired>"#
505 );
506 }
507 #[test]
508 fn element_writer_empty() {
509 let mut buffer = Vec::new();
510 let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
511
512 writer
513 .create_element(b"empty")
514 .with_attribute(("attr1", "value1"))
515 .with_attribute(("attr2", "value2"))
516 .write_empty()
517 .expect("failure");
518
519 assert_eq!(
520 std::str::from_utf8(&buffer).unwrap(),
521 r#"<empty attr1="value1" attr2="value2"/>"#
522 );
523 }
524
525 #[test]
526 fn element_writer_text() {
527 let mut buffer = Vec::new();
528 let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
529
530 writer
531 .create_element("paired")
532 .with_attribute(("attr1", "value1"))
533 .with_attribute(("attr2", "value2"))
534 .write_text_content(BytesText::from_plain_str("text"))
535 .expect("failure");
536
537 assert_eq!(
538 std::str::from_utf8(&buffer).unwrap(),
539 r#"<paired attr1="value1" attr2="value2">text</paired>"#
540 );
541 }
542
543 #[test]
544 fn element_writer_nested() {
545 let mut buffer = Vec::new();
546 let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
547
548 writer
549 .create_element("outer")
550 .with_attribute(("attr1", "value1"))
551 .with_attribute(("attr2", "value2"))
552 .write_inner_content(|writer| {
553 let fruits = ["apple", "orange", "banana"];
554 for (quant, item) in fruits.iter().enumerate() {
555 writer
556 .create_element("fruit")
557 .with_attribute(("quantity", quant.to_string().as_str()))
558 .write_text_content(BytesText::from_plain_str(item))?;
559 }
560 writer
561 .create_element("inner")
562 .write_inner_content(|writer| {
563 writer.create_element("empty").write_empty()?;
564 Ok(())
565 })?;
566
567 Ok(())
568 })
569 .expect("failure");
570
571 assert_eq!(
572 std::str::from_utf8(&buffer).unwrap(),
573 r#"<outer attr1="value1" attr2="value2">
574 <fruit quantity="0">apple</fruit>
575 <fruit quantity="1">orange</fruit>
576 <fruit quantity="2">banana</fruit>
577 <inner>
578 <empty/>
579 </inner>
580</outer>"#
581 );
582 }
583}