Skip to content

Commit 79ff317

Browse files
Rémi Labeyriedralley
Rémi Labeyrie
authored andcommitted
implement write_serializable_content on element writer
1 parent 5fc695e commit 79ff317

File tree

5 files changed

+111
-8
lines changed

5 files changed

+111
-8
lines changed

src/errors.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ pub enum Error {
4343
EscapeError(EscapeError),
4444
/// Specified namespace prefix is unknown, cannot resolve namespace for it
4545
UnknownPrefix(Vec<u8>),
46+
/// Serialization error
47+
NonSerializable(String),
4648
}
4749

4850
impl From<IoError> for Error {
@@ -116,6 +118,7 @@ impl fmt::Display for Error {
116118
write_byte_string(f, prefix)?;
117119
f.write_str("'")
118120
}
121+
Error::NonSerializable(e) => write!(f, "error while serializing value: {e}"),
119122
}
120123
}
121124
}

src/se/content.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,7 @@ pub(super) mod tests {
670670
let ser = ContentSerializer {
671671
writer: &mut buffer,
672672
level: QuoteLevel::Full,
673-
indent: Indent::Owned(Indentation::new(b' ', 2)),
673+
indent: Indent::Owned(Indentation::new(b' ', 2, 0)),
674674
write_indent: false,
675675
};
676676

@@ -690,7 +690,7 @@ pub(super) mod tests {
690690
let ser = ContentSerializer {
691691
writer: &mut buffer,
692692
level: QuoteLevel::Full,
693-
indent: Indent::Owned(Indentation::new(b' ', 2)),
693+
indent: Indent::Owned(Indentation::new(b' ', 2, 0)),
694694
write_indent: false,
695695
};
696696

src/se/element.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1531,7 +1531,7 @@ mod tests {
15311531
ser: ContentSerializer {
15321532
writer: &mut buffer,
15331533
level: QuoteLevel::Full,
1534-
indent: Indent::Owned(Indentation::new(b' ', 2)),
1534+
indent: Indent::Owned(Indentation::new(b' ', 2, 0)),
15351535
write_indent: false,
15361536
},
15371537
key: XmlName("root"),
@@ -1554,7 +1554,7 @@ mod tests {
15541554
ser: ContentSerializer {
15551555
writer: &mut buffer,
15561556
level: QuoteLevel::Full,
1557-
indent: Indent::Owned(Indentation::new(b' ', 2)),
1557+
indent: Indent::Owned(Indentation::new(b' ', 2, 0)),
15581558
write_indent: false,
15591559
},
15601560
key: XmlName("root"),

src/se/mod.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,17 @@ impl<'w, 'r, W: Write> Serializer<'w, 'r, W> {
529529

530530
/// Configure indent for a serializer
531531
pub fn indent(&mut self, indent_char: char, indent_size: usize) -> &mut Self {
532-
self.ser.indent = Indent::Owned(Indentation::new(indent_char as u8, indent_size));
532+
self.indent_with_len(indent_char, indent_size, 0)
533+
}
534+
535+
/// Set initial indent level for a serializer
536+
pub fn indent_with_len(
537+
&mut self,
538+
indent_char: char,
539+
indent_size: usize,
540+
indents_len: usize,
541+
) -> &mut Self {
542+
self.ser.indent = Indent::Owned(Indentation::new(indent_char as u8, indent_size, indents_len));
533543
self
534544
}
535545

src/writer.rs

Lines changed: 93 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
33
use std::io::Write;
44

5+
#[cfg(feature = "serialize")]
6+
use serde::Serialize;
7+
58
use crate::encoding::UTF8_BOM;
69
use crate::errors::Result;
710
use crate::events::{attributes::Attribute, BytesCData, BytesStart, BytesText, Event};
@@ -75,7 +78,7 @@ impl<W> Writer<W> {
7578
pub fn new_with_indent(inner: W, indent_char: u8, indent_size: usize) -> Writer<W> {
7679
Writer {
7780
writer: inner,
78-
indent: Some(Indentation::new(indent_char, indent_size)),
81+
indent: Some(Indentation::new(indent_char, indent_size, 0)),
7982
}
8083
}
8184

@@ -340,6 +343,48 @@ impl<'a, W: Write> ElementWriter<'a, W> {
340343
.write_event(Event::End(self.start_tag.to_end()))?;
341344
Ok(self.writer)
342345
}
346+
347+
/// Serialize an arbitrary value inside the current element
348+
#[cfg(feature = "serialize")]
349+
pub fn write_serializable_content<T: Serialize>(self, content: T) -> Result<&'a mut Writer<W>> {
350+
use crate::se::Serializer;
351+
352+
self.writer
353+
.write_event(Event::Start(self.start_tag.borrow()))?;
354+
self.writer.write_indent()?;
355+
356+
let indent = self.writer.indent.clone();
357+
let mut serializer = Serializer::new(ToFmtWrite(self.writer.inner()));
358+
359+
if let Some(indent) = indent {
360+
serializer.indent_with_len(
361+
indent.indent_char as char,
362+
indent.indent_size,
363+
indent.indents_len,
364+
);
365+
}
366+
367+
if let Err(error) = content.serialize(serializer) {
368+
return Err(Error::NonSerializable(error.to_string()));
369+
}
370+
371+
self.writer
372+
.write_event(Event::End(self.start_tag.to_end()))?;
373+
Ok(self.writer)
374+
}
375+
}
376+
377+
#[cfg(feature = "serialize")]
378+
struct ToFmtWrite<T>(pub T);
379+
380+
#[cfg(feature = "serialize")]
381+
impl<T> std::fmt::Write for ToFmtWrite<T>
382+
where
383+
T: std::io::Write,
384+
{
385+
fn write_str(&mut self, s: &str) -> std::fmt::Result {
386+
self.0.write_all(s.as_bytes()).map_err(|_| std::fmt::Error)
387+
}
343388
}
344389

345390
#[derive(Clone)]
@@ -352,13 +397,13 @@ pub(crate) struct Indentation {
352397
}
353398

354399
impl Indentation {
355-
pub fn new(indent_char: u8, indent_size: usize) -> Self {
400+
pub fn new(indent_char: u8, indent_size: usize, indents_len: usize) -> Self {
356401
Self {
357402
should_line_break: false,
358403
indent_char,
359404
indent_size,
360405
indents: vec![indent_char; 128],
361-
indents_len: 0,
406+
indents_len: indents_len,
362407
}
363408
}
364409

@@ -623,4 +668,49 @@ mod indentation {
623668
</outer>"#
624669
);
625670
}
671+
672+
#[cfg(feature = "serialize")]
673+
#[derive(Serialize)]
674+
struct Foo {
675+
bar: Bar,
676+
val: String,
677+
}
678+
679+
#[cfg(feature = "serialize")]
680+
#[derive(Serialize)]
681+
struct Bar {
682+
baz: usize,
683+
bat: usize,
684+
}
685+
686+
#[cfg(feature = "serialize")]
687+
#[test]
688+
fn element_writer_serialize() {
689+
let mut buffer = Vec::new();
690+
let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4);
691+
let content = Foo {
692+
bar: Bar { baz: 42, bat: 43 },
693+
val: "foo".to_owned(),
694+
};
695+
696+
writer
697+
.create_element("paired")
698+
.with_attribute(("attr1", "value1"))
699+
.with_attribute(("attr2", "value2"))
700+
.write_serializable_content(content)
701+
.expect("failure");
702+
703+
assert_eq!(
704+
std::str::from_utf8(&buffer).unwrap(),
705+
r#"<paired attr1="value1" attr2="value2">
706+
<Foo>
707+
<bar>
708+
<baz>42</baz>
709+
<bat>43</bat>
710+
</bar>
711+
<val>foo</val>
712+
</Foo>
713+
</paired>"#
714+
);
715+
}
626716
}

0 commit comments

Comments
 (0)