aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Vander Stoep <jeffv@google.com>2023-01-03 20:44:45 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-01-03 20:44:45 +0000
commit254a8667172991a2f7860d7db3deb8c72fb44b15 (patch)
tree20813e9df9e74173b1fbfc707995b22ad437b4f8
parent4f0fb1052481fe5bf9b9f0627bb3e35dfdce261f (diff)
parent85c49e4c7a532a38f183a4bc86f759b186a0417f (diff)
downloadserde-xml-rs-254a8667172991a2f7860d7db3deb8c72fb44b15.tar.gz
Upgrade serde-xml-rs to 0.6.0 am: 85c49e4c7a
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/serde-xml-rs/+/2362481 Change-Id: Ice7236efbb9fe27f8f338ce5cef113cdc3e15b40 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--.cargo_vcs_info.json7
-rw-r--r--Android.bp7
-rw-r--r--Cargo.toml13
-rw-r--r--Cargo.toml.orig7
-rw-r--r--METADATA14
-rw-r--r--README.md3
-rw-r--r--cargo2android.json4
-rw-r--r--src/de/mod.rs22
-rw-r--r--src/error.rs6
-rw-r--r--src/lib.rs14
-rw-r--r--src/ser/map.rs124
-rw-r--r--src/ser/mod.rs412
-rw-r--r--src/ser/plain.rs196
-rw-r--r--src/ser/seq.rs37
-rw-r--r--src/ser/tuple.rs91
-rw-r--r--src/ser/var.rs103
-rw-r--r--tests/common/mod.rs5
-rw-r--r--tests/datatypes.rs149
-rw-r--r--tests/failures.rs10
-rw-r--r--tests/migrated.rs141
-rw-r--r--tests/round_trip.rs21
-rw-r--r--tests/test.rs9
22 files changed, 891 insertions, 504 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 61ebbbd..1c94bec 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,6 @@
{
"git": {
- "sha1": "2a13dbd3f6ae77e67d7d329e7fce0b66f2d16d05"
- }
-}
+ "sha1": "920e54d059efe1dce4cef7f9728ef70e9d47b7b9"
+ },
+ "path_in_vcs": ""
+} \ No newline at end of file
diff --git a/Android.bp b/Android.bp
index 7d1bd7b..f8add92 100644
--- a/Android.bp
+++ b/Android.bp
@@ -20,11 +20,10 @@ license {
rust_library {
name: "libserde_xml_rs",
- // has rustc warnings
host_supported: true,
crate_name: "serde_xml_rs",
cargo_env_compat: true,
- cargo_pkg_version: "0.5.1",
+ cargo_pkg_version: "0.6.0",
srcs: ["src/lib.rs"],
edition: "2018",
rustlibs: [
@@ -41,11 +40,10 @@ rust_library {
rust_test {
name: "serde-xml-rs_test_src_lib",
- // has rustc warnings
host_supported: true,
crate_name: "serde_xml_rs",
cargo_env_compat: true,
- cargo_pkg_version: "0.5.1",
+ cargo_pkg_version: "0.6.0",
srcs: ["src/lib.rs"],
test_suites: ["general-tests"],
auto_gen_config: true,
@@ -59,5 +57,4 @@ rust_test {
"libthiserror",
"libxml_rust",
],
- proc_macros: ["libserde_derive"],
}
diff --git a/Cargo.toml b/Cargo.toml
index 08bafe4..a642a06 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,11 +12,13 @@
[package]
edition = "2018"
name = "serde-xml-rs"
-version = "0.5.1"
+version = "0.6.0"
authors = ["Ingvar Stepanyan <me@rreverser.com>"]
description = "xml-rs based deserializer for Serde (compatible with 0.9+)"
+readme = "README.md"
license = "MIT"
repository = "https://github.com/RReverser/serde-xml-rs"
+
[dependencies.log]
version = "0.4"
@@ -28,11 +30,16 @@ version = "1.0"
[dependencies.xml-rs]
version = "0.8"
+
[dev-dependencies.docmatic]
version = "0.1"
-[dev-dependencies.serde_derive]
+[dev-dependencies.rstest]
+version = "0.12"
+
+[dev-dependencies.serde]
version = "1.0"
+features = ["derive"]
[dev-dependencies.simple_logger]
-version = "1.0"
+version = "2.1"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 09ea859..1a4a29d 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -4,7 +4,7 @@ description = "xml-rs based deserializer for Serde (compatible with 0.9+)"
license = "MIT"
name = "serde-xml-rs"
repository = "https://github.com/RReverser/serde-xml-rs"
-version = "0.5.1"
+version = "0.6.0"
edition = "2018"
[dependencies]
@@ -14,6 +14,7 @@ xml-rs = "0.8"
thiserror = "1.0"
[dev-dependencies]
-serde_derive = "1.0"
-simple_logger = "1.0"
+serde = { version = "1.0", features = ["derive"] }
+simple_logger = "2.1"
docmatic = "0.1"
+rstest = "0.12"
diff --git a/METADATA b/METADATA
index 2a22775..b1016df 100644
--- a/METADATA
+++ b/METADATA
@@ -1,3 +1,7 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update rust/crates/serde-xml-rs
+# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+
name: "serde-xml-rs"
description: "xml-rs based deserializer for Serde (compatible with 0.9+)"
third_party {
@@ -7,13 +11,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/serde-xml-rs/serde-xml-rs-0.5.1.crate"
+ value: "https://static.crates.io/crates/serde-xml-rs/serde-xml-rs-0.6.0.crate"
}
- version: "0.5.1"
+ version: "0.6.0"
license_type: NOTICE
last_upgrade_date {
- year: 2021
- month: 9
- day: 28
+ year: 2022
+ month: 12
+ day: 19
}
}
diff --git a/README.md b/README.md
index ba23d1e..80ac31e 100644
--- a/README.md
+++ b/README.md
@@ -7,8 +7,7 @@
## Example usage
```rust
-use serde;
-use serde_derive::{Deserialize, Serialize};
+use serde::{Deserialize, Serialize};
use serde_xml_rs::{from_str, to_string};
#[derive(Debug, Serialize, Deserialize, PartialEq)]
diff --git a/cargo2android.json b/cargo2android.json
index d735201..3223434 100644
--- a/cargo2android.json
+++ b/cargo2android.json
@@ -5,15 +5,17 @@
],
"dependency-blocklist": [
"docmatic",
+ "rstest",
"simple_logger"
],
"device": true,
"run": true,
"test-blocklist": [
+ "tests/datatypes.rs",
"tests/failures.rs",
"tests/migrated.rs",
"tests/round_trip.rs",
"tests/test.rs"
],
"tests": true
-} \ No newline at end of file
+}
diff --git a/src/de/mod.rs b/src/de/mod.rs
index 21240c5..486b38c 100644
--- a/src/de/mod.rs
+++ b/src/de/mod.rs
@@ -1,6 +1,6 @@
use std::{io::Read, marker::PhantomData};
-use log::debug;
+use log::trace;
use serde::de::{self, Unexpected};
use serde::forward_to_deserialize_any;
use xml::name::OwnedName;
@@ -21,10 +21,7 @@ mod var;
/// A convenience method for deserialize some object from a string.
///
/// ```rust
-/// # #[macro_use]
-/// # extern crate serde_derive;
-/// # extern crate serde;
-/// # extern crate serde_xml_rs;
+/// # use serde::{Deserialize, Serialize};
/// # use serde_xml_rs::from_str;
/// #[derive(Debug, Deserialize, PartialEq)]
/// struct Item {
@@ -44,10 +41,7 @@ pub fn from_str<'de, T: de::Deserialize<'de>>(s: &str) -> Result<T> {
/// A convenience method for deserialize some object from a reader.
///
/// ```rust
-/// # #[macro_use]
-/// # extern crate serde_derive;
-/// # extern crate serde;
-/// # extern crate serde_xml_rs;
+/// # use serde::Deserialize;
/// # use serde_xml_rs::from_reader;
/// #[derive(Debug, Deserialize, PartialEq)]
/// struct Item {
@@ -108,12 +102,8 @@ impl<'de, R: Read> RootDeserializer<R> {
/// default. Enabling this option may incur additional memory usage.
///
/// ```rust
- /// # #[macro_use]
- /// # extern crate serde_derive;
- /// # extern crate serde;
- /// # extern crate serde_xml_rs;
- /// # use serde_xml_rs::from_reader;
/// # use serde::Deserialize;
+ /// # use serde_xml_rs::from_reader;
/// #[derive(Debug, Deserialize, PartialEq)]
/// struct Foo {
/// bar: Vec<usize>,
@@ -164,7 +154,7 @@ impl<'de, R: Read, B: BufferedXmlReader<R>> Deserializer<R, B> {
fn peek(&mut self) -> Result<&XmlEvent> {
let peeked = self.buffered_reader.peek()?;
- debug!("Peeked {:?}", peeked);
+ trace!("Peeked {:?}", peeked);
Ok(peeked)
}
@@ -181,7 +171,7 @@ impl<'de, R: Read, B: BufferedXmlReader<R>> Deserializer<R, B> {
}
_ => {}
}
- debug!("Fetched {:?}", next);
+ trace!("Fetched {:?}", next);
Ok(next)
}
diff --git a/src/error.rs b/src/error.rs
index 5061b52..50a15c0 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -47,6 +47,12 @@ pub enum Error {
#[from]
source: ::xml::reader::Error,
},
+
+ #[error("Writer: {source}")]
+ Writer {
+ #[from]
+ source: ::xml::writer::Error,
+ },
}
pub type Result<T> = std::result::Result<T, Error>;
diff --git a/src/lib.rs b/src/lib.rs
index e1ef1df..41d9c82 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -49,8 +49,7 @@
//! ## Basic example
//!
//! ```rust
-//! use serde;
-//! use serde_derive::{Deserialize, Serialize};
+//! use serde::{Deserialize, Serialize};
//! use serde_xml_rs::{from_str, to_string};
//!
//! #[derive(Debug, Serialize, Deserialize, PartialEq)]
@@ -60,7 +59,7 @@
//! }
//!
//! fn main() {
-//! let src = r#"<Item><name>Banana</name><source>Store</source></Item>"#;
+//! let src = r#"<?xml version="1.0" encoding="UTF-8"?><Item><name>Banana</name><source>Store</source></Item>"#;
//! let should_be = Item {
//! name: "Banana".to_string(),
//! source: "Store".to_string(),
@@ -77,8 +76,7 @@
//! ## Tag contents
//!
//! ```rust
-//! # use serde;
-//! # use serde_derive::{Deserialize, Serialize};
+//! # use serde::{Deserialize, Serialize};
//! # use serde_xml_rs::{from_str, to_string};
//!
//! #[derive(Debug, Serialize, Deserialize, PartialEq)]
@@ -102,8 +100,7 @@
//! ## Repeated tags
//!
//! ```rust
-//! # use serde;
-//! # use serde_derive::{Deserialize, Serialize};
+//! # use serde::{Deserialize, Serialize};
//! # use serde_xml_rs::{from_str, to_string};
//!
//! #[derive(Debug, Serialize, Deserialize, PartialEq)]
@@ -160,8 +157,7 @@
//! ## Custom EventReader
//!
//! ```rust
-//! use serde::Deserialize;
-//! use serde_derive::{Deserialize, Serialize};
+//! use serde::{Deserialize, Serialize};
//! use serde_xml_rs::{from_str, to_string, de::Deserializer};
//! use xml::reader::{EventReader, ParserConfig};
//!
diff --git a/src/ser/map.rs b/src/ser/map.rs
new file mode 100644
index 0000000..b0793e6
--- /dev/null
+++ b/src/ser/map.rs
@@ -0,0 +1,124 @@
+use super::{plain::to_plain_string, Serializer};
+use crate::error::{Error, Result};
+use log::debug;
+use serde::ser::Serialize;
+use std::io::Write;
+
+pub struct MapSerializer<'ser, W: 'ser + Write> {
+ ser: &'ser mut Serializer<W>,
+ must_close_tag: bool,
+}
+
+impl<'ser, W: 'ser + Write> MapSerializer<'ser, W> {
+ pub fn new(ser: &'ser mut Serializer<W>, must_close_tag: bool) -> Self {
+ MapSerializer {
+ ser,
+ must_close_tag,
+ }
+ }
+}
+
+impl<'ser, W: Write> serde::ser::SerializeMap for MapSerializer<'ser, W> {
+ type Ok = ();
+ type Error = Error;
+
+ fn serialize_key<T>(&mut self, key: &T) -> Result<()>
+ where
+ T: ?Sized + Serialize,
+ {
+ self.ser.open_tag(&to_plain_string(key)?)?;
+ Ok(())
+ }
+
+ fn serialize_value<T>(&mut self, value: &T) -> Result<()>
+ where
+ T: ?Sized + Serialize,
+ {
+ value.serialize(&mut *self.ser)?;
+ Ok(())
+ }
+
+ fn end(self) -> Result<()> {
+ if self.must_close_tag {
+ self.ser.end_tag()?;
+ }
+ Ok(())
+ }
+}
+
+pub struct StructSerializer<'ser, W: 'ser + Write> {
+ ser: &'ser mut Serializer<W>,
+ must_close_tag: bool,
+}
+
+impl<'ser, W: 'ser + Write> StructSerializer<'ser, W> {
+ pub fn new(ser: &'ser mut Serializer<W>, must_close_tag: bool) -> Self {
+ StructSerializer {
+ ser,
+ must_close_tag,
+ }
+ }
+
+ fn serialize_struct_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
+ where
+ T: ?Sized + Serialize,
+ {
+ if key.starts_with("@") {
+ debug!("attribute {}", key);
+ self.ser.add_attr(&key[1..], to_plain_string(value)?)
+ } else if key == "$value" {
+ self.ser.build_start_tag()?;
+ debug!("body");
+ value.serialize(&mut *self.ser)?;
+ Ok(())
+ } else {
+ self.ser.build_start_tag()?;
+ self.ser.open_tag(key)?;
+ debug!("field {}", key);
+ value.serialize(&mut *self.ser)?;
+ debug!("end field");
+ Ok(())
+ }
+ }
+
+ fn after_fields(self) -> Result<()> {
+ self.ser.build_start_tag()?;
+ self.ser.end_tag()?;
+ if self.must_close_tag {
+ self.ser.end_tag()?;
+ }
+ Ok(())
+ }
+}
+
+impl<'ser, W: 'ser + Write> serde::ser::SerializeStruct for StructSerializer<'ser, W> {
+ type Ok = ();
+ type Error = Error;
+
+ fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
+ where
+ T: ?Sized + Serialize,
+ {
+ self.serialize_struct_field(key, value)
+ }
+
+ fn end(self) -> Result<()> {
+ self.after_fields()
+ }
+}
+
+impl<'ser, W: 'ser + Write> serde::ser::SerializeStructVariant for StructSerializer<'ser, W> {
+ type Ok = ();
+ type Error = Error;
+
+ fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
+ where
+ T: ?Sized + Serialize,
+ {
+ self.serialize_struct_field(key, value)
+ }
+
+ fn end(self) -> Result<()> {
+ self.after_fields()
+ }
+}
diff --git a/src/ser/mod.rs b/src/ser/mod.rs
index a29ca6f..8130a8d 100644
--- a/src/ser/mod.rs
+++ b/src/ser/mod.rs
@@ -1,22 +1,25 @@
-use std::fmt::Display;
-use std::io::Write;
-
-use serde::ser::{self, Impossible, Serialize};
-
-use self::var::{Map, Struct};
+mod map;
+mod plain;
+mod seq;
+mod tuple;
+
+use self::{
+ map::{MapSerializer, StructSerializer},
+ seq::SeqSeralizer,
+ tuple::TupleSerializer,
+};
use crate::error::{Error, Result};
-
-mod var;
+use log::debug;
+use serde::ser::Serialize;
+use std::{collections::HashMap, io::Write};
+use xml::writer::{EmitterConfig, EventWriter, XmlEvent};
/// A convenience method for serializing some object to a buffer.
///
/// # Examples
///
/// ```rust
-/// # #[macro_use]
-/// # extern crate serde_derive;
-/// # extern crate serde;
-/// # extern crate serde_xml_rs;
+/// # use serde::Serialize;
/// # use serde_xml_rs::to_writer;
/// #[derive(Serialize)]
/// struct Person {
@@ -44,10 +47,7 @@ pub fn to_writer<W: Write, S: Serialize>(writer: W, value: &S) -> Result<()> {
/// # Examples
///
/// ```rust
-/// # #[macro_use]
-/// # extern crate serde_derive;
-/// # extern crate serde;
-/// # extern crate serde_xml_rs;
+/// # use serde::Serialize;
/// # use serde_xml_rs::to_string;
/// #[derive(Serialize)]
/// struct Person {
@@ -77,266 +77,329 @@ pub struct Serializer<W>
where
W: Write,
{
- writer: W,
+ writer: EventWriter<W>,
+ root: bool,
+ current_tag: String,
+ current_tag_attrs: Option<HashMap<&'static str, String>>,
}
impl<W> Serializer<W>
where
W: Write,
{
+ fn new_from_writer(writer: EventWriter<W>) -> Self {
+ Self {
+ writer,
+ root: true,
+ current_tag: "".into(),
+ current_tag_attrs: None,
+ }
+ }
+
pub fn new(writer: W) -> Self {
- Self { writer: writer }
+ Self::new_from_writer(EmitterConfig::new().create_writer(writer))
}
- fn write_primitive<P: Display>(&mut self, primitive: P) -> Result<()> {
- write!(self.writer, "{}", primitive)?;
+ fn next(&mut self, event: XmlEvent) -> Result<()> {
+ self.writer.write(event)?;
Ok(())
}
- fn write_wrapped<S: Serialize>(&mut self, tag: &str, value: S) -> Result<()> {
- write!(self.writer, "<{}>", tag)?;
- value.serialize(&mut *self)?;
- write!(self.writer, "</{}>", tag)?;
+ fn characters(&mut self, s: &str) -> Result<()> {
+ self.next(XmlEvent::characters(s))
+ }
+
+ fn start_document(&mut self) -> Result<()> {
+ self.next(XmlEvent::StartDocument {
+ encoding: Default::default(),
+ standalone: Default::default(),
+ version: xml::common::XmlVersion::Version10,
+ })
+ }
+
+ fn open_root_tag(&mut self, name: &'static str) -> Result<()> {
+ if self.root {
+ self.root = false;
+ self.start_document()?;
+ self.open_tag(name)?;
+ }
+ Ok(())
+ }
+
+ fn open_tag(&mut self, tag_name: &str) -> Result<()> {
+ self.current_tag = tag_name.into();
+ self.current_tag_attrs = Some(HashMap::new());
+ Ok(())
+ }
+
+ fn reopen_tag(&mut self) -> Result<()> {
+ self.current_tag_attrs = Some(HashMap::new());
Ok(())
}
+
+ fn abandon_tag(&mut self) -> Result<()> {
+ self.current_tag = "".into();
+ self.current_tag_attrs = None;
+ Ok(())
+ }
+
+ fn add_attr(&mut self, name: &'static str, value: String) -> Result<()> {
+ self.current_tag_attrs
+ .as_mut()
+ .ok_or(Error::Custom {
+ field: format!("Cannot add attribute {}", name),
+ })
+ .map(|attrs| {
+ attrs.insert(name, value);
+ })
+ }
+
+ fn build_start_tag(&mut self) -> Result<bool> {
+ if let Some(attrs) = self.current_tag_attrs.take() {
+ self.start_tag(&self.current_tag(), attrs)?;
+ Ok(true)
+ } else {
+ Ok(false)
+ }
+ }
+
+ fn start_tag(&mut self, tag_name: &str, attrs: HashMap<&str, String>) -> Result<()> {
+ let element = attrs
+ .iter()
+ .fold(XmlEvent::start_element(tag_name), |b, (&name, value)| {
+ b.attr(name, value)
+ });
+
+ self.next(element.into())
+ }
+
+ fn end_tag(&mut self) -> Result<()> {
+ self.next(XmlEvent::end_element().into())
+ }
+
+ fn current_tag(&self) -> String {
+ self.current_tag.clone()
+ }
}
-#[allow(unused_variables)]
-impl<'w, W> ser::Serializer for &'w mut Serializer<W>
-where
- W: Write,
-{
+impl<'ser, W: Write> serde::ser::Serializer for &'ser mut Serializer<W> {
type Ok = ();
type Error = Error;
- type SerializeSeq = Impossible<Self::Ok, Self::Error>;
- type SerializeTuple = Impossible<Self::Ok, Self::Error>;
- type SerializeTupleStruct = Impossible<Self::Ok, Self::Error>;
- type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
- type SerializeMap = Map<'w, W>;
- type SerializeStruct = Struct<'w, W>;
- type SerializeStructVariant = Impossible<Self::Ok, Self::Error>;
+ type SerializeSeq = SeqSeralizer<'ser, W>;
+ type SerializeTuple = TupleSerializer<'ser, W>;
+ type SerializeTupleStruct = TupleSerializer<'ser, W>;
+ type SerializeTupleVariant = TupleSerializer<'ser, W>;
+ type SerializeMap = MapSerializer<'ser, W>;
+ type SerializeStruct = StructSerializer<'ser, W>;
+ type SerializeStructVariant = StructSerializer<'ser, W>;
fn serialize_bool(self, v: bool) -> Result<Self::Ok> {
- if v {
- write!(self.writer, "true")?;
- } else {
- write!(self.writer, "false")?;
- }
-
- Ok(())
+ self.serialize_str(&v.to_string())
}
fn serialize_i8(self, v: i8) -> Result<Self::Ok> {
- self.write_primitive(v)
+ self.serialize_i64(i64::from(v))
}
fn serialize_i16(self, v: i16) -> Result<Self::Ok> {
- self.write_primitive(v)
+ self.serialize_i64(i64::from(v))
}
fn serialize_i32(self, v: i32) -> Result<Self::Ok> {
- self.write_primitive(v)
+ self.serialize_i64(i64::from(v))
}
fn serialize_i64(self, v: i64) -> Result<Self::Ok> {
- self.write_primitive(v)
+ self.serialize_str(&v.to_string())
}
fn serialize_u8(self, v: u8) -> Result<Self::Ok> {
- self.write_primitive(v)
+ self.serialize_u64(u64::from(v))
}
fn serialize_u16(self, v: u16) -> Result<Self::Ok> {
- self.write_primitive(v)
+ self.serialize_u64(u64::from(v))
}
fn serialize_u32(self, v: u32) -> Result<Self::Ok> {
- self.write_primitive(v)
+ self.serialize_u64(u64::from(v))
}
fn serialize_u64(self, v: u64) -> Result<Self::Ok> {
- self.write_primitive(v)
+ let must_close_tag = self.build_start_tag()?;
+ self.characters(&v.to_string())?;
+ if must_close_tag {
+ self.end_tag()?;
+ }
+ Ok(())
}
fn serialize_f32(self, v: f32) -> Result<Self::Ok> {
- self.write_primitive(v)
+ self.serialize_f64(f64::from(v))
}
fn serialize_f64(self, v: f64) -> Result<Self::Ok> {
- self.write_primitive(v)
+ self.serialize_str(&v.to_string())
}
fn serialize_char(self, v: char) -> Result<Self::Ok> {
- self.write_primitive(v)
+ self.serialize_str(&v.to_string())
}
- fn serialize_str(self, value: &str) -> Result<Self::Ok> {
- self.write_primitive(value)
+ fn serialize_str(self, v: &str) -> Result<Self::Ok> {
+ let must_close_tag = self.build_start_tag()?;
+ self.characters(v)?;
+ if must_close_tag {
+ self.end_tag()?;
+ }
+ Ok(())
}
- fn serialize_bytes(self, value: &[u8]) -> Result<Self::Ok> {
- // TODO: I imagine you'd want to use base64 here.
- // Not sure how to roundtrip effectively though...
- Err(Error::UnsupportedOperation {
- operation: "serialize_bytes".to_string(),
- })
+ fn serialize_bytes(self, _v: &[u8]) -> Result<Self::Ok> {
+ unimplemented!()
}
fn serialize_none(self) -> Result<Self::Ok> {
+ debug!("None");
+ let must_close_tag = self.build_start_tag()?;
+ if must_close_tag {
+ self.end_tag()?;
+ }
Ok(())
}
- fn serialize_some<T: ?Sized + Serialize>(self, value: &T) -> Result<Self::Ok> {
+ fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Self::Ok>
+ where
+ T: Serialize,
+ {
+ debug!("Some");
value.serialize(self)
}
fn serialize_unit(self) -> Result<Self::Ok> {
- self.serialize_none()
+ debug!("Unit");
+ let must_close_tag = self.build_start_tag()?;
+ if must_close_tag {
+ self.end_tag()?;
+ }
+ Ok(())
}
fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok> {
- self.write_wrapped(name, ())
+ debug!("Unit struct {}", name);
+ self.serialize_unit()
}
fn serialize_unit_variant(
self,
name: &'static str,
- variant_index: u32,
+ _variant_index: u32,
variant: &'static str,
) -> Result<Self::Ok> {
- Err(Error::UnsupportedOperation {
- operation: "serialize_unit_variant".to_string(),
- })
+ debug!("Unit variant {}::{}", name, variant);
+ self.start_tag(variant, HashMap::new())?;
+ self.serialize_unit()?;
+ self.end_tag()?;
+ Ok(())
}
- fn serialize_newtype_struct<T: ?Sized + Serialize>(
- self,
- name: &'static str,
- value: &T,
- ) -> Result<Self::Ok> {
- Err(Error::UnsupportedOperation {
- operation: "serialize_newtype_struct".to_string(),
- })
+ fn serialize_newtype_struct<T: ?Sized>(self, name: &'static str, value: &T) -> Result<Self::Ok>
+ where
+ T: Serialize,
+ {
+ debug!("Newtype struct {}", name);
+ value.serialize(self)
}
- fn serialize_newtype_variant<T: ?Sized + Serialize>(
+ fn serialize_newtype_variant<T: ?Sized>(
self,
name: &'static str,
- variant_index: u32,
+ _variant_index: u32,
variant: &'static str,
value: &T,
- ) -> Result<Self::Ok> {
- self.write_wrapped(variant, value)
+ ) -> Result<Self::Ok>
+ where
+ T: Serialize,
+ {
+ let must_close_tag = self.build_start_tag()?;
+
+ debug!("Newtype variant {}::{}", name, variant);
+ self.open_tag(variant)?;
+ value.serialize(&mut *self)?;
+
+ if must_close_tag {
+ self.end_tag()?;
+ }
+ Ok(())
}
- fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq> {
- // TODO: Figure out how to constrain the things written to only be composites
- Err(Error::UnsupportedOperation {
- operation: "serialize_seq".to_string(),
- })
+ fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
+ debug!("Sequence");
+ Ok(SeqSeralizer::new(self))
}
- fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
- Err(Error::UnsupportedOperation {
- operation: "serialize_tuple".to_string(),
- })
+ fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple> {
+ debug!("Tuple");
+ let must_close_tag = self.build_start_tag()?;
+ Ok(TupleSerializer::new(self, must_close_tag))
}
fn serialize_tuple_struct(
self,
name: &'static str,
- len: usize,
+ _len: usize,
) -> Result<Self::SerializeTupleStruct> {
- Err(Error::UnsupportedOperation {
- operation: "serialize_tuple_struct".to_string(),
- })
+ debug!("Tuple struct {}", name);
+ let must_close_tag = self.build_start_tag()?;
+ Ok(TupleSerializer::new(self, must_close_tag))
}
fn serialize_tuple_variant(
self,
name: &'static str,
- variant_index: u32,
+ _variant_index: u32,
variant: &'static str,
- len: usize,
+ _len: usize,
) -> Result<Self::SerializeTupleVariant> {
- Err(Error::UnsupportedOperation {
- operation: "serialize_tuple_variant".to_string(),
- })
+ debug!("Tuple variant {}::{}", name, variant);
+ let must_close_tag = self.build_start_tag()?;
+ self.start_tag(variant, HashMap::new())?;
+ Ok(TupleSerializer::new(self, must_close_tag))
}
- fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap> {
- Ok(Map::new(self))
+ fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
+ let must_close_tag = self.build_start_tag()?;
+ Ok(MapSerializer::new(self, must_close_tag))
}
- fn serialize_struct(self, name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
- write!(self.writer, "<{}>", name)?;
- Ok(Struct::new(self, name))
+ fn serialize_struct(self, name: &'static str, _len: usize) -> Result<Self::SerializeStruct> {
+ self.open_root_tag(name)?;
+
+ debug!("Struct {}", name);
+ Ok(StructSerializer::new(self, false))
}
fn serialize_struct_variant(
self,
name: &'static str,
- variant_index: u32,
+ _variant_index: u32,
variant: &'static str,
- len: usize,
+ _len: usize,
) -> Result<Self::SerializeStructVariant> {
- Err(Error::UnsupportedOperation {
- operation: "Result".to_string(),
- })
+ self.open_root_tag(name)?;
+
+ debug!("Struct variant {}", variant);
+ let must_close_tag = self.build_start_tag()?;
+ self.open_tag(variant)?;
+ Ok(StructSerializer::new(self, must_close_tag))
}
}
#[cfg(test)]
mod tests {
use super::*;
- use serde::ser::{SerializeMap, SerializeStruct};
- use serde::Serializer as SerSerializer;
- use serde_derive::Serialize;
-
- #[test]
- fn test_serialize_bool() {
- let inputs = vec![(true, "true"), (false, "false")];
-
- for (src, should_be) in inputs {
- let mut buffer = Vec::new();
-
- {
- let mut ser = Serializer::new(&mut buffer);
- ser.serialize_bool(src).unwrap();
- }
-
- let got = String::from_utf8(buffer).unwrap();
- assert_eq!(got, should_be);
- }
- }
-
- #[test]
- fn test_start_serialize_struct() {
- let mut buffer = Vec::new();
-
- {
- let mut ser = Serializer::new(&mut buffer);
- let _ = ser.serialize_struct("foo", 0).unwrap();
- }
-
- let got = String::from_utf8(buffer).unwrap();
- assert_eq!(got, "<foo>");
- }
-
- #[test]
- fn test_serialize_struct_field() {
- let mut buffer = Vec::new();
-
- {
- let mut ser = Serializer::new(&mut buffer);
- let mut struct_ser = Struct::new(&mut ser, "baz");
- struct_ser.serialize_field("foo", "bar").unwrap();
- }
-
- let got = String::from_utf8(buffer).unwrap();
- assert_eq!(got, "<foo>bar</foo>");
- }
+ use serde::Serialize;
#[test]
fn test_serialize_struct() {
@@ -350,7 +413,7 @@ mod tests {
name: "Bob".to_string(),
age: 42,
};
- let should_be = "<Person><name>Bob</name><age>42</age></Person>";
+ let should_be = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Person><name>Bob</name><age>42</age></Person>";
let mut buffer = Vec::new();
{
@@ -363,22 +426,6 @@ mod tests {
}
#[test]
- fn test_serialize_map_entries() {
- let should_be = "<name>Bob</name><age>5</age>";
- 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();
- }
-
- let got = String::from_utf8(buffer).unwrap();
- assert_eq!(got, should_be);
- }
-
- #[test]
fn test_serialize_enum() {
#[derive(Serialize)]
#[allow(dead_code)]
@@ -389,7 +436,7 @@ mod tests {
}
let mut buffer = Vec::new();
- let should_be = "<Boolean>true</Boolean>";
+ let should_be = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Boolean>true</Boolean>";
{
let mut ser = Serializer::new(&mut buffer);
@@ -400,21 +447,4 @@ mod tests {
let got = String::from_utf8(buffer).unwrap();
assert_eq!(got, should_be);
}
-
- #[test]
- #[ignore]
- fn serialize_a_list() {
- let inputs = vec![1, 2, 3, 4];
-
- let mut buffer = Vec::new();
-
- {
- let mut ser = Serializer::new(&mut buffer);
- inputs.serialize(&mut ser).unwrap();
- }
-
- let got = String::from_utf8(buffer).unwrap();
- println!("{}", got);
- panic!();
- }
}
diff --git a/src/ser/plain.rs b/src/ser/plain.rs
new file mode 100644
index 0000000..49e2964
--- /dev/null
+++ b/src/ser/plain.rs
@@ -0,0 +1,196 @@
+use std::io::Write;
+
+use serde::ser::{Impossible, Serialize};
+
+use crate::error::{Error, Result};
+
+pub fn to_plain_string<T>(value: &T) -> Result<String>
+where
+ T: ?Sized + Serialize,
+{
+ let mut writer = Vec::with_capacity(128);
+ value.serialize(&mut PlainStringSerializer::new(&mut writer))?;
+
+ let string = String::from_utf8(writer)?;
+ Ok(string)
+}
+
+struct PlainStringSerializer<W: Write> {
+ writer: W,
+}
+
+impl<W: Write> PlainStringSerializer<W> {
+ fn new(writer: W) -> Self {
+ PlainStringSerializer { writer }
+ }
+
+ fn characters(&mut self, s: &str) -> Result<()> {
+ write!(self.writer, "{}", s)?;
+ Ok(())
+ }
+}
+
+impl<'ser, W: 'ser + Write> serde::ser::Serializer for &'ser mut PlainStringSerializer<W> {
+ type Ok = ();
+ type Error = Error;
+
+ type SerializeSeq = Impossible<Self::Ok, Self::Error>;
+ type SerializeTuple = Impossible<Self::Ok, Self::Error>;
+ type SerializeTupleStruct = Impossible<Self::Ok, Self::Error>;
+ type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
+ type SerializeMap = Impossible<Self::Ok, Self::Error>;
+ type SerializeStruct = Impossible<Self::Ok, Self::Error>;
+ type SerializeStructVariant = Impossible<Self::Ok, Self::Error>;
+
+ fn serialize_bool(self, v: bool) -> Result<Self::Ok> {
+ self.characters(&v.to_string())
+ }
+
+ fn serialize_i8(self, v: i8) -> Result<Self::Ok> {
+ self.serialize_i64(i64::from(v))
+ }
+
+ fn serialize_i16(self, v: i16) -> Result<Self::Ok> {
+ self.serialize_i64(i64::from(v))
+ }
+
+ fn serialize_i32(self, v: i32) -> Result<Self::Ok> {
+ self.serialize_i64(i64::from(v))
+ }
+
+ fn serialize_i64(self, v: i64) -> Result<Self::Ok> {
+ self.characters(&v.to_string())
+ }
+
+ fn serialize_u8(self, v: u8) -> Result<Self::Ok> {
+ self.serialize_u64(u64::from(v))
+ }
+
+ fn serialize_u16(self, v: u16) -> Result<Self::Ok> {
+ self.serialize_u64(u64::from(v))
+ }
+
+ fn serialize_u32(self, v: u32) -> Result<Self::Ok> {
+ self.serialize_u64(u64::from(v))
+ }
+
+ fn serialize_u64(self, v: u64) -> Result<Self::Ok> {
+ self.characters(&v.to_string())
+ }
+
+ fn serialize_f32(self, v: f32) -> Result<Self::Ok> {
+ self.serialize_f64(f64::from(v))
+ }
+
+ fn serialize_f64(self, v: f64) -> Result<Self::Ok> {
+ self.characters(&v.to_string())
+ }
+
+ fn serialize_char(self, v: char) -> Result<Self::Ok> {
+ self.characters(&v.to_string())
+ }
+
+ fn serialize_str(self, v: &str) -> Result<Self::Ok> {
+ self.characters(v)
+ }
+
+ fn serialize_bytes(self, _v: &[u8]) -> Result<Self::Ok> {
+ unimplemented!()
+ }
+
+ fn serialize_none(self) -> Result<Self::Ok> {
+ unimplemented!()
+ }
+
+ fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<Self::Ok>
+ where
+ T: Serialize,
+ {
+ unimplemented!()
+ }
+
+ fn serialize_unit(self) -> Result<Self::Ok> {
+ unimplemented!()
+ }
+
+ fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok> {
+ unimplemented!()
+ }
+
+ fn serialize_unit_variant(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ ) -> Result<Self::Ok> {
+ unimplemented!()
+ }
+
+ fn serialize_newtype_struct<T: ?Sized>(
+ self,
+ _name: &'static str,
+ _value: &T,
+ ) -> Result<Self::Ok>
+ where
+ T: Serialize,
+ {
+ unimplemented!()
+ }
+
+ fn serialize_newtype_variant<T: ?Sized>(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ _value: &T,
+ ) -> Result<Self::Ok>
+ where
+ T: Serialize,
+ {
+ unimplemented!()
+ }
+
+ fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
+ unimplemented!()
+ }
+
+ fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple> {
+ unimplemented!()
+ }
+
+ fn serialize_tuple_struct(
+ self,
+ _name: &'static str,
+ _len: usize,
+ ) -> Result<Self::SerializeTupleStruct> {
+ unimplemented!()
+ }
+
+ fn serialize_tuple_variant(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ _len: usize,
+ ) -> Result<Self::SerializeTupleVariant> {
+ unimplemented!()
+ }
+
+ fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
+ unimplemented!()
+ }
+
+ fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeStruct> {
+ unimplemented!()
+ }
+
+ fn serialize_struct_variant(
+ self,
+ _name: &'static str,
+ _variant_index: u32,
+ _variant: &'static str,
+ _len: usize,
+ ) -> Result<Self::SerializeStructVariant> {
+ unimplemented!()
+ }
+}
diff --git a/src/ser/seq.rs b/src/ser/seq.rs
new file mode 100644
index 0000000..1681534
--- /dev/null
+++ b/src/ser/seq.rs
@@ -0,0 +1,37 @@
+use super::Serializer;
+use crate::error::{Error, Result};
+use serde::ser::Serialize;
+use std::io::Write;
+
+pub struct SeqSeralizer<'ser, W: 'ser + Write> {
+ ser: &'ser mut Serializer<W>,
+}
+
+impl<'ser, W: 'ser + Write> SeqSeralizer<'ser, W> {
+ pub fn new(ser: &'ser mut Serializer<W>) -> Self {
+ SeqSeralizer { ser }
+ }
+}
+
+impl<'ser, W: 'ser + Write> serde::ser::SerializeSeq for SeqSeralizer<'ser, W> {
+ type Ok = ();
+ type Error = Error;
+
+ fn serialize_element<T>(&mut self, value: &T) -> Result<()>
+ where
+ T: ?Sized + Serialize,
+ {
+ let must_close_tag = self.ser.build_start_tag()?;
+ value.serialize(&mut *self.ser)?;
+ if must_close_tag {
+ self.ser.end_tag()?;
+ self.ser.reopen_tag()?;
+ }
+ Ok(())
+ }
+
+ fn end(self) -> Result<()> {
+ self.ser.abandon_tag()?;
+ Ok(())
+ }
+}
diff --git a/src/ser/tuple.rs b/src/ser/tuple.rs
new file mode 100644
index 0000000..3d893f8
--- /dev/null
+++ b/src/ser/tuple.rs
@@ -0,0 +1,91 @@
+use std::io::Write;
+
+use serde::ser::Serialize;
+
+use super::Serializer;
+use crate::error::{Error, Result};
+
+pub struct TupleSerializer<'ser, W: 'ser + Write> {
+ ser: &'ser mut Serializer<W>,
+ must_close_tag: bool,
+ first: bool,
+}
+
+impl<'ser, W: 'ser + Write> TupleSerializer<'ser, W> {
+ pub fn new(ser: &'ser mut Serializer<W>, must_close_tag: bool) -> Self {
+ Self {
+ ser,
+ must_close_tag,
+ first: true,
+ }
+ }
+
+ fn serialize_item<T>(&mut self, value: &T) -> Result<()>
+ where
+ T: ?Sized + Serialize,
+ {
+ if self.first {
+ self.first = false;
+ } else {
+ self.ser.characters(" ")?;
+ }
+ value.serialize(&mut *self.ser)?;
+ Ok(())
+ }
+
+ fn after_items(self) -> Result<()> {
+ if self.must_close_tag {
+ self.ser.end_tag()?;
+ }
+ Ok(())
+ }
+}
+
+impl<'ser, W: 'ser + Write> serde::ser::SerializeTupleVariant for TupleSerializer<'ser, W> {
+ type Ok = ();
+ type Error = Error;
+
+ fn serialize_field<T>(&mut self, value: &T) -> Result<()>
+ where
+ T: ?Sized + Serialize,
+ {
+ self.serialize_item(value)
+ }
+
+ fn end(self) -> Result<()> {
+ self.ser.end_tag()?;
+ self.after_items()
+ }
+}
+
+impl<'ser, W: 'ser + Write> serde::ser::SerializeTupleStruct for TupleSerializer<'ser, W> {
+ type Ok = ();
+ type Error = Error;
+
+ fn serialize_field<T>(&mut self, value: &T) -> Result<()>
+ where
+ T: ?Sized + Serialize,
+ {
+ self.serialize_item(value)
+ }
+
+ fn end(self) -> Result<()> {
+ self.after_items()
+ }
+}
+
+impl<'ser, W: 'ser + Write> serde::ser::SerializeTuple for TupleSerializer<'ser, W> {
+ type Ok = ();
+ type Error = Error;
+
+ fn serialize_element<T>(&mut self, value: &T) -> Result<()>
+ where
+ T: ?Sized + Serialize,
+ {
+ self.serialize_item(value)
+ }
+
+ fn end(self) -> Result<()> {
+ self.after_items()
+ }
+}
diff --git a/src/ser/var.rs b/src/ser/var.rs
deleted file mode 100644
index e4ee0f0..0000000
--- a/src/ser/var.rs
+++ /dev/null
@@ -1,103 +0,0 @@
-use std::io::Write;
-
-use serde::ser::{self, Serialize};
-
-use crate::error::{Error, Result};
-use crate::ser::Serializer;
-
-/// An implementation of `SerializeMap` for serializing to XML.
-pub struct Map<'w, W>
-where
- W: Write,
-{
- parent: &'w mut Serializer<W>,
-}
-
-impl<'w, W> Map<'w, W>
-where
- W: 'w + Write,
-{
- pub fn new(parent: &'w mut Serializer<W>) -> Map<'w, W> {
- Map { parent }
- }
-}
-
-impl<'w, W> ser::SerializeMap for Map<'w, W>
-where
- W: 'w + Write,
-{
- type Ok = ();
- type Error = Error;
-
- fn serialize_key<T: ?Sized + Serialize>(&mut self, _: &T) -> Result<()> {
- panic!("impossible to serialize the key on its own, please use serialize_entry()")
- }
-
- fn serialize_value<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<()> {
- value.serialize(&mut *self.parent)
- }
-
- fn end(self) -> Result<Self::Ok> {
- Ok(())
- }
-
- fn serialize_entry<K: ?Sized + Serialize, V: ?Sized + Serialize>(
- &mut self,
- key: &K,
- value: &V,
- ) -> Result<()> {
- // 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, "<")?;
- key.serialize(&mut *self.parent)?;
- write!(self.parent.writer, ">")?;
-
- value.serialize(&mut *self.parent)?;
-
- write!(self.parent.writer, "</")?;
- key.serialize(&mut *self.parent)?;
- write!(self.parent.writer, ">")?;
- Ok(())
- }
-}
-
-/// An implementation of `SerializeStruct` for serializing to XML.
-pub struct Struct<'w, W>
-where
- W: Write,
-{
- parent: &'w mut Serializer<W>,
- name: &'w str,
-}
-
-impl<'w, W> Struct<'w, W>
-where
- W: 'w + Write,
-{
- pub fn new(parent: &'w mut Serializer<W>, name: &'w str) -> Struct<'w, W> {
- Struct { parent, name }
- }
-}
-
-impl<'w, W> ser::SerializeStruct for Struct<'w, W>
-where
- W: 'w + Write,
-{
- type Ok = ();
- type Error = Error;
-
- fn serialize_field<T: ?Sized + Serialize>(
- &mut self,
- key: &'static str,
- value: &T,
- ) -> Result<()> {
- write!(self.parent.writer, "<{}>", key)?;
- value.serialize(&mut *self.parent)?;
- write!(self.parent.writer, "</{}>", key)?;
- Ok(())
- }
-
- fn end(self) -> Result<Self::Ok> {
- write!(self.parent.writer, "</{}>", self.name).map_err(|e| e.into())
- }
-}
diff --git a/tests/common/mod.rs b/tests/common/mod.rs
new file mode 100644
index 0000000..26a82e4
--- /dev/null
+++ b/tests/common/mod.rs
@@ -0,0 +1,5 @@
+use simple_logger::SimpleLogger;
+
+pub fn init_logger() {
+ let _ = SimpleLogger::new().with_utc_timestamps().init();
+}
diff --git a/tests/datatypes.rs b/tests/datatypes.rs
new file mode 100644
index 0000000..60410c4
--- /dev/null
+++ b/tests/datatypes.rs
@@ -0,0 +1,149 @@
+pub use rstest::{fixture, rstest};
+use simple_logger::SimpleLogger;
+use std::fmt::Debug;
+
+#[fixture]
+fn logger() {
+ let _ = SimpleLogger::new().init();
+}
+
+mod de {
+ use super::*;
+ use serde::Deserialize;
+ use serde_xml_rs::from_str;
+
+ #[rstest]
+ #[case::string("<bla>This is a String</bla>", "This is a String".to_string())]
+ #[case::string("<bla></bla>", "".to_string())]
+ #[case::string("<bla> </bla>", "".to_string())]
+ #[case::string("<bla>&lt;boom/&gt;</bla>", "<boom/>".to_string())]
+ #[case::string("<bla>&#9835;</bla>", "♫".to_string())]
+ #[case::string("<bla>&#x266B;</bla>", "♫".to_string())]
+ #[case::string("<bla>♫<![CDATA[<cookies/>]]>♫</bla>", "♫<cookies/>♫".to_string())]
+ #[case::i64("<bla>0</bla>", 0i64)]
+ #[case::i64("<bla>-2</bla>", -2i64)]
+ #[case::i64("<bla>-1234</bla>", -1234i64)]
+ #[case::i64("<bla> -1234 </bla>", -1234i64)]
+ #[case::u64("<bla>0</bla>", 0u64)]
+ #[case::u64("<bla>1234</bla>", 1234u64)]
+ #[case::u64("<bla> 1234 </bla>", 1234u64)]
+ #[case::bool("<bla>true</bla>", true)]
+ #[case::bool("<bla>false</bla>", false)]
+ #[case::unit("<bla/>", ())]
+ #[case::f64("<bla>3.0</bla>", 3.0f64)]
+ #[case::f64("<bla>3.1</bla>", 3.1f64)]
+ #[case::f64("<bla>-1.2</bla>", -1.2f64)]
+ #[case::f64("<bla>0.4</bla>", 0.4f64)]
+ #[case::f64("<bla>0.4e5</bla>", 0.4e5f64)]
+ #[case::f64("<bla>0.4e15</bla>", 0.4e15f64)]
+ #[case::f64_precision_troubles("<bla>0.4e-01</bla>", 0.4e-01f64)]
+ #[case::f64("<bla> 0.4e-01 </bla>", 0.4e-01f64)]
+ #[case::option("<bla/>", Some("".to_string()))]
+ #[case::option("<bla></bla>", Some("".to_string()))]
+ #[case::option("<bla> </bla>", Some("".to_string()))]
+ #[case::option("<bla>42</bla>", Some("42".to_string()))]
+ fn element_ok<T, 'de>(_logger: (), #[case] document: &str, #[case] expected: T)
+ where
+ T: Deserialize<'de> + Debug + PartialEq,
+ {
+ let actual: T = from_str(document).unwrap();
+ assert_eq!(actual, expected);
+ }
+
+ #[rstest]
+ #[case("<bla>verum</bla>", Some(true))]
+ fn element_ko<T, 'de>(_logger: (), #[case] document: &str, #[case] _type: Option<T>)
+ where
+ T: Deserialize<'de> + Debug + PartialEq,
+ {
+ let actual: Result<T, _> = from_str(document);
+ assert!(actual.is_err());
+ }
+
+ #[derive(PartialEq, Debug, Deserialize)]
+ struct DummyAttribute<T> {
+ foo: T,
+ }
+
+ #[rstest]
+ #[case(r#"<bla foo="true"/>"#, DummyAttribute { foo: true })]
+ #[case(r#"<bla foo="false"/>"#, DummyAttribute { foo: false })]
+ #[case(r#"<bla foo="1"/>"#, DummyAttribute { foo: true })]
+ #[case(r#"<bla foo="0"/>"#, DummyAttribute { foo: false })]
+ fn attribute_ok<T, 'de>(_logger: (), #[case] document: &str, #[case] expected: T)
+ where
+ T: Deserialize<'de> + Debug + PartialEq,
+ {
+ let actual: T = from_str(document).unwrap();
+ assert_eq!(actual, expected);
+ }
+}
+
+mod ser {
+ use super::*;
+ use serde::{self, Serialize};
+ use serde_xml_rs::to_string;
+
+ #[derive(Serialize, Debug)]
+ #[serde(rename = "bla")]
+ struct Dummy<T> {
+ #[serde(rename = "$value")]
+ value: T,
+ }
+
+ #[rstest]
+ #[case::string("<bla>This is a String</bla>", "This is a String".to_string())]
+ #[case::string("<bla></bla>", "".to_string())]
+ #[case::string("<bla>&lt;boom/></bla>", "<boom/>".to_string())]
+ #[case::string("<bla>♫</bla>", "♫".to_string())]
+ #[case::string("<bla>♫&lt;cookies/>♫</bla>", "♫<cookies/>♫".to_string())]
+ #[case::i64("<bla>0</bla>", 0i64)]
+ #[case::i64("<bla>-2</bla>", -2i64)]
+ #[case::i64("<bla>-1234</bla>", -1234i64)]
+ #[case::u64("<bla>0</bla>", 0u64)]
+ #[case::u64("<bla>1234</bla>", 1234u64)]
+ #[case::bool("<bla>true</bla>", true)]
+ #[case::bool("<bla>false</bla>", false)]
+ #[case::unit("<bla />", ())]
+ #[case::f64("<bla>3</bla>", 3.0f64)]
+ #[case::f64("<bla>3.1</bla>", 3.1f64)]
+ #[case::f64("<bla>-1.2</bla>", -1.2f64)]
+ #[case::f64("<bla>0.4</bla>", 0.4f64)]
+ #[case::f64("<bla>40000</bla>", 0.4e5f64)]
+ #[case::f64("<bla>400000000000000</bla>", 0.4e15f64)]
+ #[case::f64_precision_troubles("<bla>0.04</bla>", 0.4e-01f64)]
+ #[case::option("<bla></bla>", Some("".to_string()))]
+ #[case::option("<bla>42</bla>", Some("42".to_string()))]
+ fn element_ok<T>(_logger: (), #[case] expected: &str, #[case] value: T)
+ where
+ T: Serialize + Debug,
+ {
+ let actual = to_string(&Dummy { value }).unwrap();
+ assert_eq!(
+ actual,
+ format!(r#"<?xml version="1.0" encoding="UTF-8"?>{}"#, expected)
+ );
+ }
+
+ #[derive(Serialize, Debug)]
+ #[serde(rename = "bla")]
+ struct DummyAttribute<T> {
+ #[serde(rename = "@value")]
+ value: T,
+ }
+
+ #[rstest]
+ #[case::string(r#"<bla value="" />"#, "".to_string())]
+ #[case::bool(r#"<bla value="true" />"#, true)]
+ #[case::bool(r#"<bla value="false" />"#, false)]
+ fn attribute_ok<T>(_logger: (), #[case] expected: &str, #[case] value: T)
+ where
+ T: Serialize + Debug,
+ {
+ let actual = to_string(&DummyAttribute { value }).unwrap();
+ assert_eq!(
+ actual,
+ format!(r#"<?xml version="1.0" encoding="UTF-8"?>{}"#, expected)
+ );
+ }
+}
diff --git a/tests/failures.rs b/tests/failures.rs
index 7a55811..89ac200 100644
--- a/tests/failures.rs
+++ b/tests/failures.rs
@@ -1,11 +1,9 @@
+mod common;
+
+use common::init_logger;
use log::info;
-use serde_derive::Deserialize;
+use serde::Deserialize;
use serde_xml_rs::from_str;
-use simple_logger::SimpleLogger;
-
-fn init_logger() {
- let _ = SimpleLogger::new().init();
-}
#[derive(Debug, Deserialize, PartialEq)]
struct Item {
diff --git a/tests/migrated.rs b/tests/migrated.rs
index e01d750..c67712e 100644
--- a/tests/migrated.rs
+++ b/tests/migrated.rs
@@ -1,13 +1,9 @@
-use simple_logger::SimpleLogger;
-use std::fmt::Debug;
+mod common;
-use serde::{de, ser};
-use serde_derive::{Deserialize, Serialize};
+use common::init_logger;
+use serde::{de, ser, Deserialize, Serialize};
use serde_xml_rs::{from_str, Error};
-
-fn init_logger() {
- let _ = SimpleLogger::new().init();
-}
+use std::fmt::Debug;
#[derive(PartialEq, Debug, Serialize, Deserialize)]
enum Animal {
@@ -66,18 +62,6 @@ where
}
}
-fn test_parse_invalid<'de, 'a, T>(errors: &[&'a str])
-where
- T: PartialEq + Debug + ser::Serialize + de::Deserialize<'de>,
-{
- for &s in errors {
- assert!(match from_str::<T>(s) {
- Err(_) => true,
- _ => false,
- });
- }
-}
-
#[test]
fn test_namespaces() {
init_logger();
@@ -173,27 +157,6 @@ fn test_forwarded_namespace() {
}
#[test]
-fn test_parse_string() {
- init_logger();
-
- test_parse_ok(&[
- (
- "<bla>This is a String</bla>",
- "This is a String".to_string(),
- ),
- ("<bla></bla>", "".to_string()),
- ("<bla> </bla>", "".to_string()),
- ("<bla>&lt;boom/&gt;</bla>", "<boom/>".to_string()),
- ("<bla>&#9835;</bla>", "♫".to_string()),
- ("<bla>&#x266B;</bla>", "♫".to_string()),
- (
- "<bla>♫<![CDATA[<cookies/>]]>♫</bla>",
- "♫<cookies/>♫".to_string(),
- ),
- ]);
-}
-
-#[test]
#[ignore] // FIXME
fn test_parse_string_not_trim() {
init_logger();
@@ -269,87 +232,6 @@ fn test_parse_enum() {
}
#[test]
-fn test_parse_i64() {
- init_logger();
- test_parse_ok(&[
- ("<bla>0</bla>", 0),
- ("<bla>-2</bla>", -2),
- ("<bla>-1234</bla>", -1234),
- ("<bla> -1234 </bla>", -1234),
- ]);
-}
-
-#[test]
-fn test_parse_u64() {
- init_logger();
- test_parse_ok(&[
- ("<bla>0</bla>", 0),
- ("<bla>1234</bla>", 1234),
- ("<bla> 1234 </bla>", 1234),
- ]);
-}
-
-#[test]
-fn test_parse_bool_element() {
- init_logger();
- test_parse_ok(&[
- ("<bla>true</bla>", true),
- ("<bla>false</bla>", false),
- ("<bla> true </bla>", true),
- ("<bla> false </bla>", false),
- ("<bla>1</bla>", true),
- ("<bla>0</bla>", false),
- ]);
-
- test_parse_invalid::<bool>(&["<bla>verum</bla>"]);
-}
-
-#[test]
-fn test_parse_bool_attribute() {
- #[derive(PartialEq, Debug, Deserialize, Serialize)]
- struct Dummy {
- foo: bool,
- }
-
- init_logger();
- test_parse_ok(&[
- ("<bla foo=\"true\"/>", Dummy { foo: true }),
- ("<bla foo=\"false\"/>", Dummy { foo: false }),
- ("<bla foo=\"1\"/>", Dummy { foo: true }),
- ("<bla foo=\"0\"/>", Dummy { foo: false }),
- ]);
-
- test_parse_invalid::<Dummy>(&[
- "<bla foo=\"bar\"/>",
- "<bla foo=\" true \"/>",
- "<bla foo=\"10\"/>",
- "<bla foo=\"\"/>",
- "<bla/>",
- ]);
-}
-
-#[test]
-fn test_parse_unit() {
- init_logger();
- test_parse_ok(&[("<bla/>", ())]);
-}
-
-#[test]
-fn test_parse_f64() {
- init_logger();
- test_parse_ok(&[
- ("<bla>3.0</bla>", 3.0f64),
- ("<bla>3.1</bla>", 3.1),
- ("<bla>-1.2</bla>", -1.2),
- ("<bla>0.4</bla>", 0.4),
- ("<bla>0.4e5</bla>", 0.4e5),
- ("<bla>0.4e15</bla>", 0.4e15),
- ("<bla>0.4e-01</bla>", 0.4e-01), // precision troubles
- ("<bla> 0.4e-01 </bla>", 0.4e-01),
- ]);
-}
-
-#[test]
fn test_parse_struct() {
init_logger();
@@ -397,17 +279,6 @@ fn test_parse_struct() {
}
#[test]
-fn test_option() {
- init_logger();
- test_parse_ok(&[
- ("<a/>", Some("".to_string())),
- ("<a></a>", Some("".to_string())),
- ("<a> </a>", Some("".to_string())),
- ("<a>42</a>", Some("42".to_string())),
- ]);
-}
-
-#[test]
#[ignore] // FIXME
fn test_option_not_trim() {
init_logger();
@@ -976,12 +847,12 @@ fn futile2() {
#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
struct Object {
field: Option<Null>,
- };
+ }
#[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
struct Stuff {
stuff_field: Option<Object>,
- };
+ }
test_parse_ok(&[
(
diff --git a/tests/round_trip.rs b/tests/round_trip.rs
index 450a4b5..65c84ae 100644
--- a/tests/round_trip.rs
+++ b/tests/round_trip.rs
@@ -1,5 +1,4 @@
-use serde::Deserialize;
-use serde_derive::{Deserialize, Serialize};
+use serde::{Deserialize, Serialize};
use serde_xml_rs::{self, from_str, to_string, EventReader, ParserConfig};
#[derive(Debug, Serialize, Deserialize, PartialEq)]
@@ -23,7 +22,7 @@ struct Nodes {
#[test]
fn basic_struct() {
- let src = r#"<Item><name>Banana</name><source>Store</source></Item>"#;
+ let src = r#"<?xml version="1.0" encoding="UTF-8"?><Item><name>Banana</name><source>Store</source></Item>"#;
let should_be = Item {
name: "Banana".to_string(),
source: "Store".to_string(),
@@ -37,7 +36,6 @@ fn basic_struct() {
}
#[test]
-#[ignore]
fn round_trip_list_of_enums() {
// Construct some inputs
let nodes = Nodes {
@@ -51,17 +49,7 @@ fn round_trip_list_of_enums() {
],
};
- let should_be = r#"
- <Nodes>
- <Boolean>
- true
- </Boolean>
- <Identifier>
- <value>foo</value>
- <index>5</index>
- </Identifier>
- <EOF />
- </Nodes>"#;
+ let should_be = r#"<?xml version="1.0" encoding="UTF-8"?><Nodes><Boolean>true</Boolean><Identifier><value>foo</value><index>5</index></Identifier><EOF /></Nodes>"#;
let serialized_nodes = to_string(&nodes).unwrap();
assert_eq!(serialized_nodes, should_be);
@@ -77,6 +65,7 @@ fn whitespace_preserving_config() {
// Test a configuration which does not clip whitespace from tags
let src = r#"
+ <?xml version="1.0" encoding="UTF-8"?>
<Item>
<name> space banana </name>
<source> fantasy costco </source>
@@ -97,7 +86,7 @@ fn whitespace_preserving_config() {
// Space outside values is not preserved.
let serialized_should_be =
- "<Item><name> space banana </name><source> fantasy costco </source></Item>";
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Item><name> space banana </name><source> fantasy costco </source></Item>";
let reserialized_item = to_string(&item).unwrap();
assert_eq!(reserialized_item, serialized_should_be);
}
diff --git a/tests/test.rs b/tests/test.rs
index 52075b1..aa93df6 100644
--- a/tests/test.rs
+++ b/tests/test.rs
@@ -1,11 +1,8 @@
+mod common;
+
+use common::init_logger;
use serde::Deserialize;
-use serde_derive::Deserialize;
use serde_xml_rs::{from_str, Deserializer};
-use simple_logger::SimpleLogger;
-
-fn init_logger() {
- let _ = SimpleLogger::new().init();
-}
#[derive(Debug, Deserialize, PartialEq)]
struct Item {