diff --git a/src/se/content.rs b/src/se/content.rs index 4a1a97c9..053208b8 100644 --- a/src/se/content.rs +++ b/src/se/content.rs @@ -668,7 +668,7 @@ pub(super) mod tests { let ser = ContentSerializer { writer: String::new(), level: QuoteLevel::Full, - indent: Indent::Owned(Indentation::new(b' ', 2)), + indent: Indent::Owned(Indentation::new(b' ', 2, 0)), write_indent: false, }; @@ -688,7 +688,7 @@ pub(super) mod tests { let ser = ContentSerializer { writer: &mut buffer, level: QuoteLevel::Full, - indent: Indent::Owned(Indentation::new(b' ', 2)), + indent: Indent::Owned(Indentation::new(b' ', 2, 0)), write_indent: false, }; diff --git a/src/se/element.rs b/src/se/element.rs index 57033290..1260c4b8 100644 --- a/src/se/element.rs +++ b/src/se/element.rs @@ -1486,7 +1486,7 @@ mod tests { ser: ContentSerializer { writer: String::new(), level: QuoteLevel::Full, - indent: Indent::Owned(Indentation::new(b' ', 2)), + indent: Indent::Owned(Indentation::new(b' ', 2, 0)), write_indent: false, }, key: XmlName("root"), @@ -1509,7 +1509,7 @@ mod tests { ser: ContentSerializer { writer: &mut buffer, level: QuoteLevel::Full, - indent: Indent::Owned(Indentation::new(b' ', 2)), + indent: Indent::Owned(Indentation::new(b' ', 2, 0)), write_indent: false, }, key: XmlName("root"), diff --git a/src/se/mod.rs b/src/se/mod.rs index 8e559d35..b9fb8619 100644 --- a/src/se/mod.rs +++ b/src/se/mod.rs @@ -366,7 +366,17 @@ impl<'r, W: Write> Serializer<'r, W> { /// Configure indent for a serializer pub fn indent(&mut self, indent_char: char, indent_size: usize) -> &mut Self { - self.ser.indent = Indent::Owned(Indentation::new(indent_char as u8, indent_size)); + self.indent_with_len(indent_char, indent_size, 0) + } + + /// Set initial indent level for a serializer + pub fn indent_with_len( + &mut self, + indent_char: char, + indent_size: usize, + indents_len: usize, + ) -> &mut Self { + self.ser.indent = Indent::Owned(Indentation::new(indent_char as u8, indent_size, indents_len)); self } diff --git a/src/writer.rs b/src/writer.rs index 2c633c74..946572fc 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -6,6 +6,9 @@ use crate::encoding::UTF8_BOM; use crate::errors::{Error, Result}; use crate::events::{attributes::Attribute, BytesCData, BytesStart, BytesText, Event}; +#[cfg(feature = "serialize")] +use {crate::de::DeError, serde::Serialize}; + /// XML writer. Writes XML [`Event`]s to a [`std::io::Write`] implementor. /// /// # Examples @@ -72,7 +75,7 @@ impl Writer { pub fn new_with_indent(inner: W, indent_char: u8, indent_size: usize) -> Writer { Writer { writer: inner, - indent: Some(Indentation::new(indent_char, indent_size)), + indent: Some(Indentation::new(indent_char, indent_size, 0)), } } @@ -330,6 +333,49 @@ impl<'a, W: Write> ElementWriter<'a, W> { .write_event(Event::End(self.start_tag.to_end()))?; Ok(self.writer) } + + /// Serialize an arbitrary value inside the current element + #[cfg(feature = "serialize")] + pub fn write_serializable_content( + self, + content: T, + ) -> std::result::Result<&'a mut Writer, DeError> { + use crate::se::Serializer; + + self.writer + .write_event(Event::Start(self.start_tag.borrow()))?; + self.writer.write_indent()?; + + let indent = self.writer.indent.clone(); + let mut serializer = Serializer::new(ToFmtWrite(self.writer.inner())); + + if let Some(indent) = indent { + serializer.indent_with_len( + indent.indent_char as char, + indent.indent_size, + indent.indents_len, + ); + } + + content.serialize(serializer)?; + + self.writer + .write_event(Event::End(self.start_tag.to_end()))?; + Ok(self.writer) + } +} + +#[cfg(feature = "serialize")] +struct ToFmtWrite(pub T); + +#[cfg(feature = "serialize")] +impl std::fmt::Write for ToFmtWrite +where + T: std::io::Write, +{ + fn write_str(&mut self, s: &str) -> std::fmt::Result { + self.0.write_all(s.as_bytes()).map_err(|_| std::fmt::Error) + } } #[derive(Clone)] @@ -342,13 +388,13 @@ pub(crate) struct Indentation { } impl Indentation { - pub fn new(indent_char: u8, indent_size: usize) -> Self { + pub fn new(indent_char: u8, indent_size: usize, indents_len: usize) -> Self { Self { should_line_break: false, indent_char, indent_size, indents: vec![indent_char; 128], - indents_len: 0, + indents_len, } } @@ -613,4 +659,47 @@ mod indentation { "# ); } + + #[cfg(feature = "serialize")] + #[test] + fn element_writer_serialize() { + #[derive(Serialize)] + struct Foo { + bar: Bar, + val: String, + } + + #[derive(Serialize)] + struct Bar { + baz: usize, + bat: usize, + } + + let mut buffer = Vec::new(); + let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4); + let content = Foo { + bar: Bar { baz: 42, bat: 43 }, + val: "foo".to_owned(), + }; + + writer + .create_element("paired") + .with_attribute(("attr1", "value1")) + .with_attribute(("attr2", "value2")) + .write_serializable_content(content) + .expect("failure"); + + assert_eq!( + std::str::from_utf8(&buffer).unwrap(), + r#" + + + 42 + 43 + + foo + +"# + ); + } }