Import serde-xml-rs 0.4.1

Bug: 191601801
Test: m libserde_xml_rs
Change-Id: Ie6b7a9e17bebcd738e798e4d1974be0ed23a3012
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..ee9f639
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,34 @@
+// This file is generated by cargo2android.py --config cargo2android.json.
+// Do not modify this file as changes will be overridden on upgrade.
+
+
+
+rust_library {
+    name: "libserde_xml_rs",
+    host_supported: true,
+    crate_name: "serde_xml_rs",
+    srcs: ["src/lib.rs"],
+    edition: "2015",
+    rustlibs: [
+        "liblog_rust",
+        "libserde",
+        "libthiserror",
+        "libxml",
+    ],
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.virt",
+    ],
+}
+
+// dependent_library ["feature_list"]
+//   cfg-if-1.0.0
+//   log-0.4.14 "std"
+//   proc-macro2-1.0.27 "default,proc-macro"
+//   quote-1.0.9 "default,proc-macro"
+//   serde-1.0.126 "default,std"
+//   syn-1.0.73 "clone-impls,default,derive,parsing,printing,proc-macro,quote"
+//   thiserror-1.0.26
+//   thiserror-impl-1.0.26
+//   unicode-xid-0.2.2 "default"
+//   xml-rs-0.8.3
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..fa4d9b9
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+authors = ["Ingvar Stepanyan <me@rreverser.com>"]
+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.4.1"
+
+[dependencies]
+log = "0.4"
+serde = "1.0"
+xml-rs = "0.8.0"
+thiserror = "1.0"
+
+[dev-dependencies]
+serde_derive = "1.0"
+simple_logger = "1.0.1"
+docmatic = "0.1.2"
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..774d94a
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017 Ingvar Stepanyan
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..a1b4d08
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,17 @@
+name: "serde-xml-rs"
+description:
+    "xml-rs based deserializer for Serde"
+
+third_party {
+  url {
+    type: HOMEPAGE
+    value: "https://crates.io/crates/serde_xml_rs"
+  }
+  url {
+    type: GIT
+    value: "https://github.com/RReverser/serde-xml-rs"
+  }
+  version: "0.4.1"
+  last_upgrade_date { year: 2021 month: 6 day: 21 }
+  license_type: NOTICE
+}
\ No newline at end of file
diff --git a/MODULE_LICENSE_MIT b/MODULE_LICENSE_MIT
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_MIT
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..98a1473
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,2 @@
+include platform/prebuilts/rust:/OWNERS
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..f2e530c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,62 @@
+# serde-xml-rs
+
+[![Build Status](https://travis-ci.org/RReverser/serde-xml-rs.svg?branch=master)](https://travis-ci.org/RReverser/serde-xml-rs)
+
+xml-rs based deserializer for Serde (compatible with 0.9+)
+
+## Usage
+
+Use `serde_xml_rs::from_reader(...)` on any type that implements [`std::io::Read`](https://doc.rust-lang.org/std/io/trait.Read.html) as following:
+
+```rust
+#[macro_use]
+extern crate serde_derive;
+extern crate serde;
+extern crate serde_xml_rs;
+
+use serde_xml_rs::from_reader;
+
+#[derive(Debug, Deserialize)]
+struct Item {
+    pub name: String,
+    pub source: String
+}
+
+#[derive(Debug, Deserialize)]
+struct Project {
+    pub name: String,
+
+    #[serde(rename = "Item", default)]
+    pub items: Vec<Item>
+}
+
+fn main() {
+    let s = r##"
+        <Project name="my_project">
+            <Item name="hello" source="world.rs" />
+        </Project>
+    "##;
+    let project: Project = from_reader(s.as_bytes()).unwrap();
+    println!("{:#?}", project);
+}
+```
+
+Alternatively, you can use `serde_xml_rs::Deserializer` to create a deserializer from a preconfigured [`xml_rs::EventReader`](https://netvl.github.io/xml-rs/xml/reader/struct.EventReader.html).
+
+## Parsing the "value" of a tag
+
+If you have an input of the form `<foo abc="xyz">bar</foo>`, and you want to get at the`bar`, you can use the special name `$value`:
+
+```rust,ignore
+struct Foo {
+    pub abc: String,
+    #[serde(rename = "$value")]
+    pub body: String,
+}
+```
+
+## Parsed representations
+
+Deserializer tries to be as intuitive as possible.
+
+However, there are some edge cases where you might get unexpected errors, so it's best to check out [`tests`](tests/test.rs) for expectations.
diff --git a/cargo2android.json b/cargo2android.json
new file mode 100644
index 0000000..42b7833
--- /dev/null
+++ b/cargo2android.json
@@ -0,0 +1,9 @@
+{
+  "apex-available": [
+    "//apex_available:platform",
+    "com.android.virt"
+  ],
+  "dependencies": true,
+  "device": true,
+  "run": true
+}
\ No newline at end of file
diff --git a/rustfmt.toml b/rustfmt.toml
new file mode 100644
index 0000000..8c795ae
--- /dev/null
+++ b/rustfmt.toml
@@ -0,0 +1 @@
+match_block_trailing_comma = true
diff --git a/src/de/map.rs b/src/de/map.rs
new file mode 100644
index 0000000..ed1d0bb
--- /dev/null
+++ b/src/de/map.rs
@@ -0,0 +1,126 @@
+use std::io::Read;
+
+use serde::de::{self, IntoDeserializer, Unexpected};
+use xml::attribute::OwnedAttribute;
+use xml::reader::XmlEvent;
+
+use Deserializer;
+use error::{Error, Result};
+
+pub struct MapAccess<'a, R: 'a + Read> {
+    attrs: ::std::vec::IntoIter<OwnedAttribute>,
+    next_value: Option<String>,
+    de: &'a mut Deserializer<R>,
+    inner_value: bool,
+}
+
+impl<'a, R: 'a + Read> MapAccess<'a, R> {
+    pub fn new(de: &'a mut Deserializer<R>, attrs: Vec<OwnedAttribute>, inner_value: bool) -> Self {
+        MapAccess {
+            attrs: attrs.into_iter(),
+            next_value: None,
+            de: de,
+            inner_value: inner_value,
+        }
+    }
+}
+
+impl<'de, 'a, R: 'a + Read> de::MapAccess<'de> for MapAccess<'a, R> {
+    type Error = Error;
+
+    fn next_key_seed<K: de::DeserializeSeed<'de>>(&mut self, seed: K) -> Result<Option<K::Value>> {
+        debug_assert_eq!(self.next_value, None);
+        match self.attrs.next() {
+            Some(OwnedAttribute { name, value }) => {
+                self.next_value = Some(value);
+                seed.deserialize(name.local_name.into_deserializer())
+                    .map(Some)
+            },
+            None => match *self.de.peek()? {
+                XmlEvent::StartElement { ref name, .. } => seed.deserialize(
+                    if !self.inner_value {
+                        name.local_name.as_str()
+                    } else {
+                        "$value"
+                    }.into_deserializer(),
+                ).map(Some),
+                XmlEvent::Characters(_) => seed.deserialize("$value".into_deserializer()).map(Some),
+                _ => Ok(None),
+            },
+        }
+    }
+
+    fn next_value_seed<V: de::DeserializeSeed<'de>>(&mut self, seed: V) -> Result<V::Value> {
+        match self.next_value.take() {
+            Some(value) => seed.deserialize(AttrValueDeserializer(value)),
+            None => {
+                if !self.inner_value {
+                    if let XmlEvent::StartElement { .. } = *self.de.peek()? {
+                        self.de.set_map_value();
+                    }
+                }
+                let result = seed.deserialize(&mut *self.de)?;
+                Ok(result)
+            },
+        }
+    }
+
+    fn size_hint(&self) -> Option<usize> {
+        self.attrs.size_hint().1
+    }
+}
+
+struct AttrValueDeserializer(String);
+
+macro_rules! deserialize_type_attr {
+    ($deserialize:ident => $visit:ident) => {
+        fn $deserialize<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
+            visitor.$visit(self.0.parse()?)
+        }
+    }
+}
+
+impl<'de> de::Deserializer<'de> for AttrValueDeserializer {
+    type Error = Error;
+
+    fn deserialize_any<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
+        visitor.visit_string(self.0)
+    }
+
+    deserialize_type_attr!(deserialize_i8 => visit_i8);
+    deserialize_type_attr!(deserialize_i16 => visit_i16);
+    deserialize_type_attr!(deserialize_i32 => visit_i32);
+    deserialize_type_attr!(deserialize_i64 => visit_i64);
+    deserialize_type_attr!(deserialize_u8 => visit_u8);
+    deserialize_type_attr!(deserialize_u16 => visit_u16);
+    deserialize_type_attr!(deserialize_u32 => visit_u32);
+    deserialize_type_attr!(deserialize_u64 => visit_u64);
+    deserialize_type_attr!(deserialize_f32 => visit_f32);
+    deserialize_type_attr!(deserialize_f64 => visit_f64);
+
+    fn deserialize_enum<V: de::Visitor<'de>>(
+        self,
+        _name: &str,
+        _variants: &'static [&'static str],
+        visitor: V,
+    ) -> Result<V::Value> {
+        visitor.visit_enum(self.0.into_deserializer())
+    }
+
+    fn deserialize_option<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
+        visitor.visit_some(self)
+    }
+
+    fn deserialize_bool<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
+        match self.0.as_str() {
+            "true" | "1" => visitor.visit_bool(true),
+            "false" | "0" => visitor.visit_bool(false),
+            _ => Err(de::Error::invalid_value(Unexpected::Str(&self.0), &"a boolean")),
+        }
+    }
+
+    forward_to_deserialize_any! {
+        char str string unit seq bytes map unit_struct newtype_struct tuple_struct
+        struct identifier tuple ignored_any byte_buf
+    }
+}
diff --git a/src/de/mod.rs b/src/de/mod.rs
new file mode 100644
index 0000000..94077c5
--- /dev/null
+++ b/src/de/mod.rs
@@ -0,0 +1,367 @@
+use std::io::Read;
+
+use serde::de::{self, Unexpected};
+use xml::name::OwnedName;
+use xml::reader::{EventReader, ParserConfig, XmlEvent};
+
+use self::map::MapAccess;
+use self::seq::SeqAccess;
+use self::var::EnumAccess;
+use error::{Error, Result};
+
+mod map;
+mod seq;
+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_xml_rs::from_str;
+/// #[derive(Debug, Deserialize, PartialEq)]
+/// struct Item {
+///     name: String,
+///     source: String,
+/// }
+/// # fn main() {
+/// let s = r##"<item name="hello" source="world.rs" />"##;
+/// let item: Item = from_str(s).unwrap();
+/// assert_eq!(item, Item { name: "hello".to_string(),source: "world.rs".to_string()});
+/// # }
+/// ```
+pub fn from_str<'de, T: de::Deserialize<'de>>(s: &str) -> Result<T> {
+    from_reader(s.as_bytes())
+}
+
+/// 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_xml_rs::from_reader;
+/// #[derive(Debug, Deserialize, PartialEq)]
+/// struct Item {
+///     name: String,
+///     source: String,
+/// }
+/// # fn main() {
+/// let s = r##"<item name="hello" source="world.rs" />"##;
+/// let item: Item = from_reader(s.as_bytes()).unwrap();
+/// assert_eq!(item, Item { name: "hello".to_string(),source: "world.rs".to_string()});
+/// # }
+/// ```
+pub fn from_reader<'de, R: Read, T: de::Deserialize<'de>>(reader: R) -> Result<T> {
+    T::deserialize(&mut Deserializer::new_from_reader(reader))
+}
+
+pub struct Deserializer<R: Read> {
+    depth: usize,
+    reader: EventReader<R>,
+    peeked: Option<XmlEvent>,
+    is_map_value: bool,
+}
+
+impl<'de, R: Read> Deserializer<R> {
+    pub fn new(reader: EventReader<R>) -> Self {
+        Deserializer {
+            depth: 0,
+            reader: reader,
+            peeked: None,
+            is_map_value: false,
+        }
+    }
+
+    pub fn new_from_reader(reader: R) -> Self {
+        let config = ParserConfig::new()
+            .trim_whitespace(true)
+            .whitespace_to_characters(true)
+            .cdata_to_characters(true)
+            .ignore_comments(true)
+            .coalesce_characters(true);
+
+        Self::new(EventReader::new_with_config(reader, config))
+    }
+
+    fn peek(&mut self) -> Result<&XmlEvent> {
+        if self.peeked.is_none() {
+            self.peeked = Some(self.inner_next()?);
+        }
+        debug_expect!(self.peeked.as_ref(), Some(peeked) => {
+            debug!("Peeked {:?}", peeked);
+            Ok(peeked)
+        })
+    }
+
+    fn inner_next(&mut self) -> Result<XmlEvent> {
+        loop {
+            match self.reader.next()? {
+                XmlEvent::StartDocument { .. }
+                | XmlEvent::ProcessingInstruction { .. }
+                | XmlEvent::Whitespace { .. }
+                | XmlEvent::Comment(_) => { /* skip */ }
+                other => return Ok(other),
+            }
+        }
+    }
+
+    fn next(&mut self) -> Result<XmlEvent> {
+        let next = if let Some(peeked) = self.peeked.take() {
+            peeked
+        } else {
+            self.inner_next()?
+        };
+        match next {
+            XmlEvent::StartElement { .. } => {
+                self.depth += 1;
+            }
+            XmlEvent::EndElement { .. } => {
+                self.depth -= 1;
+            }
+            _ => {}
+        }
+        debug!("Fetched {:?}", next);
+        Ok(next)
+    }
+
+    fn set_map_value(&mut self) {
+        self.is_map_value = true;
+    }
+
+    pub fn unset_map_value(&mut self) -> bool {
+        ::std::mem::replace(&mut self.is_map_value, false)
+    }
+
+    fn read_inner_value<V: de::Visitor<'de>, T, F: FnOnce(&mut Self) -> Result<T>>(
+        &mut self,
+        f: F,
+    ) -> Result<T> {
+        if self.unset_map_value() {
+            debug_expect!(self.next(), Ok(XmlEvent::StartElement { name, .. }) => {
+                let result = f(self)?;
+                self.expect_end_element(name)?;
+                Ok(result)
+            })
+        } else {
+            f(self)
+        }
+    }
+
+    fn expect_end_element(&mut self, start_name: OwnedName) -> Result<()> {
+        expect!(self.next()?, XmlEvent::EndElement { name, .. } => {
+            if name == start_name {
+                Ok(())
+            } else {
+                Err(Error::Custom { field: format!(
+                    "End tag </{}> didn't match the start tag <{}>",
+                    name.local_name,
+                    start_name.local_name
+                ) })
+            }
+        })
+    }
+
+    fn prepare_parse_type<V: de::Visitor<'de>>(&mut self) -> Result<String> {
+        if let XmlEvent::StartElement { .. } = *self.peek()? {
+            self.set_map_value()
+        }
+        self.read_inner_value::<V, String, _>(|this| {
+            if let XmlEvent::EndElement { .. } = *this.peek()? {
+                return Err(Error::UnexpectedToken {
+                    token: "EndElement".into(),
+                    found: "Characters".into(),
+                });
+            }
+
+            expect!(this.next()?, XmlEvent::Characters(s) => {
+                return Ok(s)
+            })
+        })
+    }
+}
+
+macro_rules! deserialize_type {
+    ($deserialize:ident => $visit:ident) => {
+        fn $deserialize<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
+            let value = self.prepare_parse_type::<V>()?.parse()?;
+            visitor.$visit(value)
+        }
+    }
+}
+
+impl<'de, 'a, R: Read> de::Deserializer<'de> for &'a mut Deserializer<R> {
+    type Error = Error;
+
+    forward_to_deserialize_any! {
+        identifier
+    }
+
+    fn deserialize_struct<V: de::Visitor<'de>>(
+        self,
+        _name: &'static str,
+        fields: &'static [&'static str],
+        visitor: V,
+    ) -> Result<V::Value> {
+        self.unset_map_value();
+        expect!(self.next()?, XmlEvent::StartElement { name, attributes, .. } => {
+            let map_value = visitor.visit_map(MapAccess::new(
+                self,
+                attributes,
+                fields.contains(&"$value")
+            ))?;
+            self.expect_end_element(name)?;
+            Ok(map_value)
+        })
+    }
+
+    deserialize_type!(deserialize_i8 => visit_i8);
+    deserialize_type!(deserialize_i16 => visit_i16);
+    deserialize_type!(deserialize_i32 => visit_i32);
+    deserialize_type!(deserialize_i64 => visit_i64);
+    deserialize_type!(deserialize_u8 => visit_u8);
+    deserialize_type!(deserialize_u16 => visit_u16);
+    deserialize_type!(deserialize_u32 => visit_u32);
+    deserialize_type!(deserialize_u64 => visit_u64);
+    deserialize_type!(deserialize_f32 => visit_f32);
+    deserialize_type!(deserialize_f64 => visit_f64);
+
+    fn deserialize_bool<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
+        if let XmlEvent::StartElement { .. } = *self.peek()? {
+            self.set_map_value()
+        }
+        self.read_inner_value::<V, V::Value, _>(|this| {
+            if let XmlEvent::EndElement { .. } = *this.peek()? {
+                return visitor.visit_bool(false);
+            }
+            expect!(this.next()?, XmlEvent::Characters(s) => {
+                match s.as_str() {
+                    "true" | "1" => visitor.visit_bool(true),
+                    "false" | "0" => visitor.visit_bool(false),
+                    _ => Err(de::Error::invalid_value(Unexpected::Str(&s), &"a boolean")),
+                }
+
+            })
+        })
+    }
+
+    fn deserialize_char<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
+        self.deserialize_string(visitor)
+    }
+
+    fn deserialize_str<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
+        self.deserialize_string(visitor)
+    }
+
+    fn deserialize_bytes<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
+        self.deserialize_string(visitor)
+    }
+
+    fn deserialize_byte_buf<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
+        self.deserialize_string(visitor)
+    }
+
+    fn deserialize_unit<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
+        if let XmlEvent::StartElement { .. } = *self.peek()? {
+            self.set_map_value()
+        }
+        self.read_inner_value::<V, V::Value, _>(
+            |this| expect!(this.peek()?, &XmlEvent::EndElement { .. } => visitor.visit_unit()),
+        )
+    }
+
+    fn deserialize_unit_struct<V: de::Visitor<'de>>(
+        self,
+        _name: &'static str,
+        visitor: V,
+    ) -> Result<V::Value> {
+        self.deserialize_unit(visitor)
+    }
+
+    fn deserialize_newtype_struct<V: de::Visitor<'de>>(
+        self,
+        _name: &'static str,
+        visitor: V,
+    ) -> Result<V::Value> {
+        visitor.visit_newtype_struct(self)
+    }
+
+    fn deserialize_tuple_struct<V: de::Visitor<'de>>(
+        self,
+        _name: &'static str,
+        len: usize,
+        visitor: V,
+    ) -> Result<V::Value> {
+        self.deserialize_tuple(len, visitor)
+    }
+
+    fn deserialize_tuple<V: de::Visitor<'de>>(self, len: usize, visitor: V) -> Result<V::Value> {
+        visitor.visit_seq(SeqAccess::new(self, Some(len)))
+    }
+
+    fn deserialize_enum<V: de::Visitor<'de>>(
+        self,
+        _name: &'static str,
+        _variants: &'static [&'static str],
+        visitor: V,
+    ) -> Result<V::Value> {
+        self.read_inner_value::<V, V::Value, _>(|this| visitor.visit_enum(EnumAccess::new(this)))
+    }
+
+    fn deserialize_string<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
+        if let XmlEvent::StartElement { .. } = *self.peek()? {
+            self.set_map_value()
+        }
+        self.read_inner_value::<V, V::Value, _>(|this| {
+            if let XmlEvent::EndElement { .. } = *this.peek()? {
+                return visitor.visit_str("");
+            }
+            expect!(this.next()?, XmlEvent::Characters(s) => {
+                visitor.visit_string(s)
+            })
+        })
+    }
+
+    fn deserialize_seq<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
+        visitor.visit_seq(SeqAccess::new(self, None))
+    }
+
+    fn deserialize_map<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
+        self.unset_map_value();
+        expect!(self.next()?, XmlEvent::StartElement { name, attributes, .. } => {
+            let map_value = visitor.visit_map(MapAccess::new(self, attributes, false))?;
+            self.expect_end_element(name)?;
+            Ok(map_value)
+        })
+    }
+
+    fn deserialize_option<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
+        match *self.peek()? {
+            XmlEvent::EndElement { .. } => visitor.visit_none(),
+            _ => visitor.visit_some(self),
+        }
+    }
+
+    fn deserialize_ignored_any<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
+        self.unset_map_value();
+        let depth = self.depth;
+        loop {
+            self.next()?;
+            if self.depth == depth {
+                break;
+            }
+        }
+        visitor.visit_unit()
+    }
+
+    fn deserialize_any<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
+        match *self.peek()? {
+            XmlEvent::StartElement { .. } => self.deserialize_map(visitor),
+            XmlEvent::EndElement { .. } => self.deserialize_unit(visitor),
+            _ => self.deserialize_string(visitor),
+        }
+    }
+}
diff --git a/src/de/seq.rs b/src/de/seq.rs
new file mode 100644
index 0000000..7e88d0c
--- /dev/null
+++ b/src/de/seq.rs
@@ -0,0 +1,70 @@
+use std::io::Read;
+
+use serde::de;
+use xml::reader::XmlEvent;
+
+use de::Deserializer;
+use error::{Error, Result};
+
+pub struct SeqAccess<'a, R: 'a + Read> {
+    de: &'a mut Deserializer<R>,
+    max_size: Option<usize>,
+    expected_name: Option<String>,
+}
+
+impl<'a, R: 'a + Read> SeqAccess<'a, R> {
+    pub fn new(de: &'a mut Deserializer<R>, max_size: Option<usize>) -> Self {
+        let expected_name = if de.unset_map_value() {
+            debug_expect!(de.peek(), Ok(&XmlEvent::StartElement { ref name, .. }) => {
+                Some(name.local_name.clone())
+            })
+        } else {
+            None
+        };
+        SeqAccess {
+            de: de,
+            max_size: max_size,
+            expected_name: expected_name,
+        }
+    }
+}
+
+impl<'de, 'a, R: 'a + Read> de::SeqAccess<'de> for SeqAccess<'a, R> {
+    type Error = Error;
+
+    fn next_element_seed<T: de::DeserializeSeed<'de>>(
+        &mut self,
+        seed: T,
+    ) -> Result<Option<T::Value>> {
+        match self.max_size.as_mut() {
+            Some(&mut 0) => {
+                return Ok(None);
+            },
+            Some(max_size) => {
+                *max_size -= 1;
+            },
+            None => {},
+        }
+        let more = match (self.de.peek()?, self.expected_name.as_ref()) {
+            (&XmlEvent::StartElement { ref name, .. }, Some(expected_name)) => {
+                &name.local_name == expected_name
+            },
+            (&XmlEvent::EndElement { .. }, None) |
+            (_, Some(_)) |
+            (&XmlEvent::EndDocument { .. }, _) => false,
+            (_, None) => true,
+        };
+        if more {
+            if self.expected_name.is_some() {
+                self.de.set_map_value();
+            }
+            seed.deserialize(&mut *self.de).map(Some)
+        } else {
+            Ok(None)
+        }
+    }
+
+    fn size_hint(&self) -> Option<usize> {
+        self.max_size
+    }
+}
diff --git a/src/de/var.rs b/src/de/var.rs
new file mode 100644
index 0000000..dbb400f
--- /dev/null
+++ b/src/de/var.rs
@@ -0,0 +1,84 @@
+use std::io::Read;
+
+use serde::de::{self, Deserializer as SerdeDeserializer, IntoDeserializer};
+use xml::name::OwnedName;
+use xml::reader::XmlEvent;
+
+use de::Deserializer;
+use error::{Error, Result};
+
+pub struct EnumAccess<'a, R: 'a + Read> {
+    de: &'a mut Deserializer<R>,
+}
+
+impl<'a, R: 'a + Read> EnumAccess<'a, R> {
+    pub fn new(de: &'a mut Deserializer<R>) -> Self {
+        EnumAccess { de: de }
+    }
+}
+
+impl<'de, 'a, R: 'a + Read> de::EnumAccess<'de> for EnumAccess<'a, R> {
+    type Error = Error;
+    type Variant = VariantAccess<'a, R>;
+
+    fn variant_seed<V: de::DeserializeSeed<'de>>(
+        self,
+        seed: V,
+    ) -> Result<(V::Value, VariantAccess<'a, R>)> {
+        let name = expect!(
+            self.de.peek()?,
+
+            &XmlEvent::Characters(ref name) |
+            &XmlEvent::StartElement { name: OwnedName { local_name: ref name, .. }, .. } => {
+                seed.deserialize(name.as_str().into_deserializer())
+            }
+        )?;
+        self.de.set_map_value();
+        Ok((name, VariantAccess::new(self.de)))
+    }
+}
+
+pub struct VariantAccess<'a, R: 'a + Read> {
+    de: &'a mut Deserializer<R>,
+}
+
+impl<'a, R: 'a + Read> VariantAccess<'a, R> {
+    pub fn new(de: &'a mut Deserializer<R>) -> Self {
+        VariantAccess { de: de }
+    }
+}
+
+impl<'de, 'a, R: 'a + Read> de::VariantAccess<'de> for VariantAccess<'a, R> {
+    type Error = Error;
+
+    fn unit_variant(self) -> Result<()> {
+        self.de.unset_map_value();
+        match self.de.next()? {
+            XmlEvent::StartElement {
+                name, attributes, ..
+            } => if attributes.is_empty() {
+                self.de.expect_end_element(name)
+            } else {
+                Err(de::Error::invalid_length(attributes.len(), &"0"))
+            },
+            XmlEvent::Characters(_) => Ok(()),
+            _ => unreachable!(),
+        }
+    }
+
+    fn newtype_variant_seed<T: de::DeserializeSeed<'de>>(self, seed: T) -> Result<T::Value> {
+        seed.deserialize(&mut *self.de)
+    }
+
+    fn tuple_variant<V: de::Visitor<'de>>(self, len: usize, visitor: V) -> Result<V::Value> {
+        self.de.deserialize_tuple(len, visitor)
+    }
+
+    fn struct_variant<V: de::Visitor<'de>>(
+        self,
+        _fields: &'static [&'static str],
+        visitor: V,
+    ) -> Result<V::Value> {
+        self.de.deserialize_map(visitor)
+    }
+}
diff --git a/src/error.rs b/src/error.rs
new file mode 100644
index 0000000..8d6e4ad
--- /dev/null
+++ b/src/error.rs
@@ -0,0 +1,104 @@
+use serde::de::Error as DeError;
+use serde::ser::Error as SerError;
+use std::fmt::Display;
+use thiserror::Error;
+
+#[derive(Debug, Error)]
+pub enum Error {
+    #[error("Expected token {token}, found {found}")]
+    UnexpectedToken { token: String, found: String },
+    #[error("custom: {field}")]
+    Custom { field: String },
+    #[error("unsupported operation: '{operation}'")]
+    UnsupportedOperation { operation: String },
+
+    #[error("IO error: {source}")]
+    Io {
+        #[from]
+        source: ::std::io::Error,
+    },
+
+    #[error("FromUtf8Error: {source}")]
+    FromUtf8Error {
+        #[from]
+        source: ::std::string::FromUtf8Error,
+    },
+
+    #[error("ParseIntError: {source}")]
+    ParseIntError {
+        #[from]
+        source: ::std::num::ParseIntError,
+    },
+
+    #[error("ParseFloatError: {source}")]
+    ParseFloatError {
+        #[from]
+        source: ::std::num::ParseFloatError,
+    },
+
+    #[error("ParseBoolError: {source}")]
+    ParseBoolError {
+        #[from]
+        source: ::std::str::ParseBoolError,
+    },
+
+    #[error("Syntax: {source}")]
+    Syntax {
+        #[from]
+        source: ::xml::reader::Error,
+    },
+}
+
+pub type Result<T> = std::result::Result<T, Error>;
+
+macro_rules! expect {
+    ($actual: expr, $($expected: pat)|+ => $if_ok: expr) => {
+        match $actual {
+            $($expected)|+ => $if_ok,
+            actual => Err($crate::Error::UnexpectedToken {
+                token: stringify!($($expected)|+).to_string(),
+                found: format!("{:?}",actual)
+            }) as Result<_>
+        }
+    }
+}
+
+#[cfg(debug_assertions)]
+macro_rules! debug_expect {
+    ($actual: expr, $($expected: pat)|+ => $if_ok: expr) => {
+        match $actual {
+            $($expected)|+ => $if_ok,
+            actual => panic!(
+                "Internal error: Expected token {}, found {:?}",
+                stringify!($($expected)|+),
+                actual
+            )
+        }
+    }
+}
+
+#[cfg(not(debug_assertions))]
+macro_rules! debug_expect {
+    ($actual: expr, $($expected: pat)|+ => $if_ok: expr) => {
+        match $actual {
+            $($expected)|+ => $if_ok,
+            _ => unreachable!()
+        }
+    }
+}
+
+impl DeError for Error {
+    fn custom<T: Display>(msg: T) -> Self {
+        Error::Custom {
+            field: msg.to_string(),
+        }
+    }
+}
+
+impl SerError for Error {
+    fn custom<T: Display>(msg: T) -> Self {
+        Error::Custom {
+            field: msg.to_string(),
+        }
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..1f93ed8
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,55 @@
+//!
+//!
+//! # Examples
+//!
+//! ```rust
+//! extern crate serde;
+//! extern crate serde_xml_rs;
+//!
+//! #[macro_use]
+//! extern crate serde_derive;
+//!
+//! use serde_xml_rs::{from_str, to_string};
+//!
+//! #[derive(Debug, Serialize, Deserialize, PartialEq)]
+//! struct Item {
+//!     name: String,
+//!     source: String,
+//! }
+//!
+//! fn main() {
+//!     let src = r#"<Item><name>Banana</name><source>Store</source></Item>"#;
+//!     let should_be = Item {
+//!         name: "Banana".to_string(),
+//!         source: "Store".to_string(),
+//!     };
+//!
+//!     let item: Item = from_str(src).unwrap();
+//!     assert_eq!(item, should_be);
+//!
+//!     let reserialized_item = to_string(&item).unwrap();
+//!     assert_eq!(src, reserialized_item);
+//! }
+//! ```
+
+#[macro_use]
+extern crate log;
+#[macro_use]
+extern crate serde;
+extern crate xml;
+
+extern crate thiserror;
+
+#[cfg(test)]
+#[macro_use]
+extern crate serde_derive;
+
+#[macro_use]
+mod error;
+pub mod de;
+pub mod ser;
+
+pub use de::{from_reader, from_str, Deserializer};
+pub use error::Error;
+pub use ser::{to_string, to_writer, Serializer};
+pub use xml::reader::{EventReader, ParserConfig};
diff --git a/src/ser/mod.rs b/src/ser/mod.rs
new file mode 100644
index 0000000..bf97b1f
--- /dev/null
+++ b/src/ser/mod.rs
@@ -0,0 +1,419 @@
+use std::fmt::Display;
+use std::io::Write;
+
+use serde::ser::{self, Impossible, Serialize};
+
+use self::var::{Map, Struct};
+use error::{Error, Result};
+
+mod var;
+
+/// 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_xml_rs::to_writer;
+/// #[derive(Serialize)]
+/// struct Person {
+///   name: String,
+///   age: u32,
+/// }
+///
+/// # fn main() {
+/// let mut buffer = Vec::new();
+/// let joe = Person {name: "Joe".to_string(), age: 42};
+///
+/// to_writer(&mut buffer, &joe).unwrap();
+///
+/// let serialized = String::from_utf8(buffer).unwrap();
+/// println!("{}", serialized);
+/// # }
+/// ```
+pub fn to_writer<W: Write, S: Serialize>(writer: W, value: &S) -> Result<()> {
+    let mut ser = Serializer::new(writer);
+    value.serialize(&mut ser)
+}
+
+/// A convenience method for serializing some object to a string.
+///
+/// # Examples
+///
+/// ```rust
+/// # #[macro_use]
+/// # extern crate serde_derive;
+/// # extern crate serde;
+/// # extern crate serde_xml_rs;
+/// # use serde_xml_rs::to_string;
+/// #[derive(Serialize)]
+/// struct Person {
+///   name: String,
+///   age: u32,
+/// }
+///
+/// # fn main() {
+///
+/// let joe = Person {name: "Joe".to_string(), age: 42};
+/// let serialized = to_string(&joe).unwrap();
+/// println!("{}", serialized);
+/// # }
+/// ```
+pub fn to_string<S: Serialize>(value: &S) -> Result<String> {
+    // Create a buffer and serialize our nodes into it
+    let mut writer = Vec::with_capacity(128);
+    to_writer(&mut writer, value)?;
+
+    // We then check that the serialized string is the same as what we expect
+    let string = String::from_utf8(writer)?;
+    Ok(string)
+}
+
+/// An XML `Serializer`.
+pub struct Serializer<W>
+where
+    W: Write,
+{
+    writer: W,
+}
+
+impl<W> Serializer<W>
+where
+    W: Write,
+{
+    pub fn new(writer: W) -> Self {
+        Self { writer: writer }
+    }
+
+    fn write_primitive<P: Display>(&mut self, primitive: P) -> Result<()> {
+        write!(self.writer, "{}", primitive)?;
+        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)?;
+        Ok(())
+    }
+}
+
+#[allow(unused_variables)]
+impl<'w, W> ser::Serializer for &'w mut Serializer<W>
+where
+    W: Write,
+{
+    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>;
+
+    fn serialize_bool(self, v: bool) -> Result<Self::Ok> {
+        if v {
+            write!(self.writer, "true")?;
+        } else {
+            write!(self.writer, "false")?;
+        }
+
+        Ok(())
+    }
+
+    fn serialize_i8(self, v: i8) -> Result<Self::Ok> {
+        self.write_primitive(v)
+    }
+
+    fn serialize_i16(self, v: i16) -> Result<Self::Ok> {
+        self.write_primitive(v)
+    }
+
+    fn serialize_i32(self, v: i32) -> Result<Self::Ok> {
+        self.write_primitive(v)
+    }
+
+    fn serialize_i64(self, v: i64) -> Result<Self::Ok> {
+        self.write_primitive(v)
+    }
+
+    fn serialize_u8(self, v: u8) -> Result<Self::Ok> {
+        self.write_primitive(v)
+    }
+
+    fn serialize_u16(self, v: u16) -> Result<Self::Ok> {
+        self.write_primitive(v)
+    }
+
+    fn serialize_u32(self, v: u32) -> Result<Self::Ok> {
+        self.write_primitive(v)
+    }
+
+    fn serialize_u64(self, v: u64) -> Result<Self::Ok> {
+        self.write_primitive(v)
+    }
+
+    fn serialize_f32(self, v: f32) -> Result<Self::Ok> {
+        self.write_primitive(v)
+    }
+
+    fn serialize_f64(self, v: f64) -> Result<Self::Ok> {
+        self.write_primitive(v)
+    }
+
+    fn serialize_char(self, v: char) -> Result<Self::Ok> {
+        self.write_primitive(v)
+    }
+
+    fn serialize_str(self, value: &str) -> Result<Self::Ok> {
+        self.write_primitive(value)
+    }
+
+    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_none(self) -> Result<Self::Ok> {
+        Ok(())
+    }
+
+    fn serialize_some<T: ?Sized + Serialize>(self, value: &T) -> Result<Self::Ok> {
+        value.serialize(self)
+    }
+
+    fn serialize_unit(self) -> Result<Self::Ok> {
+        self.serialize_none()
+    }
+
+    fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok> {
+        self.write_wrapped(name, ())
+    }
+
+    fn serialize_unit_variant(
+        self,
+        name: &'static str,
+        variant_index: u32,
+        variant: &'static str,
+    ) -> Result<Self::Ok> {
+        Err(Error::UnsupportedOperation {
+            operation: "serialize_unit_variant".to_string(),
+        })
+    }
+
+    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_variant<T: ?Sized + Serialize>(
+        self,
+        name: &'static str,
+        variant_index: u32,
+        variant: &'static str,
+        value: &T,
+    ) -> Result<Self::Ok> {
+        self.write_wrapped(variant, value)
+    }
+
+    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_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
+        Err(Error::UnsupportedOperation {
+            operation: "serialize_tuple".to_string(),
+        })
+    }
+
+    fn serialize_tuple_struct(
+        self,
+        name: &'static str,
+        len: usize,
+    ) -> Result<Self::SerializeTupleStruct> {
+        Err(Error::UnsupportedOperation {
+            operation: "serialize_tuple_struct".to_string(),
+        })
+    }
+
+    fn serialize_tuple_variant(
+        self,
+        name: &'static str,
+        variant_index: u32,
+        variant: &'static str,
+        len: usize,
+    ) -> Result<Self::SerializeTupleVariant> {
+        Err(Error::UnsupportedOperation {
+            operation: "serialize_tuple_variant".to_string(),
+        })
+    }
+
+    fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap> {
+        Ok(Map::new(self))
+    }
+
+    fn serialize_struct(self, name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
+        write!(self.writer, "<{}>", name)?;
+        Ok(Struct::new(self, name))
+    }
+
+    fn serialize_struct_variant(
+        self,
+        name: &'static str,
+        variant_index: u32,
+        variant: &'static str,
+        len: usize,
+    ) -> Result<Self::SerializeStructVariant> {
+        Err(Error::UnsupportedOperation {
+            operation: "Result".to_string(),
+        })
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use serde::ser::{SerializeMap, SerializeStruct};
+    use serde::Serializer as SerSerializer;
+
+    #[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>");
+    }
+
+    #[test]
+    fn test_serialize_struct() {
+        #[derive(Serialize)]
+        struct Person {
+            name: String,
+            age: u32,
+        }
+
+        let bob = Person {
+            name: "Bob".to_string(),
+            age: 42,
+        };
+        let should_be = "<Person><name>Bob</name><age>42</age></Person>";
+        let mut buffer = Vec::new();
+
+        {
+            let mut ser = Serializer::new(&mut buffer);
+            bob.serialize(&mut ser).unwrap();
+        }
+
+        let got = String::from_utf8(buffer).unwrap();
+        assert_eq!(got, should_be);
+    }
+
+    #[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)]
+        enum Node {
+            Boolean(bool),
+            Number(f64),
+            String(String),
+        }
+
+        let mut buffer = Vec::new();
+        let should_be = "<Boolean>true</Boolean>";
+
+        {
+            let mut ser = Serializer::new(&mut buffer);
+            let node = Node::Boolean(true);
+            node.serialize(&mut ser).unwrap();
+        }
+
+        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/var.rs b/src/ser/var.rs
new file mode 100644
index 0000000..bb61472
--- /dev/null
+++ b/src/ser/var.rs
@@ -0,0 +1,103 @@
+use std::io::Write;
+
+use serde::ser::{self, Serialize};
+
+use ser::Serializer;
+use error::{Error, Result};
+
+/// An implementation of `SerializeMap` for serializing to XML.
+pub struct Map<'w, W>
+where
+    W: '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: '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/failures.rs b/tests/failures.rs
new file mode 100644
index 0000000..ca51f6b
--- /dev/null
+++ b/tests/failures.rs
@@ -0,0 +1,52 @@
+#[macro_use]
+extern crate serde_derive;
+extern crate serde_xml_rs;
+
+#[macro_use]
+extern crate log;
+extern crate simple_logger;
+
+use serde_xml_rs::from_str;
+
+#[derive(Debug, Deserialize, PartialEq)]
+struct Item {
+    name: String,
+    source: String,
+}
+
+#[test]
+fn simple_struct_from_attributes_should_fail() {
+    let _ = simple_logger::init();
+
+    let s = r##"
+        <item name="hello" source="world.rs />
+    "##;
+
+    let item: Result<Item, _> = from_str(s);
+    match item {
+        Ok(_) => assert!(false),
+        Err(e) => {
+            info!("simple_struct_from_attributes_should_fail(): {}", e);
+            assert!(true)
+        }
+    }
+}
+
+#[test]
+fn multiple_roots_attributes_should_fail() {
+    let _ = simple_logger::init();
+
+    let s = r##"
+        <item name="hello" source="world.rs" />
+        <item name="hello source="world.rs" />
+    "##;
+
+    let item: Result<Vec<Item>, _> = from_str(s);
+    match item {
+        Ok(_) => assert!(false),
+        Err(e) => {
+            info!("multiple_roots_attributes_should_fail(): {}", e);
+            assert!(true)
+        }
+    }
+}
diff --git a/tests/migrated.rs b/tests/migrated.rs
new file mode 100644
index 0000000..87d3e6a
--- /dev/null
+++ b/tests/migrated.rs
@@ -0,0 +1,1086 @@
+#[macro_use]
+extern crate serde_derive;
+
+extern crate log;
+extern crate simple_logger;
+
+extern crate serde;
+extern crate serde_xml_rs;
+
+use std::fmt::Debug;
+
+use serde::{de, ser};
+use serde_xml_rs::{from_str, Error};
+
+#[derive(PartialEq, Debug, Serialize, Deserialize)]
+enum Animal {
+    Dog,
+    Frog(String),
+    Ant(Simple),
+    Cat { age: usize, name: String },
+}
+
+#[derive(PartialEq, Debug, Serialize, Deserialize)]
+struct Simple {
+    a: (),
+    b: usize,
+    c: String,
+    d: Option<String>,
+}
+
+#[derive(PartialEq, Debug, Serialize, Deserialize)]
+struct Inner {
+    a: (),
+    b: (usize, String, i8),
+    c: Vec<String>,
+}
+
+#[derive(PartialEq, Debug, Serialize, Deserialize)]
+struct Outer {
+    inner: Option<Inner>,
+}
+
+fn test_parse_ok<'de, 'a, T>(errors: &[(&'a str, T)])
+where
+    T: PartialEq + Debug + ser::Serialize + de::Deserialize<'de>,
+{
+    for &(s, ref value) in errors {
+        let v: T = from_str(s).unwrap();
+        assert_eq!(v, *value);
+
+        // // Make sure we can deserialize into an `Element`.
+        // let xml_value: Element = from_str(s).unwrap();
+
+        // // Make sure we can deserialize from an `Element`.
+        // let v: T = from_value(xml_value.clone()).unwrap();
+        // assert_eq!(v, *value);
+    }
+}
+
+fn test_parse_err<'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(Error::Syntax { source: _ }) => true,
+            _ => false,
+        });
+    }
+}
+
+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() {
+    let _ = simple_logger::init();
+    #[derive(PartialEq, Serialize, Deserialize, Debug)]
+    struct Envelope {
+        subject: String,
+    }
+    let s = r#"
+    <?xml version="1.0" encoding="UTF-8"?>
+    <gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
+        <gesmes:subject>Reference rates</gesmes:subject>
+    </gesmes:Envelope>"#;
+    test_parse_ok(&[(
+        s,
+        Envelope {
+            subject: "Reference rates".to_string(),
+        },
+    )]);
+}
+
+#[test]
+#[ignore] // FIXME
+fn test_doctype() {
+    let _ = simple_logger::init();
+    #[derive(PartialEq, Serialize, Deserialize, Debug)]
+    struct Envelope {
+        subject: String,
+    }
+
+    test_parse_ok(&[
+        (
+            r#"
+            <?xml version="1.0" encoding="UTF-8"?>
+            <!DOCTYPE Envelope>
+            <Envelope>
+            <subject>Reference rates</subject>
+            </Envelope>"#,
+            Envelope {
+                subject: "Reference rates".to_string(),
+            },
+        ),
+        (
+            r#"
+            <?xml version="1.0" encoding="UTF-8"?>
+            <!DOCTYPE Envelope[]>
+            <Envelope>
+            <subject>Reference rates</subject>
+            </Envelope>"#,
+            Envelope {
+                subject: "Reference rates".to_string(),
+            },
+        ),
+        (
+            r#"
+            <?xml version="1.0" encoding="UTF-8"?>
+            <!DOCTYPE Envelope [
+                <!ELEMENT subject (#PCDATA)>
+            ] >
+            <Envelope>
+            <subject>Reference rates</subject>
+            </Envelope>"#,
+            Envelope {
+                subject: "Reference rates".to_string(),
+            },
+        ),
+    ]);
+}
+
+#[test]
+fn test_doctype_fail() {
+    let _ = simple_logger::init();
+    #[derive(PartialEq, Serialize, Deserialize, Debug)]
+    struct Envelope {
+        subject: String,
+    }
+
+    test_parse_err::<Envelope>(&[
+        r#"
+            <?xml version="1.0" encoding="UTF-8"?>
+            <!DOCTYPE Envelope [
+                <!ELEMENT subject (#PCDATA)>
+            >
+            <Envelope>
+            <subject>Reference rates</subject>
+            </Envelope>"#,
+        r#"
+            <?xml version="1.0" encoding="UTF-8"?>
+            <Envelope>
+            <subject>Reference rates</subject>
+
+            <!DOCTYPE Envelope [
+                <!ELEMENT subject (#PCDATA)>
+            ]>
+
+            </Envelope>"#,
+    ])
+}
+
+#[test]
+#[ignore] // FIXME
+fn test_forwarded_namespace() {
+    #[derive(PartialEq, Serialize, Deserialize, Debug)]
+    struct Graphml {
+        #[serde(rename = "xsi:schemaLocation")]
+        schema_location: String,
+    }
+    let s = r#"
+    <?xml version="1.0" encoding="UTF-8"?>
+    <graphml xmlns="http://graphml.graphdrawing.org/xmlns"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
+        http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
+
+
+    </graphml>"#;
+    test_parse_ok(&[(
+        s,
+        Graphml {
+            schema_location: "http://graphml.graphdrawing.org/xmlns
+        http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd"
+                .to_string(),
+        },
+    )]);
+}
+
+#[test]
+fn test_parse_string() {
+    let _ = simple_logger::init();
+
+    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() {
+    let _ = simple_logger::init();
+
+    test_parse_ok(&[("<bla>     </bla>", "     ".to_string())]);
+}
+
+#[test]
+#[ignore] // FIXME
+fn test_parse_enum() {
+    use self::Animal::*;
+    let _ = simple_logger::init();
+
+    test_parse_ok(&[
+        ("<Animal xsi:type=\"Dog\"/>", Dog),
+        (
+            "<Animal xsi:type=\"Frog\">Quak</Animal>",
+            Frog("Quak".to_string()),
+        ),
+        (
+            "<Animal xsi:type=\"Ant\"><a/><c>bla</c><b>15</b><d>Foo</d></Animal>",
+            Ant(Simple {
+                a: (),
+                b: 15,
+                c: "bla".to_string(),
+                d: Some("Foo".to_string()),
+            }),
+        ),
+        (
+            "<Animal xsi:type=\"Ant\"><a/><c>bla</c><b>15</b></Animal>",
+            Ant(Simple {
+                a: (),
+                b: 15,
+                c: "bla".to_string(),
+                d: None,
+            }),
+        ),
+        (
+            "<Animal xsi:type=\"Cat\"><age>42</age><name>Shere Khan</name></Animal>",
+            Cat {
+                age: 42,
+                name: "Shere Khan".to_string(),
+            },
+        ),
+    ]);
+
+    #[derive(PartialEq, Debug, Serialize, Deserialize)]
+    struct Helper {
+        x: Animal,
+    }
+
+    test_parse_ok(&[
+        ("<Helper><x xsi:type=\"Dog\"/></Helper>", Helper { x: Dog }),
+        (
+            "<Helper><x xsi:type=\"Frog\">Quak</Animal></Helper>",
+            Helper {
+                x: Frog("Quak".to_string()),
+            },
+        ),
+        (
+            "<Helper><x xsi:type=\"Cat\">
+                <age>42</age>
+                <name>Shere Khan</name>
+            </x></Helper>",
+            Helper {
+                x: Cat {
+                    age: 42,
+                    name: "Shere Khan".to_string(),
+                },
+            },
+        ),
+    ]);
+}
+
+#[test]
+fn test_parse_i64() {
+    let _ = simple_logger::init();
+    test_parse_ok(&[
+        ("<bla>0</bla>", 0),
+        ("<bla>-2</bla>", -2),
+        ("<bla>-1234</bla>", -1234),
+        ("<bla> -1234 </bla>", -1234),
+    ]);
+}
+
+#[test]
+fn test_parse_u64() {
+    let _ = simple_logger::init();
+    test_parse_ok(&[
+        ("<bla>0</bla>", 0),
+        ("<bla>1234</bla>", 1234),
+        ("<bla> 1234 </bla>", 1234),
+    ]);
+}
+
+#[test]
+fn test_parse_bool_element() {
+    let _ = simple_logger::init();
+    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,
+    }
+
+    let _ = simple_logger::init();
+    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() {
+    let _ = simple_logger::init();
+    test_parse_ok(&[("<bla/>", ())]);
+}
+
+#[test]
+fn test_parse_f64() {
+    let _ = simple_logger::init();
+    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() {
+    let _ = simple_logger::init();
+
+    test_parse_ok(&[
+        (
+            "<Simple>
+                <c>abc</c>
+                <a/>
+                <b>2</b>
+            </Simple>",
+            Simple {
+                a: (),
+                b: 2,
+                c: "abc".to_string(),
+                d: None,
+            },
+        ),
+        (
+            "<Simple><!-- this is a comment -->
+                <c>abc</c>
+                <a/>
+                <b>2</b>
+            </Simple>",
+            Simple {
+                a: (),
+                b: 2,
+                c: "abc".to_string(),
+                d: None,
+            },
+        ),
+        (
+            "<Simple d=\"Foo\"><!-- this is a comment -->
+                <c>abc</c>
+                <a/>
+                <b>2</b>
+            </Simple>",
+            Simple {
+                a: (),
+                b: 2,
+                c: "abc".to_string(),
+                d: Some("Foo".to_string()),
+            },
+        ),
+    ]);
+}
+
+#[test]
+fn test_option() {
+    let _ = simple_logger::init();
+    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() {
+    let _ = simple_logger::init();
+    test_parse_ok(&[("<a> </a>", Some(" ".to_string()))]);
+}
+
+#[test]
+fn test_amoskvin() {
+    let _ = simple_logger::init();
+    #[derive(Debug, Deserialize, PartialEq, Serialize)]
+    struct Root {
+        foo: Vec<Foo>,
+    }
+
+    #[derive(Debug, Deserialize, PartialEq, Serialize)]
+    struct Foo {
+        a: String,
+        b: Option<String>,
+    }
+    test_parse_ok(&[(
+        "
+<root>
+<foo>
+ <a>Hello</a>
+ <b>World</b>
+</foo>
+<foo>
+ <a>Hi</a>
+</foo>
+</root>",
+        Root {
+            foo: vec![
+                Foo {
+                    a: "Hello".to_string(),
+                    b: Some("World".to_string()),
+                },
+                Foo {
+                    a: "Hi".to_string(),
+                    b: None,
+                },
+            ],
+        },
+    )]);
+}
+
+#[test]
+#[ignore] // FIXME
+fn test_nicolai86() {
+    let _ = simple_logger::init();
+    #[derive(Serialize, Deserialize, PartialEq, Debug)]
+    struct TheSender {
+        name: String,
+    }
+
+    #[derive(Serialize, Deserialize, PartialEq, Debug)]
+    struct CurrencyCube {
+        currency: String,
+        rate: String,
+    }
+
+    #[derive(Serialize, Deserialize, PartialEq, Debug)]
+    #[allow(non_snake_case)]
+    struct InnerCube {
+        Cube: Vec<CurrencyCube>,
+    }
+
+    #[derive(Serialize, Deserialize, PartialEq, Debug)]
+    #[allow(non_snake_case)]
+    struct OuterCube {
+        Cube: Vec<InnerCube>,
+    }
+
+    #[derive(Serialize, Deserialize, PartialEq, Debug)]
+    #[allow(non_snake_case)]
+    struct Envelope {
+        subject: String,
+        Sender: TheSender,
+        Cube: OuterCube,
+    }
+    test_parse_ok(&[
+        (
+            r#"
+            <?xml version="1.0" encoding="UTF-8"?>
+            <gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
+                <gesmes:subject>Reference rates</gesmes:subject>
+                <gesmes:Sender>
+                    <gesmes:name>European Central Bank</gesmes:name>
+                </gesmes:Sender>
+                <Cube> </Cube>
+            </gesmes:Envelope>"#,
+            Envelope {
+                subject: "Reference rates".to_string(),
+                Sender: TheSender {
+                    name: "European Central Bank".to_string(),
+                },
+                Cube: OuterCube { Cube: vec![] },
+            },
+        ),
+        (
+            r#"
+            <?xml version="1.0" encoding="UTF-8"?>
+            <gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
+                <gesmes:subject>Reference rates</gesmes:subject>
+                <gesmes:Sender>
+                    <gesmes:name>European Central Bank</gesmes:name>
+                </gesmes:Sender>
+                <Cube><Cube>
+                    <Cube currency='GBP' rate='0.81725'/>
+                    <Cube currency='Latinum' rate='999999'/>
+                </Cube></Cube>
+            </gesmes:Envelope>"#,
+            Envelope {
+                subject: "Reference rates".to_string(),
+                Sender: TheSender {
+                    name: "European Central Bank".to_string(),
+                },
+                Cube: OuterCube {
+                    Cube: vec![InnerCube {
+                        Cube: vec![
+                            CurrencyCube {
+                                currency: "GBP".to_string(),
+                                rate: "0.81725".to_string(),
+                            },
+                            CurrencyCube {
+                                currency: "Latinum".to_string(),
+                                rate: "999999".to_string(),
+                            },
+                        ],
+                    }],
+                },
+            },
+        ),
+    ]);
+}
+
+#[test]
+fn test_hugo_duncan2() {
+    let _ = simple_logger::init();
+    let s = r#"
+    <?xml version="1.0" encoding="UTF-8"?>
+    <DescribeVpcsResponse xmlns="http://ec2.amazonaws.com/doc/2014-10-01/">
+        <requestId>8d521e9a-509e-4ef6-bbb7-9f1ac0d49cd1</requestId>
+        <vpcSet>
+            <item>
+                <vpcId>vpc-ba0d18d8</vpcId>
+                <state>available</state>
+            </item>
+        </vpcSet>
+    </DescribeVpcsResponse>"#;
+    #[derive(PartialEq, Debug, Serialize, Deserialize)]
+    #[allow(non_snake_case)]
+    struct VpcSet {
+        vpcId: String,
+        state: String,
+    }
+
+    #[derive(PartialEq, Debug, Serialize)]
+    struct ItemVec<T>(Vec<T>);
+
+    impl<'de, T: de::Deserialize<'de>> de::Deserialize<'de> for ItemVec<T> {
+        fn deserialize<D>(deserializer: D) -> Result<ItemVec<T>, D::Error>
+        where
+            D: de::Deserializer<'de>,
+        {
+            #[derive(PartialEq, Debug, Serialize, Deserialize)]
+            struct Helper<U> {
+                item: Vec<U>,
+            }
+            let h: Helper<_> = de::Deserialize::deserialize(deserializer)?;
+            Ok(ItemVec(h.item))
+        }
+    }
+    #[derive(PartialEq, Debug, Serialize, Deserialize)]
+    #[allow(non_snake_case)]
+    struct DescribeVpcsResponse {
+        requestId: String,
+        vpcSet: ItemVec<VpcSet>,
+    }
+    test_parse_ok(&[(
+        s,
+        DescribeVpcsResponse {
+            requestId: "8d521e9a-509e-4ef6-bbb7-9f1ac0d49cd1".to_string(),
+            vpcSet: ItemVec(vec![VpcSet {
+                vpcId: "vpc-ba0d18d8".to_string(),
+                state: "available".to_string(),
+            }]),
+        },
+    )]);
+}
+
+#[test]
+fn test_hugo_duncan() {
+    let _ = simple_logger::init();
+    let s = "
+        <?xml version=\"1.0\" encoding=\"UTF-8\"?>
+        <DescribeInstancesResponse xmlns=\"http://ec2.amazonaws.com/doc/2014-10-01/\">
+            <requestId>9474f558-10a5-42e8-84d1-f9ee181fe943</requestId>
+            <reservationSet/>
+        </DescribeInstancesResponse>
+    ";
+    #[derive(PartialEq, Debug, Serialize, Deserialize)]
+    #[allow(non_snake_case)]
+    struct DescribeInstancesResponse {
+        requestId: String,
+        reservationSet: (),
+    }
+    test_parse_ok(&[(
+        s,
+        DescribeInstancesResponse {
+            requestId: "9474f558-10a5-42e8-84d1-f9ee181fe943".to_string(),
+            reservationSet: (),
+        },
+    )]);
+}
+
+#[test]
+fn test_parse_xml_value() {
+    let _ = simple_logger::init();
+    #[derive(Eq, Debug, PartialEq, Deserialize, Serialize)]
+    struct Test {
+        #[serde(rename = "$value")]
+        myval: String,
+    }
+    test_parse_ok(&[(
+        "<Test>abc</Test>",
+        Test {
+            myval: "abc".to_string(),
+        },
+    )]);
+}
+
+#[test]
+#[ignore] // FIXME
+fn test_parse_complexstruct() {
+    let _ = simple_logger::init();
+
+    test_parse_ok(&[
+        (
+            "<Outer>
+                <inner>
+                    <b>2</b>
+                    <b>boom</b>
+                    <b>88</b>
+                </inner>
+            </Outer>",
+            Outer {
+                inner: Some(Inner {
+                    a: (),
+                    b: (2, "boom".to_string(), 88),
+                    c: vec![],
+                }),
+            },
+        ),
+        (
+            "<Outer>
+                <inner>
+                    <c>abc</c>
+                    <c>xyz</c>
+                    <a/>
+                    <b>2</b>
+                    <b>boom</b>
+                    <b>88</b>
+                </inner>
+            </Outer>",
+            Outer {
+                inner: Some(Inner {
+                    a: (),
+                    b: (2, "boom".to_string(), 88),
+                    c: vec!["abc".to_string(), "xyz".to_string()],
+                }),
+            },
+        ),
+        ("<Outer/>", Outer { inner: None }),
+    ]);
+}
+
+#[test]
+fn test_parse_attributes() {
+    let _ = simple_logger::init();
+
+    #[derive(PartialEq, Debug, Serialize, Deserialize)]
+    struct A {
+        a1: String,
+        #[serde(rename = "$value")]
+        a2: i32,
+    }
+
+    test_parse_ok(&[(
+        r#"<A a1="What is the answer to the ultimate question?">42</A>"#,
+        A {
+            a1: "What is the answer to the ultimate question?".to_string(),
+            a2: 42,
+        },
+    )]);
+
+    #[derive(PartialEq, Debug, Serialize, Deserialize)]
+    struct B {
+        b1: String,
+        b2: i32,
+    }
+
+    test_parse_ok(&[(
+        r#"<B b1="What is the answer to the ultimate question?" b2="42"/>"#,
+        B {
+            b1: "What is the answer to the ultimate question?".to_string(),
+            b2: 42,
+        },
+    )]);
+
+    #[derive(PartialEq, Debug, Serialize, Deserialize)]
+    struct C {
+        c1: B,
+    }
+
+    test_parse_ok(&[
+        (
+            r#"<C><c1 b1="What is the answer to the ultimate question?" b2="42"/></C>"#,
+            C {
+                c1: B {
+                    b1: "What is the answer to the ultimate question?".to_string(),
+                    b2: 42,
+                },
+            },
+        ),
+        (
+            r#"<C><c1 b1="What is the answer to the ultimate question?" b2="42"/> </C>"#,
+            C {
+                c1: B {
+                    b1: "What is the answer to the ultimate question?".to_string(),
+                    b2: 42,
+                },
+            },
+        ),
+        (
+            r#"<C>  <c1 b1="What is the answer to the ultimate question?" b2="42">
+        </c1> </C>"#,
+            C {
+                c1: B {
+                    b1: "What is the answer to the ultimate question?".to_string(),
+                    b2: 42,
+                },
+            },
+        ),
+    ]);
+
+    #[derive(PartialEq, Debug, Serialize, Deserialize)]
+    struct D {
+        d1: Option<A>,
+    }
+    test_parse_ok(&[(
+        r#"<D><d1 a1="What is the answer to the ultimate question?">42</d1></D>"#,
+        D {
+            d1: Some(A {
+                a1: "What is the answer to the ultimate question?".to_string(),
+                a2: 42,
+            }),
+        },
+    )]);
+}
+
+#[test]
+#[ignore] // FIXME
+fn test_parse_hierarchies() {
+    let _ = simple_logger::init();
+    #[derive(PartialEq, Debug, Serialize, Deserialize)]
+    struct A {
+        a1: String,
+        a2: (String, String),
+    }
+    #[derive(PartialEq, Debug, Serialize, Deserialize)]
+    struct B {
+        b1: A,
+        b2: (A, A),
+    }
+    #[derive(PartialEq, Debug, Serialize, Deserialize)]
+    struct C {
+        c1: B,
+        c2: Vec<B>,
+    }
+
+    test_parse_ok(&[
+        (
+            "<C><c1>
+            <b1>
+                <a1>No</a1>
+                <a2>Maybe</a2>
+                <a2>Yes</a2>
+            </b1>
+            <b2>
+                <a1>Red</a1>
+                <a2>Green</a2>
+                <a2>Blue</a2>
+            </b2>
+            <b2>
+                <a1>London</a1>
+                <a2>Berlin</a2>
+                <a2>Paris</a2>
+            </b2>
+        </c1></C>",
+            C {
+                c1: B {
+                    b1: A {
+                        a1: "No".to_string(),
+                        a2: ("Maybe".to_string(), "Yes".to_string()),
+                    },
+                    b2: (
+                        A {
+                            a1: "Red".to_string(),
+                            a2: ("Green".to_string(), "Blue".to_string()),
+                        },
+                        A {
+                            a1: "London".to_string(),
+                            a2: ("Berlin".to_string(), "Paris".to_string()),
+                        },
+                    ),
+                },
+                c2: vec![],
+            },
+        ),
+        (
+            "<C><c1>
+            <b2>
+                <a2>Green</a2>
+                <a2>Blue</a2>
+                <a1>Red</a1>
+            </b2>
+            <b2>
+                <a2>Berlin</a2>
+                <a2>Paris</a2>
+                <a1>London</a1>
+            </b2>
+            <b1>
+                <a2>Maybe</a2>
+                <a2>Yes</a2>
+                <a1>No</a1>
+            </b1>
+        </c1></C>",
+            C {
+                c1: B {
+                    b1: A {
+                        a1: "No".to_string(),
+                        a2: ("Maybe".to_string(), "Yes".to_string()),
+                    },
+                    b2: (
+                        A {
+                            a1: "Red".to_string(),
+                            a2: ("Green".to_string(), "Blue".to_string()),
+                        },
+                        A {
+                            a1: "London".to_string(),
+                            a2: ("Berlin".to_string(), "Paris".to_string()),
+                        },
+                    ),
+                },
+                c2: vec![],
+            },
+        ),
+    ]);
+}
+
+#[test]
+fn unknown_field() {
+    #[derive(Deserialize, Debug, PartialEq, Eq, Serialize)]
+    struct A {
+        other: Vec<Other>,
+    }
+
+    #[derive(Deserialize, Debug, PartialEq, Eq, Serialize)]
+    struct Other {
+        d: i32,
+    }
+    test_parse_ok(&[(
+        "<a>
+               <b>
+                 <c>5</c>
+               </b>
+               <other>
+                 <d>6</d>
+               </other>
+            </a>",
+        A {
+            other: vec![Other { d: 6 }],
+        },
+    )]);
+}
+
+// #[test]
+// fn eoz() {
+//     use std::io::Read;
+//     let mut file = std::fs::File::open("Report_test.2.xml").unwrap();
+//     let mut s = String::new();
+//     file.read_to_string(&mut s).unwrap();
+
+//     let _xml_value: Element = from_str(&s).unwrap();
+// }
+
+#[test]
+fn test_parse_unfinished() {
+    test_parse_err::<Simple>(&["<Simple>
+            <c>abc</c>
+            <a/>
+            <b>2</b>
+            <d/>"]);
+}
+
+#[test]
+fn test_things_qc_found() {
+    test_parse_err::<u32>(&["<\u{0}:/"]);
+}
+
+#[test]
+fn futile() {
+    let _ = simple_logger::init();
+    #[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
+    struct Object {
+        id: u8,
+        name: String,
+        x: u8,
+        y: u8,
+        width: u8,
+        height: u8,
+        ellipse: Option<()>,
+    }
+
+    test_parse_ok(&[
+        (
+            r###"
+            <object id="11" name="testEllipse" x="102" y="38" width="21" height="14">
+              <ellipse/>
+            </object>
+            "###,
+            Object {
+                id: 11,
+                name: "testEllipse".to_owned(),
+                x: 102,
+                y: 38,
+                width: 21,
+                height: 14,
+                ellipse: Some(()),
+            },
+        ),
+        (
+            r###"
+            <object id="11" name="testEllipse" x="102" y="38" width="21" height="14">
+            </object>
+            "###,
+            Object {
+                id: 11,
+                name: "testEllipse".to_owned(),
+                x: 102,
+                y: 38,
+                width: 21,
+                height: 14,
+                ellipse: None,
+            },
+        ),
+    ]);
+}
+
+#[test]
+fn futile2() {
+    let _ = simple_logger::init();
+    #[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
+    struct Null;
+
+    #[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(&[
+        (
+            r###"
+            <object>
+              <field/>
+            </object>
+            "###,
+            Object { field: Some(Null) },
+        ),
+        (
+            r###"
+            <object>
+            </object>
+            "###,
+            Object { field: None },
+        ),
+    ]);
+
+    test_parse_ok(&[
+        (
+            r###"
+            <object>
+              <stuff_field/>
+            </object>
+            "###,
+            Stuff {
+                stuff_field: Some(Object { field: None }),
+            },
+        ),
+        (
+            r###"
+            <object>
+              <stuff_field>
+                <field/>
+              </stuff_field>
+            </object>
+            "###,
+            Stuff {
+                stuff_field: Some(Object { field: Some(Null) }),
+            },
+        ),
+        (
+            r###"
+            <object>
+            </object>
+            "###,
+            Stuff { stuff_field: None },
+        ),
+        (
+            r###"
+            <object/>
+            "###,
+            Stuff { stuff_field: None },
+        ),
+    ]);
+}
+
+#[test]
+fn newtype_struct() {
+    #[derive(PartialEq, Debug, Serialize, Deserialize)]
+    struct Wrapper(String);
+
+    test_parse_ok(&[(
+        r###"<wrapper>Content</wrapper>"###,
+        Wrapper("Content".into()),
+    )]);
+}
diff --git a/tests/readme.rs b/tests/readme.rs
new file mode 100644
index 0000000..881d572
--- /dev/null
+++ b/tests/readme.rs
@@ -0,0 +1,6 @@
+extern crate docmatic;
+
+#[test]
+fn test_readme() {
+    docmatic::assert_file("README.md");
+}
diff --git a/tests/round_trip.rs b/tests/round_trip.rs
new file mode 100644
index 0000000..54b3b53
--- /dev/null
+++ b/tests/round_trip.rs
@@ -0,0 +1,110 @@
+#[macro_use]
+extern crate serde_derive;
+extern crate serde;
+extern crate serde_xml_rs;
+
+use serde::Deserialize;
+use serde_xml_rs::{from_str, to_string, EventReader, ParserConfig};
+
+#[derive(Debug, Serialize, Deserialize, PartialEq)]
+struct Item {
+    name: String,
+    source: String,
+}
+
+
+#[derive(Debug, Serialize, Deserialize, PartialEq)]
+enum Node {
+    Boolean(bool),
+    Identifier { value: String, index: u32 },
+    EOF,
+}
+
+#[derive(Debug, Serialize, Deserialize, PartialEq)]
+struct Nodes {
+    #[serde(rename = "$value")]
+    items: Vec<Node>,
+}
+
+
+#[test]
+fn basic_struct() {
+    let src = r#"<Item><name>Banana</name><source>Store</source></Item>"#;
+    let should_be = Item {
+        name: "Banana".to_string(),
+        source: "Store".to_string(),
+    };
+
+    let item: Item = from_str(src).unwrap();
+    assert_eq!(item, should_be);
+
+    let reserialized_item = to_string(&item).unwrap();
+    assert_eq!(src, reserialized_item);
+}
+
+
+#[test]
+#[ignore]
+fn round_trip_list_of_enums() {
+    // Construct some inputs
+    let nodes = Nodes {
+        items: vec![
+            Node::Boolean(true),
+            Node::Identifier {
+                value: "foo".to_string(),
+                index: 5,
+            },
+            Node::EOF,
+        ],
+    };
+
+    let should_be = r#"
+    <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);
+
+    // Then turn it back into a `Nodes` struct and make sure it's the same
+    // as the original
+    let deserialized_nodes: Nodes = from_str(serialized_nodes.as_str()).unwrap();
+    assert_eq!(deserialized_nodes, nodes);
+}
+
+#[test]
+fn whitespace_preserving_config() {
+    // Test a configuration which does not clip whitespace from tags
+
+    let src = r#"
+    <Item>
+        <name>  space banana  </name>
+        <source>   fantasy costco   </source>
+    </Item>"#;
+
+    let item_should_be = Item {
+        name: "  space banana  ".to_string(),
+        source: "   fantasy costco   ".to_string(),
+    };
+    let config = ParserConfig::new()
+        .trim_whitespace(false)
+        .whitespace_to_characters(false);
+    let mut deserializer =
+        serde_xml_rs::Deserializer::new(EventReader::new_with_config(src.as_bytes(), config));
+
+    let item = Item::deserialize(&mut deserializer).unwrap();
+    assert_eq!(item, item_should_be);
+
+    // Space outside values is not preserved.
+    let serialized_should_be =
+        "<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
new file mode 100644
index 0000000..4b8ec86
--- /dev/null
+++ b/tests/test.rs
@@ -0,0 +1,161 @@
+#[macro_use]
+extern crate serde_derive;
+extern crate serde_xml_rs;
+
+extern crate log;
+extern crate simple_logger;
+
+use serde_xml_rs::from_str;
+
+#[derive(Debug, Deserialize, PartialEq)]
+struct Item {
+    name: String,
+    source: String,
+}
+
+#[test]
+fn simple_struct_from_attributes() {
+    let _ = simple_logger::init();
+
+    let s = r##"
+        <item name="hello" source="world.rs" />
+    "##;
+
+    let item: Item = from_str(s).unwrap();
+
+    assert_eq!(
+        item,
+        Item {
+            name: "hello".to_string(),
+            source: "world.rs".to_string(),
+        }
+    );
+}
+
+#[test]
+fn multiple_roots_attributes() {
+    let _ = simple_logger::init();
+
+    let s = r##"
+        <item name="hello" source="world.rs" />
+        <item name="hello" source="world.rs" />
+    "##;
+
+    let item: Vec<Item> = from_str(s).unwrap();
+
+    assert_eq!(
+        item,
+        vec![
+            Item {
+                name: "hello".to_string(),
+                source: "world.rs".to_string(),
+            },
+            Item {
+                name: "hello".to_string(),
+                source: "world.rs".to_string(),
+            },
+        ]
+    );
+}
+
+#[test]
+fn simple_struct_from_attribute_and_child() {
+    let _ = simple_logger::init();
+
+    let s = r##"
+        <item name="hello">
+            <source>world.rs</source>
+        </item>
+    "##;
+
+    let item: Item = from_str(s).unwrap();
+
+    assert_eq!(
+        item,
+        Item {
+            name: "hello".to_string(),
+            source: "world.rs".to_string(),
+        }
+    );
+}
+
+#[derive(Debug, Deserialize, PartialEq)]
+struct Project {
+    name: String,
+
+    #[serde(rename = "item", default)]
+    items: Vec<Item>,
+}
+
+#[test]
+fn nested_collection() {
+    let _ = simple_logger::init();
+
+    let s = r##"
+        <project name="my_project">
+            <item name="hello1" source="world1.rs" />
+            <item name="hello2" source="world2.rs" />
+        </project>
+    "##;
+
+    let project: Project = from_str(s).unwrap();
+
+    assert_eq!(
+        project,
+        Project {
+            name: "my_project".to_string(),
+            items: vec![
+                Item {
+                    name: "hello1".to_string(),
+                    source: "world1.rs".to_string(),
+                },
+                Item {
+                    name: "hello2".to_string(),
+                    source: "world2.rs".to_string(),
+                },
+            ],
+        }
+    );
+}
+
+#[derive(Debug, Deserialize, PartialEq)]
+enum MyEnum {
+    A(String),
+    B { name: String, flag: bool },
+    C,
+}
+
+#[derive(Debug, Deserialize, PartialEq)]
+struct MyEnums {
+    #[serde(rename = "$value")]
+    items: Vec<MyEnum>,
+}
+
+#[test]
+fn collection_of_enums() {
+    let _ = simple_logger::init();
+
+    let s = r##"
+        <enums>
+            <A>test</A>
+            <B name="hello" flag="true" />
+            <C />
+        </enums>
+    "##;
+
+    let project: MyEnums = from_str(s).unwrap();
+
+    assert_eq!(
+        project,
+        MyEnums {
+            items: vec![
+                MyEnum::A("test".to_string()),
+                MyEnum::B {
+                    name: "hello".to_string(),
+                    flag: true,
+                },
+                MyEnum::C,
+            ],
+        }
+    );
+}