diff --git a/Changelog.md b/Changelog.md
index 16d014a0..5f6f6b39 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -14,11 +14,24 @@
### Bug Fixes
+- [#490]: Ensure that serialization of map keys always produces valid XML names.
+ In particular, that means that maps with numeric and numeric-like keys (for
+ example, `"42"`) no longer can be serialized because [XML name] cannot start
+ from a digit
+
### Misc Changes
- [#490]: Removed `$unflatten=` special prefix for fields for serde (de)serializer, because:
- it is useless for deserializer
- serializer was rewritten and does not require it anymore
+
+ This prefix allowed you to serialize struct field as an XML element and now
+ replaced by a more thoughtful system explicitly indicating that a field should
+ be serialized as an attribute by prepending `@` character to its name
+- [#490]: Removed `$primitive=` prefix. That prefix allowed you to serialize struct
+ field as an attribute instead of an element and now replaced by a more thoughtful
+ system explicitly indicating that a field should be serialized as an attribute
+ by prepending `@` character to its name
- [#490]: In addition to the `$value` special name for a field a new `#text`
special name was added:
- `#text` is used if you want to map field to text content only. No markup is
@@ -31,6 +44,7 @@
Refer to [documentation] for details.
[#490]: https://github.com/tafia/quick-xml/pull/490
+[XML name]: https://www.w3.org/TR/xml11/#NT-Name
[documentation]: https://docs.rs/quick-xml/0.27.0/quick_xml/de/index.html#difference-between-text-and-value-special-names
## 0.26.0 -- 2022-10-23
diff --git a/README.md b/README.md
index 29658f4c..9088a107 100644
--- a/README.md
+++ b/README.md
@@ -132,23 +132,6 @@ struct Foo {
Read about the difference in the [documentation](https://docs.rs/quick-xml/latest/quick_xml/de/index.html#difference-between-text-and-value-special-names).
-### Serializing unit variants as primitives
-
-The `$primitive` prefix lets you serialize enum variants without associated values (internally referred to as _unit variants_) as primitive strings rather than self-closing tags. Consider the following definitions:
-
-```rust,ignore
-enum Foo {
- #[serde(rename = "$primitive=Bar")]
- Bar
-}
-
-struct Root {
- foo: Foo
-}
-```
-
-Serializing `Root { foo: Foo::Bar }` will then yield `` instead of ``.
-
### Performance
Note that despite not focusing on performance (there are several unnecessary copies), it remains about 10x faster than serde-xml-rs.
diff --git a/src/de/mod.rs b/src/de/mod.rs
index 41bced18..227bc39e 100644
--- a/src/de/mod.rs
+++ b/src/de/mod.rs
@@ -356,7 +356,6 @@ use std::num::NonZeroUsize;
pub(crate) const TEXT_KEY: &str = "#text";
/// Data represented by any XML markup inside
pub(crate) const VALUE_KEY: &str = "$value";
-pub(crate) const PRIMITIVE_PREFIX: &str = "$primitive=";
/// Simplified event which contains only these variants that used by deserializer
#[derive(Debug, PartialEq, Eq)]
diff --git a/src/se/mod.rs b/src/se/mod.rs
index d6978125..3df5b5f4 100644
--- a/src/se/mod.rs
+++ b/src/se/mod.rs
@@ -77,31 +77,24 @@ mod content;
mod element;
mod key;
pub(crate) mod simple_type;
-mod var;
-
-use self::var::{Map, Seq, Struct, Tuple};
-use crate::{
- de::PRIMITIVE_PREFIX,
- errors::serialize::DeError,
- events::{BytesEnd, BytesStart, BytesText, Event},
- writer::{Indentation, Writer},
-};
+
+use self::content::ContentSerializer;
+use self::element::ElementSerializer;
+use crate::errors::serialize::DeError;
+use crate::writer::Indentation;
use serde::ser::{self, Serialize};
use serde::serde_if_integer128;
-use std::io::Write;
+use std::fmt::Write;
use std::str::from_utf8;
/// Serialize struct into a `Write`r
-pub fn to_writer(writer: W, value: &S) -> Result<(), DeError> {
- let mut serializer = Serializer::new(writer);
- value.serialize(&mut serializer)
+pub fn to_writer(writer: W, value: &S) -> Result {
+ value.serialize(Serializer::new(writer))
}
/// Serialize struct into a `String`
pub fn to_string(value: &S) -> Result {
- let mut writer = Vec::new();
- to_writer(&mut writer, value)?;
- Ok(String::from_utf8(writer)?)
+ to_writer(String::new(), value)
}
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -109,7 +102,7 @@ pub fn to_string(value: &S) -> Result {
/// Defines which characters would be escaped in [`Text`] events and attribute
/// values.
///
-/// [`Text`]: Event::Text
+/// [`Text`]: crate::events::Event::Text
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum QuoteLevel {
/// Performs escaping, escape all characters that could have special meaning
@@ -154,6 +147,18 @@ pub enum QuoteLevel {
////////////////////////////////////////////////////////////////////////////////////////////////////
+/// Implements serialization method by forwarding it to the serializer created by
+/// the helper method [`Serializer::ser`].
+macro_rules! forward {
+ ($name:ident($ty:ty)) => {
+ fn $name(self, value: $ty) -> Result {
+ self.ser(&concat!("`", stringify!($ty), "`"))?.$name(value)
+ }
+ };
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
/// Almost all characters can form a name. Citation from :
///
/// > The overall philosophy of names has changed since XML 1.0. Whereas XML 1.0
@@ -273,9 +278,9 @@ impl<'i> Indent<'i> {
/// A Serializer
pub struct Serializer<'r, W: Write> {
- writer: Writer,
+ ser: ContentSerializer<'r, W>,
/// Name of the root tag. If not specified, deduced from the structure name
- root_tag: Option<&'r str>,
+ root_tag: Option>,
}
impl<'r, W: Write> Serializer<'r, W> {
@@ -285,10 +290,19 @@ impl<'r, W: Write> Serializer<'r, W> {
/// and newtype structs) will end up to an error. Use `with_root` to create
/// serializer with explicitly defined root element name
pub fn new(writer: W) -> Self {
- Self::with_root(Writer::new(writer), None)
+ Self {
+ ser: ContentSerializer {
+ writer,
+ level: QuoteLevel::Full,
+ indent: Indent::None,
+ write_indent: false,
+ },
+ root_tag: None,
+ }
}
- /// Creates a new `Serializer` that uses specified root tag name
+ /// Creates a new `Serializer` that uses specified root tag name. `name` should
+ /// be valid [XML name], otherwise error is returned.
///
/// # Examples
///
@@ -298,14 +312,13 @@ impl<'r, W: Write> Serializer<'r, W> {
/// # use pretty_assertions::assert_eq;
/// # use serde::Serialize;
/// # use quick_xml::se::Serializer;
- /// use quick_xml::writer::Writer;
///
- /// let mut buffer = Vec::new();
- /// let mut writer = Writer::new_with_indent(&mut buffer, b' ', 2);
- /// let mut ser = Serializer::with_root(writer, Some("root"));
+ /// let ser = Serializer::with_root(String::new(), Some("root")).unwrap();
///
- /// "node".serialize(&mut ser).unwrap();
- /// assert_eq!(String::from_utf8(buffer).unwrap(), "node");
+ /// assert_eq!(
+ /// "node".serialize(ser).unwrap(),
+ /// "node"
+ /// );
/// ```
///
/// When serializing a struct, newtype struct, unit struct or tuple `root_tag`
@@ -314,8 +327,7 @@ impl<'r, W: Write> Serializer<'r, W> {
/// ```
/// # use pretty_assertions::assert_eq;
/// # use serde::Serialize;
- /// use quick_xml::se::Serializer;
- /// use quick_xml::writer::Writer;
+ /// # use quick_xml::se::Serializer;
///
/// #[derive(Debug, PartialEq, Serialize)]
/// struct Struct {
@@ -323,144 +335,107 @@ impl<'r, W: Write> Serializer<'r, W> {
/// answer: u32,
/// }
///
- /// let mut buffer = Vec::new();
- /// let mut writer = Writer::new_with_indent(&mut buffer, b' ', 2);
- /// let mut ser = Serializer::with_root(writer, Some("root"));
+ /// let ser = Serializer::with_root(String::new(), Some("root")).unwrap();
///
- /// Struct {
+ /// let data = Struct {
/// question: "The Ultimate Question of Life, the Universe, and Everything".into(),
/// answer: 42,
- /// }.serialize(&mut ser).unwrap();
+ /// };
+ ///
/// assert_eq!(
- /// String::from_utf8(buffer.clone()).unwrap(),
- /// r#""#
+ /// data.serialize(ser).unwrap(),
+ /// "\
+ /// The Ultimate Question of Life, the Universe, and Everything\
+ /// 42\
+ /// "
/// );
/// ```
- pub fn with_root(writer: Writer, root_tag: Option<&'r str>) -> Self {
- Self { writer, root_tag }
+ ///
+ /// [XML name]: https://www.w3.org/TR/REC-xml/#NT-Name
+ pub fn with_root(writer: W, root_tag: Option<&'r str>) -> Result {
+ Ok(Self {
+ ser: ContentSerializer {
+ writer,
+ level: QuoteLevel::Full,
+ indent: Indent::None,
+ write_indent: false,
+ },
+ root_tag: root_tag.map(|tag| XmlName::try_from(tag)).transpose()?,
+ })
}
- fn write_primitive(
- &mut self,
- value: P,
- escaped: bool,
- ) -> Result<(), DeError> {
- let value = value.to_string();
- let event = if escaped {
- BytesText::from_escaped(&value)
- } else {
- BytesText::new(&value)
- };
- self.writer.write_event(Event::Text(event))?;
- Ok(())
+ /// 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
}
- /// Writes self-closed tag `` into inner writer
- fn write_self_closed(&mut self, tag_name: &str) -> Result<(), DeError> {
- self.writer
- .write_event(Event::Empty(BytesStart::new(tag_name)))?;
- Ok(())
+ /// Creates actual serializer or returns an error if root tag is not defined.
+ /// In that case `err` contains the name of type that cannot be serialized.
+ fn ser(self, err: &str) -> Result, DeError> {
+ if let Some(key) = self.root_tag {
+ Ok(ElementSerializer { ser: self.ser, key })
+ } else {
+ Err(DeError::Unsupported(
+ format!("cannot serialize {} without defined root tag", err).into(),
+ ))
+ }
}
- /// Writes a serialized `value` surrounded by `...`
- fn write_paired(
- &mut self,
- tag_name: &str,
- value: &T,
- ) -> Result<(), DeError> {
- self.writer
- .write_event(Event::Start(BytesStart::new(tag_name)))?;
- value.serialize(&mut *self)?;
- self.writer
- .write_event(Event::End(BytesEnd::new(tag_name)))?;
- Ok(())
+ /// Creates actual serializer using root tag or a specified `key` if root tag
+ /// is not defined. Returns an error if root tag is not defined and a `key`
+ /// does not conform [XML rules](XmlName::try_from) for names.
+ fn ser_name(self, key: &'static str) -> Result, DeError> {
+ Ok(ElementSerializer {
+ ser: self.ser,
+ key: match self.root_tag {
+ Some(key) => key,
+ None => XmlName::try_from(key)?,
+ },
+ })
}
}
-impl<'r, 'w, W: Write> ser::Serializer for &'w mut Serializer<'r, W> {
- type Ok = ();
+impl<'r, W: Write> ser::Serializer for Serializer<'r, W> {
+ type Ok = W;
type Error = DeError;
- type SerializeSeq = Seq<'r, 'w, W>;
- type SerializeTuple = Tuple<'r, 'w, W>;
- type SerializeTupleStruct = Tuple<'r, 'w, W>;
- type SerializeTupleVariant = Tuple<'r, 'w, W>;
- type SerializeMap = Map<'r, 'w, W>;
- type SerializeStruct = Struct<'r, 'w, W>;
- type SerializeStructVariant = Struct<'r, 'w, W>;
-
- fn serialize_bool(self, v: bool) -> Result {
- self.write_primitive(if v { "true" } else { "false" }, true)
- }
-
- fn serialize_i8(self, v: i8) -> Result {
- self.write_primitive(v, true)
- }
-
- fn serialize_i16(self, v: i16) -> Result {
- self.write_primitive(v, true)
- }
-
- fn serialize_i32(self, v: i32) -> Result {
- self.write_primitive(v, true)
- }
-
- fn serialize_i64(self, v: i64) -> Result {
- self.write_primitive(v, true)
- }
+ type SerializeSeq = as ser::Serializer>::SerializeSeq;
+ type SerializeTuple = as ser::Serializer>::SerializeTuple;
+ type SerializeTupleStruct = as ser::Serializer>::SerializeTupleStruct;
+ type SerializeTupleVariant =
+ as ser::Serializer>::SerializeTupleVariant;
+ type SerializeMap = as ser::Serializer>::SerializeMap;
+ type SerializeStruct = as ser::Serializer>::SerializeStruct;
+ type SerializeStructVariant =
+ as ser::Serializer>::SerializeStructVariant;
- fn serialize_u8(self, v: u8) -> Result {
- self.write_primitive(v, true)
- }
+ forward!(serialize_bool(bool));
- fn serialize_u16(self, v: u16) -> Result {
- self.write_primitive(v, true)
- }
+ forward!(serialize_i8(i8));
+ forward!(serialize_i16(i16));
+ forward!(serialize_i32(i32));
+ forward!(serialize_i64(i64));
- fn serialize_u32(self, v: u32) -> Result {
- self.write_primitive(v, true)
- }
-
- fn serialize_u64(self, v: u64) -> Result {
- self.write_primitive(v, true)
- }
+ forward!(serialize_u8(u8));
+ forward!(serialize_u16(u16));
+ forward!(serialize_u32(u32));
+ forward!(serialize_u64(u64));
serde_if_integer128! {
- fn serialize_i128(self, v: i128) -> Result {
- self.write_primitive(v, true)
- }
-
- fn serialize_u128(self, v: u128) -> Result {
- self.write_primitive(v, true)
- }
- }
-
- fn serialize_f32(self, v: f32) -> Result {
- self.write_primitive(v, true)
+ forward!(serialize_i128(i128));
+ forward!(serialize_u128(u128));
}
- fn serialize_f64(self, v: f64) -> Result {
- self.write_primitive(v, true)
- }
-
- fn serialize_char(self, v: char) -> Result {
- self.write_primitive(v, false)
- }
-
- fn serialize_str(self, value: &str) -> Result {
- self.write_primitive(value, false)
- }
+ forward!(serialize_f32(f32));
+ forward!(serialize_f64(f64));
- fn serialize_bytes(self, _value: &[u8]) -> Result {
- // TODO: I imagine you'd want to use base64 here.
- // Not sure how to roundtrip effectively though...
- Err(DeError::Unsupported(
- "`serialize_bytes` not supported yet".into(),
- ))
- }
+ forward!(serialize_char(char));
+ forward!(serialize_str(&str));
+ forward!(serialize_bytes(&[u8]));
fn serialize_none(self) -> Result {
- Ok(())
+ Ok(self.ser.writer)
}
fn serialize_some(self, value: &T) -> Result {
@@ -468,25 +443,21 @@ impl<'r, 'w, W: Write> ser::Serializer for &'w mut Serializer<'r, W> {
}
fn serialize_unit(self) -> Result {
- self.serialize_none()
+ self.ser("`()`")?.serialize_unit()
}
fn serialize_unit_struct(self, name: &'static str) -> Result {
- self.write_self_closed(self.root_tag.unwrap_or(name))
+ self.ser_name(name)?.serialize_unit_struct(name)
}
fn serialize_unit_variant(
self,
- _name: &'static str,
- _variant_index: u32,
+ name: &'static str,
+ variant_index: u32,
variant: &'static str,
) -> Result {
- if variant.starts_with(PRIMITIVE_PREFIX) {
- let variant = variant.split_at(PRIMITIVE_PREFIX.len()).1;
- self.write_primitive(variant, false)
- } else {
- self.write_self_closed(variant)
- }
+ self.ser_name(name)?
+ .serialize_unit_variant(name, variant_index, variant)
}
fn serialize_newtype_struct(
@@ -494,85 +465,67 @@ impl<'r, 'w, W: Write> ser::Serializer for &'w mut Serializer<'r, W> {
name: &'static str,
value: &T,
) -> Result {
- self.write_paired(self.root_tag.unwrap_or(name), value)
+ self.ser_name(name)?.serialize_newtype_struct(name, value)
}
fn serialize_newtype_variant(
self,
- _name: &'static str,
- _variant_index: u32,
+ name: &'static str,
+ variant_index: u32,
variant: &'static str,
value: &T,
) -> Result {
- // Flatten structs in enums are serialized as newtype struct variant + map.
- // As serialize_map should write `root_tag` for ordinal maps (because it's
- // only way for maps), and for enums this method already written a tag name
- // (`variant`), we need to clear root tag before writing content and restore
- // it after
- let root = self.root_tag.take();
- let result = self.write_paired(variant, value);
- self.root_tag = root;
- result
+ self.ser_name(name)?
+ .serialize_newtype_variant(name, variant_index, variant, value)
}
- fn serialize_seq(self, _len: Option) -> Result {
- Ok(Seq::new(self))
+ fn serialize_seq(self, len: Option) -> Result {
+ self.ser("sequence")?.serialize_seq(len)
}
- fn serialize_tuple(self, _len: usize) -> Result {
- let tag = match self.root_tag {
- Some(tag) => tag,
- None => {
- return Err(DeError::Custom(
- "cannot serialize unnamed tuple without defined root tag".into(),
- ))
- }
- };
- Ok(Tuple::new(self, tag))
+ fn serialize_tuple(self, len: usize) -> Result {
+ self.ser("unnamed tuple")?.serialize_tuple(len)
}
fn serialize_tuple_struct(
self,
name: &'static str,
- _len: usize,
+ len: usize,
) -> Result {
- Ok(Tuple::new(self, self.root_tag.unwrap_or(name)))
+ self.ser_name(name)?.serialize_tuple_struct(name, len)
}
fn serialize_tuple_variant(
self,
- _name: &'static str,
- _variant_index: u32,
+ name: &'static str,
+ variant_index: u32,
variant: &'static str,
- _len: usize,
+ len: usize,
) -> Result {
- Ok(Tuple::new(self, variant))
+ self.ser_name(name)?
+ .serialize_tuple_variant(name, variant_index, variant, len)
}
- fn serialize_map(self, _len: Option) -> Result {
- if let Some(tag) = self.root_tag {
- // TODO: Write self-closed tag if map is empty
- self.writer
- .write_event(Event::Start(BytesStart::new(tag)))?;
- }
- Ok(Map::new(self))
+ fn serialize_map(self, len: Option) -> Result {
+ self.ser("map")?.serialize_map(len)
}
fn serialize_struct(
self,
name: &'static str,
- _len: usize,
+ len: usize,
) -> Result {
- Ok(Struct::new(self, self.root_tag.unwrap_or(name)))
+ self.ser_name(name)?.serialize_struct(name, len)
}
fn serialize_struct_variant(
self,
- _name: &'static str,
- _variant_index: u32,
+ name: &'static str,
+ variant_index: u32,
variant: &'static str,
- _len: usize,
+ len: usize,
) -> Result {
- Ok(Struct::new(self, variant))
+ self.ser_name(name)?
+ .serialize_struct_variant(name, variant_index, variant, len)
}
}
diff --git a/src/se/var.rs b/src/se/var.rs
deleted file mode 100644
index 15991b57..00000000
--- a/src/se/var.rs
+++ /dev/null
@@ -1,335 +0,0 @@
-use crate::{
- de::{TEXT_KEY, VALUE_KEY},
- errors::{serialize::DeError, Error},
- events::{BytesEnd, BytesStart, Event},
- se::key::QNameSerializer,
- se::Serializer,
- writer::Writer,
-};
-use serde::ser::{self, Serialize};
-use std::io::Write;
-
-/// An implementation of `SerializeMap` for serializing to XML.
-pub struct Map<'r, 'w, W>
-where
- W: 'w + Write,
-{
- parent: &'w mut Serializer<'r, W>,
-}
-
-impl<'r, 'w, W> Map<'r, 'w, W>
-where
- W: 'w + Write,
-{
- /// Create a new Map
- pub fn new(parent: &'w mut Serializer<'r, W>) -> Self {
- Map { parent }
- }
-}
-
-impl<'r, 'w, W> ser::SerializeMap for Map<'r, 'w, W>
-where
- W: 'w + Write,
-{
- type Ok = ();
- type Error = DeError;
-
- fn serialize_key(&mut self, key: &T) -> Result<(), DeError> {
- /*
- Err(DeError::Unsupported(
- "impossible to serialize the key on its own, please use serialize_entry()",
- ))
- */
- write!(self.parent.writer.inner(), "").map_err(Error::Io)?;
- Ok(())
- }
-
- fn serialize_value(&mut self, value: &T) -> Result<(), DeError> {
- value.serialize(&mut *self.parent)
- }
-
- fn end(self) -> Result {
- if let Some(tag) = self.parent.root_tag {
- self.parent
- .writer
- .write_event(Event::End(BytesEnd::new(tag)))?;
- }
- Ok(())
- }
-
- fn serialize_entry(
- &mut self,
- key: &K,
- value: &V,
- ) -> Result<(), DeError> {
- let key = key.serialize(QNameSerializer {
- writer: String::new(),
- })?;
-
- let writer = self.parent.writer.inner();
- writer.write_all(b"<").map_err(Error::Io)?;
- writer.write_all(key.as_bytes()).map_err(Error::Io)?;
- writer.write_all(b">").map_err(Error::Io)?;
-
- value.serialize(&mut *self.parent)?;
-
- let writer = self.parent.writer.inner();
- writer.write_all(b"").map_err(Error::Io)?;
- writer.write_all(key.as_bytes()).map_err(Error::Io)?;
- writer.write_all(b">").map_err(Error::Io)?;
- Ok(())
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
-/// An implementation of `SerializeStruct` for serializing to XML.
-pub struct Struct<'r, 'w, W>
-where
- W: 'w + Write,
-{
- 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>,
- /// Buffer for holding fields, serialized as elements
- children: Vec,
- /// Buffer for serializing one field. Cleared after serialize each field
- buffer: Vec,
-}
-
-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 {
- Struct {
- parent,
- attrs: BytesStart::new(name),
- children: Vec::new(),
- buffer: Vec::new(),
- }
- }
-}
-
-impl<'r, 'w, W> ser::SerializeStruct for Struct<'r, 'w, W>
-where
- W: 'w + Write,
-{
- type Ok = ();
- type Error = DeError;
-
- fn serialize_field(
- &mut self,
- key: &'static str,
- value: &T,
- ) -> Result<(), DeError> {
- // TODO: Inherit indentation state from self.parent.writer
- let writer = Writer::new(&mut self.buffer);
-
- let mut serializer = Serializer::with_root(writer, Some(key));
- value.serialize(&mut serializer)?;
-
- if !self.buffer.is_empty() {
- if self.buffer[0] == b'<' || key == VALUE_KEY || key == TEXT_KEY {
- // Drains buffer, moves it to children
- self.children.append(&mut self.buffer);
- } else {
- self.attrs
- .push_attribute((key.as_bytes(), self.buffer.as_ref()));
- self.buffer.clear();
- }
- }
-
- Ok(())
- }
-
- fn end(self) -> Result {
- if self.children.is_empty() {
- self.parent.writer.write_event(Event::Empty(self.attrs))?;
- } else {
- self.parent
- .writer
- .write_event(Event::Start(self.attrs.borrow()))?;
- self.parent.writer.write(&self.children)?;
- self.parent
- .writer
- .write_event(Event::End(self.attrs.to_end()))?;
- }
- Ok(())
- }
-}
-
-impl<'r, 'w, W> ser::SerializeStructVariant for Struct<'r, 'w, W>
-where
- W: 'w + Write,
-{
- type Ok = ();
- type Error = DeError;
-
- #[inline]
- fn serialize_field(
- &mut self,
- key: &'static str,
- value: &T,
- ) -> Result<(), Self::Error> {
- ::serialize_field(self, key, value)
- }
-
- #[inline]
- fn end(self) -> Result {
- ::end(self)
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
-/// An implementation of `SerializeSeq' for serializing to XML.
-pub struct Seq<'r, 'w, W>
-where
- W: 'w + Write,
-{
- parent: &'w mut Serializer<'r, W>,
-}
-
-impl<'r, 'w, W> Seq<'r, 'w, W>
-where
- W: 'w + Write,
-{
- /// Create a new `Seq`
- pub fn new(parent: &'w mut Serializer<'r, W>) -> Self {
- Seq { parent }
- }
-}
-
-impl<'r, 'w, W> ser::SerializeSeq for Seq<'r, 'w, W>
-where
- W: 'w + Write,
-{
- type Ok = ();
- type Error = DeError;
-
- fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error>
- where
- T: Serialize,
- {
- value.serialize(&mut *self.parent)?;
- Ok(())
- }
-
- fn end(self) -> Result {
- Ok(())
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
-/// An implementation of `SerializeTuple`, `SerializeTupleStruct` and
-/// `SerializeTupleVariant` for serializing to XML.
-pub struct Tuple<'r, 'w, W>
-where
- W: 'w + Write,
-{
- parent: &'w mut Serializer<'r, W>,
- /// Possible qualified name of XML tag surrounding each element
- name: &'r str,
-}
-
-impl<'r, 'w, W> Tuple<'r, 'w, W>
-where
- W: 'w + Write,
-{
- /// Create a new `Tuple`
- pub fn new(parent: &'w mut Serializer<'r, W>, name: &'r str) -> Self {
- Tuple { parent, name }
- }
-}
-
-impl<'r, 'w, W> ser::SerializeTuple for Tuple<'r, 'w, W>
-where
- W: 'w + Write,
-{
- type Ok = ();
- type Error = DeError;
-
- fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error>
- where
- T: Serialize,
- {
- write!(self.parent.writer.inner(), "<{}>", self.name).map_err(Error::Io)?;
- value.serialize(&mut *self.parent)?;
- write!(self.parent.writer.inner(), "{}>", self.name).map_err(Error::Io)?;
- Ok(())
- }
-
- #[inline]
- fn end(self) -> Result {
- Ok(())
- }
-}
-
-impl<'r, 'w, W> ser::SerializeTupleStruct for Tuple<'r, 'w, W>
-where
- W: 'w + Write,
-{
- type Ok = ();
- type Error = DeError;
-
- #[inline]
- fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error>
- where
- T: Serialize,
- {
- ::serialize_element(self, value)
- }
-
- #[inline]
- fn end(self) -> Result {
- ::end(self)
- }
-}
-
-impl<'r, 'w, W> ser::SerializeTupleVariant for Tuple<'r, 'w, W>
-where
- W: 'w + Write,
-{
- type Ok = ();
- type Error = DeError;
-
- #[inline]
- fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error>
- where
- T: Serialize,
- {
- ::serialize_element(self, value)
- }
-
- #[inline]
- fn end(self) -> Result {
- ::end(self)
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
-#[test]
-fn test_serialize_map_entries() {
- use serde::ser::SerializeMap;
-
- let mut buffer = Vec::new();
-
- {
- let mut ser = Serializer::new(&mut buffer);
- let mut map = Map::new(&mut ser);
- map.serialize_entry("name", "Bob").unwrap();
- map.serialize_entry("age", "5").unwrap();
- }
-
- assert_eq!(
- String::from_utf8(buffer).unwrap(),
- "Bob5"
- );
-}
diff --git a/tests/serde-se.rs b/tests/serde-se.rs
index 33523fbe..ab830627 100644
--- a/tests/serde-se.rs
+++ b/tests/serde-se.rs
@@ -1,6 +1,5 @@
use quick_xml::se::Serializer;
use quick_xml::utils::Bytes;
-use quick_xml::writer::Writer;
use quick_xml::DeError;
use serde::{serde_if_integer128, Serialize};
@@ -52,8 +51,6 @@ struct Text {
#[derive(Serialize)]
enum ExternallyTagged {
Unit,
- #[serde(rename = "$primitive=PrimitiveUnit")]
- PrimitiveUnit,
Newtype(bool),
Tuple(f64, &'static str),
Struct {
@@ -167,11 +164,9 @@ mod without_root {
($name:ident: $data:expr => $expected:literal) => {
#[test]
fn $name() {
- let mut buffer = Vec::new();
- let mut ser = Serializer::new(&mut buffer);
+ let ser = Serializer::new(String::new());
- $data.serialize(&mut ser).unwrap();
- assert_eq!(String::from_utf8(buffer).unwrap(), $expected);
+ assert_eq!($data.serialize(ser).unwrap(), $expected);
}
};
}
@@ -182,10 +177,10 @@ mod without_root {
($name:ident: $data:expr => $kind:ident($reason:literal)) => {
#[test]
fn $name() {
- let mut buffer = Vec::new();
- let mut ser = Serializer::new(&mut buffer);
+ let mut buffer = String::new();
+ let ser = Serializer::new(&mut buffer);
- match $data.serialize(&mut ser) {
+ match $data.serialize(ser) {
Err(DeError::$kind(e)) => assert_eq!(e, $reason),
e => panic!(
"Expected `{}({})`, found `{:?}`",
@@ -194,7 +189,7 @@ mod without_root {
e
),
}
- assert_eq!(String::from_utf8(buffer).unwrap(), "");
+ assert_eq!(buffer, "");
}
};
}
@@ -233,7 +228,7 @@ mod without_root {
err!(str_non_escaped: "non-escaped string" => Unsupported("cannot serialize `&str` without defined root tag"));
err!(str_escaped: "<\"escaped & string'>" => Unsupported("cannot serialize `&str` without defined root tag"));
- err!(bytes: Bytes(b"<\"escaped & bytes'>") => Unsupported("`serialize_bytes` not supported yet"));
+ err!(bytes: Bytes(b"<\"escaped & bytes'>") => Unsupported("cannot serialize `&[u8]` without defined root tag"));
serialize_as!(option_none: Option::::None => "");
serialize_as!(option_some: Some(Unit) => "");
@@ -306,9 +301,6 @@ mod without_root {
serialize_as!(unit:
ExternallyTagged::Unit
=> "");
- serialize_as!(primitive_unit:
- ExternallyTagged::PrimitiveUnit
- => "");
serialize_as!(newtype:
ExternallyTagged::Newtype(true)
=> "true");
@@ -565,11 +557,9 @@ mod with_root {
($name:ident: $data:expr => $expected:literal) => {
#[test]
fn $name() {
- let mut buffer = Vec::new();
- let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));
+ let ser = Serializer::with_root(String::new(), Some("root")).unwrap();
- $data.serialize(&mut ser).unwrap();
- assert_eq!(String::from_utf8(buffer).unwrap(), $expected);
+ assert_eq!($data.serialize(ser).unwrap(), $expected);
}
};
}
@@ -580,10 +570,10 @@ mod with_root {
($name:ident: $data:expr => $kind:ident($reason:literal)) => {
#[test]
fn $name() {
- let mut buffer = Vec::new();
- let mut ser = Serializer::with_root(Writer::new(&mut buffer), Some("root"));
+ let mut buffer = String::new();
+ let ser = Serializer::with_root(&mut buffer, Some("root")).unwrap();
- match $data.serialize(&mut ser) {
+ match $data.serialize(ser) {
Err(DeError::$kind(e)) => assert_eq!(e, $reason),
e => panic!(
"Expected `{}({})`, found `{:?}`",
@@ -593,7 +583,7 @@ mod with_root {
),
}
// We can write something before fail
- // assert_eq!(String::from_utf8(buffer).unwrap(), "");
+ // assert_eq!(buffer, "");
}
};
}
@@ -721,9 +711,6 @@ mod with_root {
serialize_as!(unit:
ExternallyTagged::Unit
=> "");
- serialize_as!(primitive_unit:
- ExternallyTagged::PrimitiveUnit
- => "");
serialize_as!(newtype:
ExternallyTagged::Newtype(true)
=> "true");