Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Behave like Golang xml #1

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/events/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,10 @@ impl<'a> std::fmt::Debug for BytesText<'a> {
/// [`Reader::read_event`]: ../reader/struct.Reader.html#method.read_event
#[derive(Clone, Debug)]
pub enum Event<'a> {
/// Indent glow.
IndentGlow,
/// Indent shrink.
IndentShrink,
/// Start tag (with attributes) `<tag attr="value">`.
Start(BytesStart<'a>),
/// End tag `</tag>`.
Expand Down Expand Up @@ -834,6 +838,8 @@ impl<'a> Event<'a> {
/// buffer used when reading but incurring a new, seperate allocation.
pub fn into_owned(self) -> Event<'static> {
match self {
Event::IndentGlow => Event::IndentGlow,
Event::IndentShrink => Event::IndentShrink,
Event::Start(e) => Event::Start(e.into_owned()),
Event::End(e) => Event::End(e.into_owned()),
Event::Empty(e) => Event::Empty(e.into_owned()),
Expand Down Expand Up @@ -880,6 +886,8 @@ impl<'a> Deref for Event<'a> {
type Target = [u8];
fn deref(&self) -> &[u8] {
match *self {
Event::IndentGlow => &[],
Event::IndentShrink => &[],
Event::Start(ref e) | Event::Empty(ref e) => &*e,
Event::End(ref e) => &*e,
Event::Text(ref e) => &*e,
Expand Down
31 changes: 28 additions & 3 deletions src/se/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ pub fn to_writer<W: Write, S: Serialize>(writer: W, value: &S) -> Result<(), DeE
value.serialize(&mut serializer)
}

/// Serialize struct into a `Write`r
pub fn to_writer_with_indent<W: Write, S: Serialize>(writer: W, value: &S, indent_char: u8, indent_size: usize) -> Result<(), DeError> {
let mut serializer = Serializer::with_root(Writer::new_with_indent(writer, indent_char, indent_size), None);
value.serialize(&mut serializer)
}

/// Serialize struct into a `String`
pub fn to_string<S: Serialize>(value: &S) -> Result<String, DeError> {
let mut writer = Vec::new();
Expand All @@ -26,6 +32,14 @@ pub fn to_string<S: Serialize>(value: &S) -> Result<String, DeError> {
Ok(s)
}

/// Serialize struct into a `String`
pub fn to_string_with_indent<S: Serialize>(value: &S, indent_char: u8, indent_size: usize) -> Result<String, DeError> {
let mut writer = Vec::new();
to_writer_with_indent(&mut writer, value, indent_char, indent_size)?;
let s = String::from_utf8(writer).map_err(|e| crate::errors::Error::Utf8(e.utf8_error()))?;
Ok(s)
}

/// A Serializer
pub struct Serializer<'r, W: Write> {
writer: Writer<W>,
Expand Down Expand Up @@ -98,13 +112,24 @@ impl<'r, W: Write> Serializer<'r, W> {
value: P,
escaped: bool,
) -> Result<(), DeError> {
if let Some(tag) = self.root_tag {
self.writer
.write_event(Event::Start(BytesStart::borrowed_name(tag.as_bytes())))?;
}

let value = value.to_string().into_bytes();
let event = if escaped {
BytesText::from_escaped(value)
} else {
BytesText::from_plain(&value)
};
self.writer.write_event(Event::Text(event))?;

if let Some(tag) = self.root_tag {
self.writer
.write_event(Event::End(BytesEnd::borrowed(tag.as_bytes())))?;
}

Ok(())
}

Expand Down Expand Up @@ -240,7 +265,7 @@ impl<'r, 'w, W: Write> ser::Serializer for &'w mut Serializer<'r, W> {
name: &'static str,
value: &T,
) -> Result<Self::Ok, DeError> {
self.write_paired(self.root_tag.unwrap_or(name), value)
value.serialize(&mut *self)
}

fn serialize_newtype_variant<T: ?Sized + Serialize>(
Expand Down Expand Up @@ -309,7 +334,7 @@ impl<'r, 'w, W: Write> ser::Serializer for &'w mut Serializer<'r, W> {
name: &'static str,
_len: usize,
) -> Result<Self::SerializeStruct, DeError> {
Ok(Struct::new(self, self.root_tag.unwrap_or(name)))
Ok(Struct::new(self, self.root_tag))
}

fn serialize_struct_variant(
Expand All @@ -319,7 +344,7 @@ impl<'r, 'w, W: Write> ser::Serializer for &'w mut Serializer<'r, W> {
variant: &'static str,
_len: usize,
) -> Result<Self::SerializeStructVariant, DeError> {
Ok(Struct::new(self, variant))
Ok(Struct::new(self, Some(variant)))
}
}

Expand Down
98 changes: 71 additions & 27 deletions src/se/var.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,26 @@ where
key: &K,
value: &V,
) -> Result<(), DeError> {
// TODO: Is it possible to ensure our key is never a composite type?
// Anything which isn't a "primitive" would lead to malformed XML here...
write!(self.parent.writer.inner(), "<").map_err(Error::Io)?;
key.serialize(&mut *self.parent)?;
write!(self.parent.writer.inner(), ">").map_err(Error::Io)?;
let mut buffer = Vec::new();
let mut writer = Writer::new(&mut buffer);
if let Some(indent) = &self.parent.writer.indent {
writer.indent = Some(indent.clone());
}
let mut serializer = Serializer::with_root(writer, None);
key.serialize(&mut serializer)?;

let tag = BytesStart::borrowed_name(&buffer);
self.parent
.writer
.write_event(Event::Start(tag.to_borrowed()))?;

let root = self.parent.root_tag.take();
value.serialize(&mut *self.parent)?;
self.parent.root_tag = root;

write!(self.parent.writer.inner(), "</").map_err(Error::Io)?;
key.serialize(&mut *self.parent)?;
write!(self.parent.writer.inner(), ">").map_err(Error::Io)?;
self.parent
.writer
.write_event(Event::End(tag.to_end()))?;
Ok(())
}
}
Expand All @@ -79,25 +88,26 @@ where
parent: &'w mut Serializer<'r, W>,
/// Buffer for holding fields, serialized as attributes. Doesn't allocate
/// if there are no fields represented as attributes
attrs: BytesStart<'w>,
attrs: Option<BytesStart<'w>>,
/// Buffer for holding fields, serialized as elements
children: Vec<u8>,
/// Buffer for serializing one field. Cleared after serialize each field
buffer: Vec<u8>,
begun: bool,
}

impl<'r, 'w, W> Struct<'r, 'w, W>
where
W: 'w + Write,
{
/// Create a new `Struct`
pub fn new(parent: &'w mut Serializer<'r, W>, name: &'r str) -> Self {
let name = name.as_bytes();
pub fn new(parent: &'w mut Serializer<'r, W>, name: Option<&'r str>) -> Self {
Struct {
parent,
attrs: BytesStart::borrowed_name(name),
attrs: name.map(|name| BytesStart::borrowed_name(name.as_bytes())),
children: Vec::new(),
buffer: Vec::new(),
begun: false,
}
}
}
Expand All @@ -114,18 +124,44 @@ where
key: &'static str,
value: &T,
) -> Result<(), DeError> {
if !self.begun {
self.begun = true;
self.parent.writer.write_event(Event::IndentGlow)?;
}

let (key, is_attr, is_name) = match key.strip_suffix(" $attr") {
Some(key) => (key, true, false),
None => {
match key.strip_suffix(" $name") {
Some(key) => (key, false, true),
None => (key, false, false)
}
},
};

if is_name {
if let Some(attrs) = &mut self.attrs {
attrs.set_name(key.as_bytes());
} else {
self.attrs = Some(BytesStart::borrowed_name(key.as_bytes()))
}
return Ok(());
}

// TODO: Inherit indentation state from self.parent.writer
let writer = Writer::new(&mut self.buffer);
let mut serializer = Serializer::with_root(writer, Some(key));
let mut writer = Writer::new(&mut self.buffer);
if let Some(indent) = &self.parent.writer.indent {
writer.indent = Some(indent.clone());
}
let mut serializer = Serializer::with_root(writer, if !is_attr { Some(key) } else { None });
value.serialize(&mut serializer)?;

if !self.buffer.is_empty() {
if self.buffer[0] == b'<' || key == "$value" {
if !is_attr {
// Drains buffer, moves it to children
self.children.append(&mut self.buffer);
} else {
self.attrs
.push_attribute((key.as_bytes(), self.buffer.as_ref()));
} else if let Some(attrs) = &mut self.attrs {
attrs.push_attribute((key.as_bytes(), self.buffer.as_ref()));
self.buffer.clear();
}
}
Expand All @@ -134,16 +170,24 @@ where
}

fn end(self) -> Result<Self::Ok, DeError> {
self.parent.writer.write_event(Event::IndentShrink)?;

if self.children.is_empty() {
self.parent.writer.write_event(Event::Empty(self.attrs))?;
if let Some(attrs) = self.attrs {
self.parent.writer.write_event(Event::Empty(attrs))?;
}
} else {
self.parent
.writer
.write_event(Event::Start(self.attrs.to_borrowed()))?;
if let Some(attrs) = &self.attrs {
self.parent
.writer
.write_event(Event::Start(attrs.to_borrowed()))?;
}
self.parent.writer.write(&self.children)?;
self.parent
.writer
.write_event(Event::End(self.attrs.to_end()))?;
if let Some(attrs) = &self.attrs {
self.parent
.writer
.write_event(Event::End(attrs.to_end()))?;
}
}
Ok(())
}
Expand Down Expand Up @@ -241,9 +285,9 @@ where
where
T: Serialize,
{
write!(self.parent.writer.inner(), "<{}>", self.name).map_err(Error::Io)?;
let root = self.parent.root_tag.replace(self.name);
value.serialize(&mut *self.parent)?;
write!(self.parent.writer.inner(), "</{}>", self.name).map_err(Error::Io)?;
self.parent.root_tag = root;
Ok(())
}

Expand Down
16 changes: 14 additions & 2 deletions src/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ use events::Event;
pub struct Writer<W: Write> {
/// underlying writer
writer: W,
indent: Option<Indentation>,
pub(crate) indent: Option<Indentation>,
}

impl<W: Write> Writer<W> {
Expand Down Expand Up @@ -94,6 +94,18 @@ impl<W: Write> Writer<W> {
pub fn write_event<'a, E: AsRef<Event<'a>>>(&mut self, event: E) -> Result<()> {
let mut next_should_line_break = true;
let result = match *event.as_ref() {
Event::IndentGlow => {
if let Some(i) = self.indent.as_mut() {
i.grow();
}
Ok(())
}
Event::IndentShrink => {
if let Some(i) = self.indent.as_mut() {
i.shrink();
}
Ok(())
}
Event::Start(ref e) => {
let result = self.write_wrapped(b"<", e, b">");
if let Some(i) = self.indent.as_mut() {
Expand Down Expand Up @@ -173,7 +185,7 @@ impl<W: Write> Writer<W> {
}

#[derive(Clone)]
struct Indentation {
pub(crate) struct Indentation {
should_line_break: bool,
indent_char: u8,
indent_size: usize,
Expand Down