Repository: tafia/quick-xml
Pull request #507 (2022-11-09 18:05:41)

Read serde (on master)
this fails and I don't know how to fix:
```
Airtemis:quick-xml sallen$ cargo run --example read_nodes_serde --features="serialize"
   Compiling quick-xml v0.26.0 (/Users/sallen/src/rust/ref/quick-xml)
    Finished dev [unoptimized + debuginfo] target(s) in 1.26s
     Running `target/debug/examples/read_nodes_serde`
[examples/read_nodes_serde.rs:71] "{:?}" = "{:?}"
[examples/read_nodes_serde.rs:71] &config = Config {
    settings: DefaultSettings {
        language: "es",
        greeting: "HELLO",
    },
    translation: [
        Translation {
            tag: "",
            lang: "",
            text: "",
        },
    ],
}
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `1`,
 right: `4`', examples/read_nodes_serde.rs:76:5
```

ultrasaurus: Note: I added Anyhow to I'm not sure what error to return from main().  If I change to:
```
fn main() -> Result<(), quick_xml::Error> {
```

I get:
```
  --> examples/read_nodes_serde.rs:70:39
   |
64 | fn main() -> Result<(), quick_xml::Error> {
   |              ---------------------------- expected `quick_xml::Error` because of this
...
70 |     let config: Config = from_str(XML)?;
   |                                       ^ the trait `From<DeError>` is not implemented for `quick_xml::Error`
   |
```


Patch:
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index a5731a4..4d96b9a 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -14,7 +14,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
     - uses: actions/checkout@v3
-    - uses: dtolnay/rust-toolchain@1.46.0
+    - uses: dtolnay/rust-toolchain@1.52.0
     - run: cargo check
 
   test:
diff --git a/Cargo.toml b/Cargo.toml
index e61fea6..872da6b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "quick-xml"
-version = "0.26.0"
+version = "0.27.1"
 description = "High performance xml reader and writer"
 edition = "2018"
 
@@ -10,7 +10,7 @@ repository = "https://github.com/tafia/quick-xml"
 keywords = ["xml", "serde", "parser", "writer", "html"]
 categories = ["asynchronous", "encoding", "parsing", "parser-implementations"]
 license = "MIT"
-rust-version = "1.46"
+rust-version = "1.52"
 include = ["src/*", "LICENSE-MIT.md", "README.md"]
 
 [dependencies]
@@ -164,8 +164,21 @@ escape-html = []
 ## [`Deserializer`]: crate::de::Deserializer
 overlapped-lists = []
 
-## Enables support for [`serde`] serialization and deserialization
-serialize = ["serde"]
+## Enables serialization of some types using [`serde`]. Probably your rarely will
+## need this feature enabled.
+##
+## This feature does NOT provide XML serializer or deserializer. You should use
+## the `serialize` feature for that instead.
+# Cannot name "serde" to avoid clash with dependency.
+# "dep:" prefix only avalible from Rust 1.60
+serde-types = ["serde/derive"]
+
+## Enables support for [`serde`] serialization and deserialization. When this
+## feature is enabled, quick-xml provides serializer and deserializer for XML.
+##
+## This feature does NOT enables serializaton of the types inside quick-xml.
+## If you need that, use the `serde-types` feature.
+serialize = ["serde"] # "dep:" prefix only avalible from Rust 1.60
 
 [package.metadata.docs.rs]
 # document all features
@@ -199,7 +212,16 @@ name = "serde-migrated"
 required-features = ["serialize"]
 path = "tests/serde-migrated.rs"
 
+[[test]]
+name = "serde-issues"
+required-features = ["serialize"]
+path = "tests/serde-issues.rs"
+
 [[test]]
 name = "async-tokio"
 required-features = ["async-tokio"]
 path = "tests/async-tokio.rs"
+
+[[example]]
+name = "read_nodes_serde"
+required-features = ["serialize"]
diff --git a/Changelog.md b/Changelog.md
index 0e66701..18a8d86 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -12,6 +12,43 @@
 
 ### New Features
 
+- [#541]: Deserialize specially named `$text` enum variant in [externally tagged]
+  enums from textual content
+
+### Bug Fixes
+
+- [#537]: Restore ability to deserialize attributes that represents XML namespace
+  mappings (`xmlns:xxx`) that was broken since [#490]
+- [#510]: Fix an error of deserialization of `Option<T>` fields where `T` is some
+  sequence type (for example, `Vec` or tuple)
+
+### Misc Changes
+
+[externally tagged]: https://serde.rs/enum-representations.html#externally-tagged
+[#490]: https://github.com/tafia/quick-xml/pull/490
+[#510]: https://github.com/tafia/quick-xml/issues/510
+[#537]: https://github.com/tafia/quick-xml/issues/537
+[#541]: https://github.com/tafia/quick-xml/pull/541
+
+## 0.27.1 -- 2022-12-28
+
+### Bug Fixes
+
+- [#530]: Fix an infinite loop leading to unbounded memory consumption that occurs when
+  skipping events on malformed XML with the `overlapped-lists` feature active.
+- [#530]: Fix an error in the `Deserializer::read_to_end` when `overlapped-lists`
+  feature is active and malformed XML is parsed
+
+[#530]: https://github.com/tafia/quick-xml/pull/530
+
+## 0.27.0 -- 2022-12-25
+
+### New Features
+
+- [#521]: Implement `Clone` for all error types. This required changing `Error::Io` to contain
+  `Arc<std::io::Error>` instead of `std::io::Error` since `std::io::Error` does not implement
+  `Clone`.
+
 ### Bug Fixes
 
 - [#490]: Ensure that serialization of map keys always produces valid XML names.
@@ -26,6 +63,18 @@
   <B/>
   <C/>
   ```
+- [#514]: Fix wrong reporting `Error::EndEventMismatch` after disabling and enabling
+  `.check_end_names`
+- [#517]: Fix swapped codes for `\r` and `\n` characters when escaping them
+- [#523]: Fix incorrect skipping text and CDATA content before any map-like structures
+  in serde deserializer, like
+  ```xml
+  unwanted text<struct>...</struct>
+  ```
+- [#523]: Fix incorrect handling of `xs:list`s with encoded spaces: they still
+  act as delimiters, which is confirmed also by mature XmlBeans Java library
+- [#473]: Fix a hidden requirement to enable serde's `derive` feature to get
+  quick-xml's `serialize` feature for `edition = 2021` or `resolver = 2` crates
 
 ### Misc Changes
 
@@ -50,9 +99,18 @@
     content of the field, text or markup
 
   Refer to [documentation] for details.
+- [#521]: MSRV bumped to 1.52.
+- [#473]: `serde` feature that used to make some types serializable, renamed to `serde-types`
+- [#528]: Added documentation for XML to `serde` mapping
 
+[#473]: https://github.com/tafia/quick-xml/issues/473
 [#490]: https://github.com/tafia/quick-xml/pull/490
 [#500]: https://github.com/tafia/quick-xml/issues/500
+[#514]: https://github.com/tafia/quick-xml/issues/514
+[#517]: https://github.com/tafia/quick-xml/issues/517
+[#521]: https://github.com/tafia/quick-xml/pull/521
+[#523]: https://github.com/tafia/quick-xml/pull/523
+[#528]: https://github.com/tafia/quick-xml/pull/528
 [XML name]: https://www.w3.org/TR/xml11/#NT-Name
 [documentation]: https://docs.rs/quick-xml/0.27.0/quick_xml/de/index.html#difference-between-text-and-value-special-names
 
diff --git a/README.md b/README.md
index 2846e14..7de9dbb 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
 [![Crate](https://img.shields.io/crates/v/quick-xml.svg)](https://crates.io/crates/quick-xml)
 [![docs.rs](https://docs.rs/quick-xml/badge.svg)](https://docs.rs/quick-xml)
 [![codecov](https://img.shields.io/codecov/c/github/tafia/quick-xml)](https://codecov.io/gh/tafia/quick-xml)
-[![MSRV](https://img.shields.io/badge/rustc-1.46.0+-ab6000.svg)](https://blog.rust-lang.org/2020/08/27/Rust-1.46.0.html)
+[![MSRV](https://img.shields.io/badge/rustc-1.52.0+-ab6000.svg)](https://blog.rust-lang.org/2021/05/06/Rust-1.52.0.html)
 
 High performance xml pull reader/writer.
 
@@ -110,6 +110,9 @@ assert_eq!(result, expected.as_bytes());
 ## Serde
 
 When using the `serialize` feature, quick-xml can be used with serde's `Serialize`/`Deserialize` traits.
+The mapping between XML and Rust types, and in particular the syntax that allows you to specify the
+distinction between *elements* and *attributes*, is described in detail in the documentation
+for [deserialization](https://docs.rs/quick-xml/latest/quick_xml/de/).
 
 ### Credits
 
@@ -124,6 +127,7 @@ you can use either the special name `$text`, or the special name `$value`:
 
 ```rust,ignore
 struct Foo {
+    #[serde(rename = "@abc")]
     pub abc: String,
     #[serde(rename = "$text")]
     pub body: String,
diff --git a/examples/custom_entities.rs b/examples/custom_entities.rs
index 1405f3d..99c59c1 100644
--- a/examples/custom_entities.rs
+++ b/examples/custom_entities.rs
@@ -40,8 +40,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
                     );
                 }
             }
-            Ok(Event::Start(ref e)) => match e.name().as_ref() {
-                b"test" => {
+            Ok(Event::Start(ref e)) => {
+                if let b"test" = e.name().as_ref() {
                     let attributes = e
                         .attributes()
                         .map(|a| {
@@ -55,8 +55,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
                         .collect::<Vec<_>>();
                     println!("attributes values: {:?}", attributes);
                 }
-                _ => (),
-            },
+            }
             Ok(Event::Text(ref e)) => {
                 println!(
                     "text value: {}",
diff --git a/examples/nested_readers.rs b/examples/nested_readers.rs
index 3b30776..e00a175 100644
--- a/examples/nested_readers.rs
+++ b/examples/nested_readers.rs
@@ -21,8 +21,8 @@ fn main() -> Result<(), quick_xml::Error> {
     let mut found_tables = Vec::new();
     loop {
         match reader.read_event_into(&mut buf)? {
-            Event::Start(element) => match element.name().as_ref() {
-                b"w:tbl" => {
+            Event::Start(element) => {
+                if let b"w:tbl" = element.name().as_ref() {
                     count += 1;
                     let mut stats = TableStat {
                         index: count,
@@ -57,8 +57,7 @@ fn main() -> Result<(), quick_xml::Error> {
                         }
                     }
                 }
-                _ => {}
-            },
+            }
             Event::Eof => break,
             _ => {}
         }
diff --git a/examples/read_nodes.rs b/examples/read_nodes.rs
new file mode 100644
index 0000000..e7ea77e
--- /dev/null
+++ b/examples/read_nodes.rs
@@ -0,0 +1,150 @@
+// example that separates logic for reading different top-level nodes of xml tree
+// Note: for this specific data set using serde feature would simplify
+//       this simple data is purely to make it easier to understand the code
+
+use quick_xml::events::{BytesStart, Event};
+use quick_xml::name::QName;
+use quick_xml::reader::Reader;
+use std::borrow::Cow;
+use std::collections::HashMap;
+use std::convert::Infallible;
+use std::str;
+
+const XML: &str = r#"
+<?xml version="1.0" encoding="utf-8"?>
+  <DefaultSettings Language="es" Greeting="HELLO"/>
+  <Localization>
+    <Translation Tag="HELLO" Language="ja">
+      <Text>こんにちは</Text>
+    </Translation>
+    <Translation Tag="BYE" Language="ja">
+      <Text>さようなら</Text>
+    </Translation>
+    <Translation Tag="HELLO" Language="es">
+      <Text>Hola</Text>
+    </Translation>
+    <Translation Tag="BYE" Language="es">
+      <Text>Adiós</Text>
+    </Translation>
+  </Localization>
+"#;
+
+#[derive(Debug)]
+struct Translation {
+    tag: String,
+    lang: String,
+    text: String,
+}
+
+impl Translation {
+    fn new_from_element(
+        reader: &mut Reader<&[u8]>,
+        element: BytesStart,
+    ) -> Result<Translation, quick_xml::Error> {
+        let mut tag = Cow::Borrowed("");
+        let mut lang = Cow::Borrowed("");
+
+        for attr_result in element.attributes() {
+            let a = attr_result?;
+            match a.key.as_ref() {
+                b"Language" => lang = a.decode_and_unescape_value(reader)?,
+                b"Tag" => tag = a.decode_and_unescape_value(reader)?,
+                _ => (),
+            }
+        }
+        let mut element_buf = Vec::new();
+        let event = reader.read_event_into(&mut element_buf)?;
+
+        if let Event::Start(ref e) = event {
+            let name = e.name();
+            if name == QName(b"Text") {
+                // note: `read_text` does not support content as CDATA
+                let text_content = reader.read_text(e.name())?;
+                Ok(Translation {
+                    tag: tag.into(),
+                    lang: lang.into(),
+                    text: text_content.into(),
+                })
+            } else {
+                dbg!("Expected Event::Start for Text, got: {:?}", &event);
+                let name_string = reader.decoder().decode(name.as_ref())?;
+                Err(quick_xml::Error::UnexpectedToken(name_string.into()))
+            }
+        } else {
+            let event_string = format!("{:?}", event);
+            Err(quick_xml::Error::UnexpectedToken(event_string))
+        }
+    }
+}
+
+fn main() -> Result<(), quick_xml::Error> {
+    // In a real-world use case, Settings would likely be a struct
+    // HashMap here is just to make the sample code short
+    let mut settings: HashMap<String, String>;
+    let mut translations: Vec<Translation> = Vec::new();
+
+    let mut reader = Reader::from_str(XML);
+    reader.trim_text(true);
+
+    // == Handling empty elements ==
+    // To simply our processing code
+    // we want the same events for empty elements, like:
+    //   <DefaultSettings Language="es" Greeting="HELLO"/>
+    //   <Text/>
+    reader.expand_empty_elements(true);
+    let mut buf = Vec::new();
+
+    loop {
+        let event = reader.read_event_into(&mut buf)?;
+
+        match event {
+            Event::Start(element) => match element.name().as_ref() {
+                b"DefaultSettings" => {
+                    // Note: real app would handle errors with good defaults or halt program with nice message
+                    // This illustrates decoding an attribute's key and value with error handling
+                    settings = element
+                        .attributes()
+                        .map(|attr_result| {
+                            match attr_result {
+                                Ok(a) => {
+                                    let key = reader.decoder().decode(a.key.local_name().as_ref())
+                                        .or_else(|err| {
+                                            dbg!("unable to read key in DefaultSettings attribute {:?}, utf8 error {:?}", &a, err);
+                                            Ok::<Cow<'_, str>, Infallible>(std::borrow::Cow::from(""))
+                                        })
+                                        .unwrap().to_string();
+                                    let value = a.decode_and_unescape_value(&reader).or_else(|err| {
+                                            dbg!("unable to read key in DefaultSettings attribute {:?}, utf8 error {:?}", &a, err);
+                                            Ok::<Cow<'_, str>, Infallible>(std::borrow::Cow::from(""))
+                                    }).unwrap().to_string();
+                                    (key, value)
+                                },
+                                Err(err) => {
+                                     dbg!("unable to read key in DefaultSettings, err = {:?}", err);
+                                    (String::new(), String::new())
+                                }
+                            }
+                        })
+                        .collect();
+                    assert_eq!(settings["Language"], "es");
+                    assert_eq!(settings["Greeting"], "HELLO");
+                    reader.read_to_end(element.name())?;
+                }
+                b"Translation" => {
+                    translations.push(Translation::new_from_element(&mut reader, element)?);
+                }
+                _ => (),
+            },
+
+            Event::Eof => break, // exits the loop when reaching end of file
+            _ => (),             // There are `Event` types not considered here
+        }
+    }
+    dbg!("{:?}", &translations);
+    assert_eq!(translations.len(), 4);
+    assert_eq!(translations[2].tag, "HELLO");
+    assert_eq!(translations[2].text, "Hola");
+    assert_eq!(translations[2].lang, "es");
+
+    Ok(())
+}
diff --git a/examples/read_nodes_serde.rs b/examples/read_nodes_serde.rs
new file mode 100644
index 0000000..3c11116
--- /dev/null
+++ b/examples/read_nodes_serde.rs
@@ -0,0 +1,86 @@
+// note: to use serde, the feature needs to be enabled
+// run example with:
+//    cargo run --example read_nodes_serde --features="serialize"
+
+use quick_xml::de::from_str;
+use serde::Deserialize;
+
+#[derive(Debug, PartialEq, Default, Deserialize)]
+#[serde(default)]
+struct Translation {
+    #[serde(rename = "@Tag")]
+    tag: String,
+    #[serde(rename = "@Language")]
+    lang: String,
+    #[serde(rename = "$text")]
+    text: String,
+}
+
+#[derive(Debug, PartialEq, Default, Deserialize)]
+#[serde(default)]
+struct DefaultSettings {
+    #[serde(rename = "@Language")]
+    language: String,
+    #[serde(rename = "@Greeting")]
+    greeting: String,
+}
+
+#[derive(Debug, PartialEq, Default, Deserialize)]
+#[serde(default, rename_all = "PascalCase")]
+struct Config {
+    #[serde(rename = "DefaultSettings")]
+    settings: DefaultSettings,
+    localization: Localization,
+}
+#[derive(Debug, PartialEq, Default, Deserialize)]
+#[serde(rename_all = "PascalCase")]
+struct Localization {
+    translation: Vec<Translation>,
+}
+
+const XML: &str = r#"
+<?xml version="1.0" encoding="utf-8"?>
+<Config>
+  <DefaultSettings Language="es" Greeting="HELLO"/>
+  <Localization>
+    <Translation Tag="HELLO" Language="ja">
+      こんにちは
+    </Translation>
+    <Translation Tag="BYE" Language="ja">
+      さようなら
+    </Translation>
+    <Translation Tag="HELLO" Language="es">
+      Hola
+    </Translation>
+    <Translation Tag="BYE" Language="es">
+      Adiós
+    </Translation>
+  </Localization>
+</Config>
+"#;
+
+const ONE_TRANSLATION_XML: &str = r#"
+    <Translation Tag="HELLO" Language="ja">
+      こんにちは
+    </Translation>
+"#;
+
+fn main() -> Result<(), quick_xml::DeError> {
+    let t: Translation = from_str(ONE_TRANSLATION_XML)?;
+    assert_eq!(t.tag, "HELLO");
+    assert_eq!(t.lang, "ja");
+    assert_eq!(t.text, "こんにちは");
+
+    let config: Config = from_str(XML)?;
+    dbg!("{:?}", &config);
+
+    assert_eq!(config.settings.language, "es");
+    assert_eq!(config.settings.greeting, "HELLO");
+
+    let translations = config.localization.translation;
+    assert_eq!(translations.len(), 4);
+    assert_eq!(translations[2].tag, "HELLO");
+    assert_eq!(translations[2].text, "Hola");
+    assert_eq!(translations[2].lang, "es");
+    Ok(())
+}
diff --git a/src/de/escape.rs b/src/de/escape.rs
deleted file mode 100644
index 446b1d2..0000000
--- a/src/de/escape.rs
+++ /dev/null
@@ -1,223 +0,0 @@
-//! Serde `Deserializer` module
-
-use crate::de::deserialize_bool;
-use crate::encoding::Decoder;
-use crate::errors::serialize::DeError;
-use crate::escape::unescape;
-use serde::de::{DeserializeSeed, EnumAccess, VariantAccess, Visitor};
-use serde::{self, forward_to_deserialize_any, serde_if_integer128};
-use std::borrow::Cow;
-
-/// A deserializer for a xml escaped and encoded value
-///
-/// # Note
-///
-/// Escaping the value is actually not always necessary, for instance
-/// when converting to float, we don't expect any escapable character
-/// anyway
-#[derive(Clone, Debug)]
-pub struct EscapedDeserializer<'a> {
-    decoder: Decoder,
-    /// Possible escaped value of text/CDATA or attribute value
-    escaped_value: Cow<'a, [u8]>,
-    /// If `true`, value requires unescaping before using
-    escaped: bool,
-}
-
-impl<'a> EscapedDeserializer<'a> {
-    pub fn new(escaped_value: Cow<'a, [u8]>, decoder: Decoder, escaped: bool) -> Self {
-        EscapedDeserializer {
-            decoder,
-            escaped_value,
-            escaped,
-        }
-    }
-}
-
-macro_rules! deserialize_num {
-    ($method:ident, $visit:ident) => {
-        fn $method<V>(self, visitor: V) -> Result<V::Value, Self::Error>
-        where
-            V: Visitor<'de>,
-        {
-            let value = self.decoder.decode(self.escaped_value.as_ref())?.parse()?;
-
-            visitor.$visit(value)
-        }
-    };
-}
-
-impl<'de, 'a> serde::Deserializer<'de> for EscapedDeserializer<'a> {
-    type Error = DeError;
-
-    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
-    where
-        V: Visitor<'de>,
-    {
-        self.deserialize_str(visitor)
-    }
-
-    fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
-    where
-        V: Visitor<'de>,
-    {
-        let decoded = self.decoder.decode(&self.escaped_value)?;
-        if self.escaped {
-            match unescape(&decoded)? {
-                Cow::Borrowed(s) => visitor.visit_str(s),
-                Cow::Owned(s) => visitor.visit_string(s),
-            }
-        } else {
-            match decoded {
-                Cow::Borrowed(s) => visitor.visit_str(s),
-                Cow::Owned(s) => visitor.visit_string(s),
-            }
-        }
-    }
-
-    /// Returns [`DeError::Unsupported`]
-    fn deserialize_bytes<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
-    where
-        V: Visitor<'de>,
-    {
-        Err(DeError::Unsupported(
-            "binary data content is not supported by XML format".into(),
-        ))
-    }
-
-    /// Forwards deserialization to the [`deserialize_bytes`](#method.deserialize_bytes)
-    fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
-    where
-        V: Visitor<'de>,
-    {
-        self.deserialize_bytes(visitor)
-    }
-
-    fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
-    where
-        V: Visitor<'de>,
-    {
-        self.deserialize_str(visitor)
-    }
-
-    fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
-    where
-        V: Visitor<'de>,
-    {
-        deserialize_bool(self.escaped_value.as_ref(), self.decoder, visitor)
-    }
-
-    fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
-    where
-        V: Visitor<'de>,
-    {
-        self.deserialize_str(visitor)
-    }
-
-    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
-    where
-        V: Visitor<'de>,
-    {
-        visitor.visit_unit()
-    }
-
-    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
-    where
-        V: Visitor<'de>,
-    {
-        if self.escaped_value.as_ref().is_empty() {
-            visitor.visit_none()
-        } else {
-            visitor.visit_some(self)
-        }
-    }
-
-    fn deserialize_enum<V>(
-        self,
-        _name: &str,
-        _variants: &'static [&'static str],
-        visitor: V,
-    ) -> Result<V::Value, Self::Error>
-    where
-        V: Visitor<'de>,
-    {
-        visitor.visit_enum(self)
-    }
-
-    fn deserialize_newtype_struct<V>(
-        self,
-        _name: &'static str,
-        visitor: V,
-    ) -> Result<V::Value, Self::Error>
-    where
-        V: Visitor<'de>,
-    {
-        visitor.visit_newtype_struct(self)
-    }
-
-    deserialize_num!(deserialize_i64, visit_i64);
-    deserialize_num!(deserialize_i32, visit_i32);
-    deserialize_num!(deserialize_i16, visit_i16);
-    deserialize_num!(deserialize_i8, visit_i8);
-    deserialize_num!(deserialize_u64, visit_u64);
-    deserialize_num!(deserialize_u32, visit_u32);
-    deserialize_num!(deserialize_u16, visit_u16);
-    deserialize_num!(deserialize_u8, visit_u8);
-    deserialize_num!(deserialize_f64, visit_f64);
-    deserialize_num!(deserialize_f32, visit_f32);
-
-    serde_if_integer128! {
-        deserialize_num!(deserialize_i128, visit_i128);
-        deserialize_num!(deserialize_u128, visit_u128);
-    }
-
-    forward_to_deserialize_any! {
-        unit_struct seq tuple tuple_struct map struct identifier ignored_any
-    }
-}
-
-impl<'de, 'a> EnumAccess<'de> for EscapedDeserializer<'a> {
-    type Error = DeError;
-    type Variant = Self;
-
-    fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self), Self::Error>
-    where
-        V: DeserializeSeed<'de>,
-    {
-        let name = seed.deserialize(self.clone())?;
-        Ok((name, self))
-    }
-}
-
-impl<'de, 'a> VariantAccess<'de> for EscapedDeserializer<'a> {
-    type Error = DeError;
-
-    fn unit_variant(self) -> Result<(), Self::Error> {
-        Ok(())
-    }
-
-    fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
-    where
-        T: DeserializeSeed<'de>,
-    {
-        seed.deserialize(self)
-    }
-
-    fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, Self::Error>
-    where
-        V: Visitor<'de>,
-    {
-        unimplemented!()
-    }
-
-    fn struct_variant<V>(
-        self,
-        _fields: &'static [&'static str],
-        _visitor: V,
-    ) -> Result<V::Value, Self::Error>
-    where
-        V: Visitor<'de>,
-    {
-        unimplemented!()
-    }
-}
diff --git a/src/de/key.rs b/src/de/key.rs
index b4905d1..a3f182e 100644
--- a/src/de/key.rs
+++ b/src/de/key.rs
@@ -35,9 +35,11 @@ fn decode_name<'n>(name: QName<'n>, decoder: Decoder) -> Result<Cow<'n, str>, De
 /// Converts a name to an identifier string using the following rules:
 ///
 /// - if it is an [`attribute`] name, put `@` in front of the identifier
+/// - if it is a namespace binding (`xmlns` or `xmlns:xxx`) put the decoded name
+///   to the identifier
 /// - put the decoded [`local_name()`] of a name to the identifier
 ///
-/// The final identifier looks like `[@]local_name`
+/// The final identifier looks like `[@]local_name`, or `@xmlns`, or `@xmlns:binding`
 /// (where `[]` means optional element).
 ///
 /// The deserializer also supports deserializing names as other primitive types:
@@ -72,10 +74,16 @@ pub struct QNameDeserializer<'d> {
 impl<'d> QNameDeserializer<'d> {
     /// Creates deserializer from name of an attribute
     pub fn from_attr(name: QName<'d>, decoder: Decoder) -> Result<Self, DeError> {
-        let local = decode_name(name, decoder)?;
+        // https://github.com/tafia/quick-xml/issues/537
+        // Namespace bindings (xmlns:xxx) map to `@xmlns:xxx` instead of `@xxx`
+        let field = if name.as_namespace_binding().is_some() {
+            decoder.decode(name.into_inner())?
+        } else {
+            decode_name(name, decoder)?
+        };
 
         Ok(Self {
-            name: Cow::Owned(format!("@{local}")),
+            name: Cow::Owned(format!("@{field}")),
         })
     }
 
diff --git a/src/de/map.rs b/src/de/map.rs
index b5c27f7..e0e3f69 100644
--- a/src/de/map.rs
+++ b/src/de/map.rs
@@ -311,15 +311,13 @@ where
             // of that events)
             // This case are checked by "xml_schema_lists::element" tests in tests/serde-de.rs
             ValueSource::Text => match self.de.next()? {
-                DeEvent::Text(e) => seed.deserialize(SimpleTypeDeserializer::from_cow(
-                    e.into_inner(),
-                    true,
-                    self.de.reader.decoder(),
+                DeEvent::Text(e) => seed.deserialize(SimpleTypeDeserializer::from_text_content(
+                    // Comment to prevent auto-formatting
+                    e.decode(true)?,
                 )),
-                DeEvent::CData(e) => seed.deserialize(SimpleTypeDeserializer::from_cow(
-                    e.into_inner(),
-                    false,
-                    self.de.reader.decoder(),
+                DeEvent::CData(e) => seed.deserialize(SimpleTypeDeserializer::from_text_content(
+                    // Comment to prevent auto-formatting
+                    e.decode()?,
                 )),
                 // SAFETY: We set `Text` only when we seen `Text` or `CData`
                 _ => unreachable!(),
@@ -381,7 +379,7 @@ where
     /// Access to the map that created this deserializer. Gives access to the
     /// context, such as list of fields, that current map known about.
     map: &'m mut MapAccess<'de, 'a, R>,
-    /// Determines, should [`Deserializer::next_text_impl()`] expand the second
+    /// Determines, should [`Deserializer::read_string_impl()`] expand the second
     /// level of tags or not.
     ///
     /// If this field is `true`, we process the following XML shape:
@@ -463,10 +461,14 @@ impl<'de, 'a, 'm, R> MapValueDeserializer<'de, 'a, 'm, R>
 where
     R: XmlRead<'de>,
 {
-    /// Returns a text event, used inside [`deserialize_primitives!()`]
+    /// Returns a next string as concatenated content of consequent [`Text`] and
+    /// [`CData`] events, used inside [`deserialize_primitives!()`].
+    ///
+    /// [`Text`]: DeEvent::Text
+    /// [`CData`]: DeEvent::CData
     #[inline]
-    fn next_text(&mut self, unescape: bool) -> Result<Cow<'de, str>, DeError> {
-        self.map.de.next_text_impl(unescape, self.allow_start)
+    fn read_string(&mut self, unescape: bool) -> Result<Cow<'de, str>, DeError> {
+        self.map.de.read_string_impl(unescape, self.allow_start)
     }
 }
 
@@ -478,10 +480,7 @@ where
 
     deserialize_primitives!(mut);
 
-    forward!(deserialize_option);
     forward!(deserialize_unit);
-    forward!(deserialize_unit_struct(name: &'static str));
-    forward!(deserialize_newtype_struct(name: &'static str));
 
     forward!(deserialize_map);
     forward!(deserialize_struct(
@@ -497,27 +496,23 @@ where
     forward!(deserialize_any);
     forward!(deserialize_ignored_any);
 
-    /// Tuple representation is the same as [sequences](#method.deserialize_seq).
-    fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, DeError>
+    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, DeError>
     where
         V: Visitor<'de>,
     {
-        self.deserialize_seq(visitor)
-    }
-
-    /// Named tuple representation is the same as [unnamed tuples](#method.deserialize_tuple).
-    fn deserialize_tuple_struct<V>(
-        self,
-        _name: &'static str,
-        len: usize,
-        visitor: V,
-    ) -> Result<V::Value, DeError>
-    where
-        V: Visitor<'de>,
-    {
-        self.deserialize_tuple(len, visitor)
+        deserialize_option!(self.map.de, self, visitor)
     }
 
+    /// Deserializes each `<tag>` in
+    /// ```xml
+    /// <any-tag>
+    ///   <tag>...</tag>
+    ///   <tag>...</tag>
+    ///   <tag>...</tag>
+    /// </any-tag>
+    /// ```
+    /// as a sequence item, where `<any-tag>` represents a Map in a [`Self::map`],
+    /// and a `<tag>` is a sequential field of that map.
     fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
     where
         V: Visitor<'de>,
@@ -619,7 +614,25 @@ impl<'de> TagFilter<'de> {
 
 /// An accessor to sequence elements forming a value for struct field.
 /// Technically, this sequence is flattened out into structure and sequence
-/// elements are overlapped with other fields of a structure
+/// elements are overlapped with other fields of a structure. Each call to
+/// [`Self::next_element_seed`] consumes a next sub-tree or consequent list
+/// of [`Text`] and [`CData`] events.
+///
+/// ```xml
+/// <>
+///   ...
+///   <item>The is the one item</item>
+///   This is <![CDATA[one another]]> item<!-- even when--> it splitted by comments
+///   <tag>...and that is the third!</tag>
+///   ...
+/// </>
+/// ```
+///
+/// Depending on [`Self::filter`], only some of that possible constructs would be
+/// an element.
+///
+/// [`Text`]: DeEvent::Text
+/// [`CData`]: DeEvent::CData
 struct MapValueSeqAccess<'de, 'a, 'm, R>
 where
     R: XmlRead<'de>,
@@ -686,7 +699,7 @@ where
 
                 // Start(tag), Text, CData
                 _ => seed
-                    .deserialize(SeqValueDeserializer { map: self.map })
+                    .deserialize(SeqItemDeserializer { map: self.map })
                     .map(Some),
             };
         }
@@ -695,8 +708,8 @@ where
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 
-/// A deserializer for a value of sequence.
-struct SeqValueDeserializer<'de, 'a, 'm, R>
+/// A deserializer for a single item of a sequence.
+struct SeqItemDeserializer<'de, 'a, 'm, R>
 where
     R: XmlRead<'de>,
 {
@@ -705,18 +718,22 @@ where
     map: &'m mut MapAccess<'de, 'a, R>,
 }
 
-impl<'de, 'a, 'm, R> SeqValueDeserializer<'de, 'a, 'm, R>
+impl<'de, 'a, 'm, R> SeqItemDeserializer<'de, 'a, 'm, R>
 where
     R: XmlRead<'de>,
 {
-    /// Returns a text event, used inside [`deserialize_primitives!()`]
+    /// Returns a next string as concatenated content of consequent [`Text`] and
+    /// [`CData`] events, used inside [`deserialize_primitives!()`].
+    ///
+    /// [`Text`]: DeEvent::Text
+    /// [`CData`]: DeEvent::CData
     #[inline]
-    fn next_text(&mut self, unescape: bool) -> Result<Cow<'de, str>, DeError> {
-        self.map.de.next_text_impl(unescape, true)
+    fn read_string(&mut self, unescape: bool) -> Result<Cow<'de, str>, DeError> {
+        self.map.de.read_string_impl(unescape, true)
     }
 }
 
-impl<'de, 'a, 'm, R> de::Deserializer<'de> for SeqValueDeserializer<'de, 'a, 'm, R>
+impl<'de, 'a, 'm, R> de::Deserializer<'de> for SeqItemDeserializer<'de, 'a, 'm, R>
 where
     R: XmlRead<'de>,
 {
@@ -724,10 +741,7 @@ where
 
     deserialize_primitives!(mut);
 
-    forward!(deserialize_option);
     forward!(deserialize_unit);
-    forward!(deserialize_unit_struct(name: &'static str));
-    forward!(deserialize_newtype_struct(name: &'static str));
 
     forward!(deserialize_map);
     forward!(deserialize_struct(
@@ -743,43 +757,38 @@ where
     forward!(deserialize_any);
     forward!(deserialize_ignored_any);
 
-    /// Representation of tuples the same as [sequences](#method.deserialize_seq).
-    fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, DeError>
+    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, DeError>
     where
         V: Visitor<'de>,
     {
-        self.deserialize_seq(visitor)
-    }
-
-    /// Representation of named tuples the same as [unnamed tuples](#method.deserialize_tuple).
-    fn deserialize_tuple_struct<V>(
-        self,
-        _name: &'static str,
-        len: usize,
-        visitor: V,
-    ) -> Result<V::Value, DeError>
-    where
-        V: Visitor<'de>,
-    {
-        self.deserialize_tuple(len, visitor)
+        deserialize_option!(self.map.de, self, visitor)
     }
 
+    /// This method deserializes a sequence inside of element that itself is a
+    /// sequence element:
+    ///
+    /// ```xml
+    /// <>
+    ///   ...
+    ///   <self>inner sequence</self>
+    ///   <self>inner sequence</self>
+    ///   <self>inner sequence</self>
+    ///   ...
+    /// </>
+    /// ```
     fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
     where
         V: Visitor<'de>,
     {
         match self.map.de.next()? {
-            DeEvent::Text(e) => SimpleTypeDeserializer::from_cow(
-                // Comment to prevent auto-formatting and keep Text and Cdata similar
-                e.into_inner(),
-                true,
-                self.map.de.reader.decoder(),
+            DeEvent::Text(e) => SimpleTypeDeserializer::from_text_content(
+                // Comment to prevent auto-formatting
+                e.decode(true)?,
             )
             .deserialize_seq(visitor),
-            DeEvent::CData(e) => SimpleTypeDeserializer::from_cow(
-                e.into_inner(),
-                false,
-                self.map.de.reader.decoder(),
+            DeEvent::CData(e) => SimpleTypeDeserializer::from_text_content(
+                // Comment to prevent auto-formatting
+                e.decode()?,
             )
             .deserialize_seq(visitor),
             // This is a sequence element. We cannot treat it as another flatten
@@ -787,16 +796,14 @@ where
             // it to `xs:simpleType` implementation
             DeEvent::Start(e) => {
                 let value = match self.map.de.next()? {
-                    DeEvent::Text(e) => SimpleTypeDeserializer::from_cow(
-                        e.into_inner(),
-                        true,
-                        self.map.de.reader.decoder(),
+                    DeEvent::Text(e) => SimpleTypeDeserializer::from_text_content(
+                        // Comment to prevent auto-formatting
+                        e.decode(true)?,
                     )
                     .deserialize_seq(visitor),
-                    DeEvent::CData(e) => SimpleTypeDeserializer::from_cow(
-                        e.into_inner(),
-                        false,
-                        self.map.de.reader.decoder(),
+                    DeEvent::CData(e) => SimpleTypeDeserializer::from_text_content(
+                        // Comment to prevent auto-formatting
+                        e.decode()?,
                     )
                     .deserialize_seq(visitor),
                     e => Err(DeError::Unsupported(
diff --git a/src/de/mod.rs b/src/de/mod.rs
index e4efcba..03b6648 100644
--- a/src/de/mod.rs
+++ b/src/de/mod.rs
@@ -1,6 +1,1394 @@
-//! Serde `Deserializer` module
+//! Serde `Deserializer` module.
 //!
-//! # Difference between `$text` and `$value` special names
+//! Due to the complexity of the XML standard and the fact that serde was developed
+//! with JSON in mind, not all serde concepts apply smoothly to XML. This leads to
+//! that fact that some XML concepts are inexpressible in terms of serde derives
+//! and may require manual deserialization.
+//!
+//! The most notable restriction is the ability to distinguish between _elements_
+//! and _attributes_, as no other format used by serde has such a conception.
+//!
+//! Due to that the mapping is performed in a best effort manner.
+//!
+//!
+//!
+//! Table of Contents
+//! =================
+//! - [Mapping XML to Rust types](#mapping-xml-to-rust-types)
+//!   - [Optional attributes and elements](#optional-attributes-and-elements)
+//!   - [Choices (`xs:choice` XML Schema type)](#choices-xschoice-xml-schema-type)
+//!   - [Sequences (`xs:all` and `xs:sequence` XML Schema types)](#sequences-xsall-and-xssequence-xml-schema-types)
+//! - [Composition Rules](#composition-rules)
+//! - [Difference between `$text` and `$value` special names](#difference-between-text-and-value-special-names)
+//!   - [`$text`](#text)
+//!   - [`$value`](#value)
+//!     - [Primitives and sequences of primitives](#primitives-and-sequences-of-primitives)
+//!     - [Structs and sequences of structs](#structs-and-sequences-of-structs)
+//!     - [Enums and sequences of enums](#enums-and-sequences-of-enums)
+//! - [Frequently Used Patterns](#frequently-used-patterns)
+//!   - [`<element>` lists](#element-lists)
+//!
+//!
+//!
+//! Mapping XML to Rust types
+//! =========================
+//!
+//! Type names are never considered when deserializing, so you can name your
+//! types as you wish. Other general rules:
+//! - `struct` field name could be represented in XML only as an attribute name
+//!   or an element name;
+//! - `enum` variant name could be represented in XML only as an attribute name
+//!   or an element name;
+//! - the unit struct, unit type `()` and unit enum variant can be deserialized
+//!   from any valid XML content:
+//!   - attribute and element names;
+//!   - attribute and element values;
+//!   - text or CDATA content (including mixed text and CDATA content).
+//!
+//! <div style="background:rgba(120,145,255,0.45);padding:0.75em;">
+//!
+//! NOTE: examples, marked with `FIXME:` does not work yet -- any PRs that fixes
+//! that are welcome! The message after marker is a test failure message.
+//! Also, all that tests are marked with an `ignore` option, although their
+//! compiles. This is by intention, because rustdoc marks such blocks with
+//! an information icon unlike `no_run` blocks.
+//!
+//! </div>
+//!
+//! <table>
+//! <thead>
+//! <tr><th>To parse all these XML's...</th><th>...use that Rust type(s)</th></tr>
+//! </thead>
+//! <tbody style="vertical-align:top;">
+//! <tr>
+//! <td>
+//! Content of attributes and text / CDATA content of elements (including mixed
+//! text and CDATA content):
+//!
+//! ```xml
+//! <... ...="content" />
+//! ```
+//! ```xml
+//! <...>content</...>
+//! ```
+//! ```xml
+//! <...><![CDATA[content]]></...>
+//! ```
+//! ```xml
+//! <...>text<![CDATA[cdata]]>text</...>
+//! ```
+//! <div style="background:rgba(80, 240, 100, 0.20);padding:0.75em;">
+//!
+//! Merging of the text / CDATA content is tracked in the issue [#474] and
+//! will be available in the next release.
+//! </div>
+//! </td>
+//! <td>
+//!
+//! You can use any type that can be deserialized from an `&str`, for example:
+//! - [`String`] and [`&str`]
+//! - [`Cow<str>`]
+//! - [`u32`], [`f32`] and other numeric types
+//! - `enum`s, like
+//!   ```ignore
+//!   // FIXME: #474, merging mixed text / CDATA
+//!   // content does not work yet
+//!   # use pretty_assertions::assert_eq;
+//!   # use serde::Deserialize;
+//!   # #[derive(Debug, PartialEq)]
+//!   #[derive(Deserialize)]
+//!   enum Language {
+//!     Rust,
+//!     Cpp,
+//!     #[serde(other)]
+//!     Other,
+//!   }
+//!   # #[derive(Debug, PartialEq, Deserialize)]
+//!   # struct X { #[serde(rename = "$text")] x: Language }
+//!   # assert_eq!(X { x: Language::Rust  }, quick_xml::de::from_str("<x>Rust</x>").unwrap());
+//!   # assert_eq!(X { x: Language::Cpp   }, quick_xml::de::from_str("<x>C<![CDATA[p]]>p</x>").unwrap());
+//!   # assert_eq!(X { x: Language::Other }, quick_xml::de::from_str("<x><![CDATA[other]]></x>").unwrap());
+//!   ```
+//!
+//! <div style="background:rgba(120,145,255,0.45);padding:0.75em;">
+//!
+//! NOTE: deserialization to non-owned types (i.e. borrow from the input),
+//! such as `&str`, is possible only if you parse document in the UTF-8
+//! encoding and content does not contain entity references such as `&amp;`,
+//! or character references such as `&#xD;`, as well as text content represented
+//! by one piece of [text] or [CDATA] element.
+//! </div>
+//! <!-- TODO: document an error type returned -->
+//!
+//! [text]: Event::Text
+//! [CDATA]: Event::CData
+//! </td>
+//! </tr>
+//! <!-- 2 ===================================================================================== -->
+//! <tr>
+//! <td>
+//!
+//! Content of attributes and text / CDATA content of elements (including mixed
+//! text and CDATA content), which represents a space-delimited lists, as
+//! specified in the XML Schema specification for [`xs:list`] `simpleType`:
+//!
+//! ```xml
+//! <... ...="element1 element2 ..." />
+//! ```
+//! ```xml
+//! <...>
+//!   element1
+//!   element2
+//!   ...
+//! </...>
+//! ```
+//! ```xml
+//! <...><![CDATA[
+//!   element1
+//!   element2
+//!   ...
+//! ]]></...>
+//! ```
+//! <div style="background:rgba(80, 240, 100, 0.20);padding:0.75em;">
+//!
+//! Merging of the text / CDATA content is tracked in the issue [#474] and
+//! will be available in the next release.
+//! </div>
+//!
+//! [`xs:list`]: https://www.w3.org/TR/xmlschema11-2/#list-datatypes
+//! </td>
+//! <td>
+//!
+//! Use any type that deserialized using [`deserialize_seq()`] call, for example:
+//!
+//! ```
+//! // FIXME: #474, merging mixed text / CDATA
+//! // content does not work yet
+//! type List = Vec<u32>;
+//! ```
+//!
+//! See the next row to learn where in your struct definition you should
+//! use that type.
+//!
+//! According to the XML Schema specification, delimiters for elements is one
+//! or more space (`' '`, `'\r'`, `'\n'`, and `'\t'`) character(s).
+//!
+//! <div style="background:rgba(120,145,255,0.45);padding:0.75em;">
+//!
+//! NOTE: according to the XML Schema restrictions, you cannot escape those
+//! white-space characters, so list elements will _never_ contain them.
+//! In practice you will usually use `xs:list`s for lists of numbers or enumerated
+//! values which looks like identifiers in many languages, for example, `item`,
+//! `some_item` or `some-item`, so that shouldn't be a problem.
+//!
+//! NOTE: according to the XML Schema specification, list elements can be
+//! delimited only by spaces. Other delimiters (for example, commas) are not
+//! allowed.
+//!
+//! </div>
+//!
+//! [`deserialize_seq()`]: de::Deserializer::deserialize_seq
+//! </td>
+//! </tr>
+//! <!-- 3 ===================================================================================== -->
+//! <tr>
+//! <td>
+//! A typical XML with attributes. The root tag name does not matter:
+//!
+//! ```xml
+//! <any-tag one="..." two="..."/>
+//! ```
+//! </td>
+//! <td>
+//!
+//! A structure where each XML attribute is mapped to a field with a name
+//! starting with `@`. Because Rust identifiers do not permit the `@` character,
+//! you should use the `#[serde(rename = "@...")]` attribute to rename it.
+//! The name of the struct itself does not matter:
+//!
+//! ```
+//! # use serde::Deserialize;
+//! # type T = ();
+//! # type U = ();
+//! // Get both attributes
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! struct AnyName {
+//!   #[serde(rename = "@one")]
+//!   one: T,
+//!
+//!   #[serde(rename = "@two")]
+//!   two: U,
+//! }
+//! # quick_xml::de::from_str::<AnyName>(r#"<any-tag one="..." two="..."/>"#).unwrap();
+//! ```
+//! ```
+//! # use serde::Deserialize;
+//! # type T = ();
+//! // Get only the one attribute, ignore the other
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! struct AnyName {
+//!   #[serde(rename = "@one")]
+//!   one: T,
+//! }
+//! # quick_xml::de::from_str::<AnyName>(r#"<any-tag one="..." two="..."/>"#).unwrap();
+//! # quick_xml::de::from_str::<AnyName>(r#"<any-tag one="..."/>"#).unwrap();
+//! # quick_xml::de::from_str::<AnyName>(r#"<any-tag one="..."><one>...</one></any-tag>"#).unwrap();
+//! ```
+//! ```
+//! # use serde::Deserialize;
+//! // Ignore all attributes
+//! // You can also use the `()` type (unit type)
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! struct AnyName;
+//! # quick_xml::de::from_str::<AnyName>(r#"<any-tag one="..." two="..."/>"#).unwrap();
+//! # quick_xml::de::from_str::<AnyName>(r#"<any-tag one="..."><one>...</one></any-tag>"#).unwrap();
+//! # quick_xml::de::from_str::<AnyName>(r#"<any-tag><one>...</one><two>...</two></any-tag>"#).unwrap();
+//! ```
+//!
+//! All these structs can be used to deserialize from an XML on the
+//! left side depending on amount of information that you want to get.
+//! Of course, you can combine them with elements extractor structs (see below).
+//!
+//! <div style="background:rgba(120,145,255,0.45);padding:0.75em;">
+//!
+//! NOTE: XML allows you to have an attribute and an element with the same name
+//! inside the one element. quick-xml deals with that by prepending a `@` prefix
+//! to the name of attributes.
+//! </div>
+//! </td>
+//! </tr>
+//! <!-- 4 ===================================================================================== -->
+//! <tr>
+//! <td>
+//! A typical XML with child elements. The root tag name does not matter:
+//!
+//! ```xml
+//! <any-tag>
+//!   <one>...</one>
+//!   <two>...</two>
+//! </any-tag>
+//! ```
+//! </td>
+//! <td>
+//! A structure where an each XML child element are mapped to the field.
+//! Each element name becomes a name of field. The name of the struct itself
+//! does not matter:
+//!
+//! ```
+//! # use serde::Deserialize;
+//! # type T = ();
+//! # type U = ();
+//! // Get both elements
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! struct AnyName {
+//!   one: T,
+//!   two: U,
+//! }
+//! # quick_xml::de::from_str::<AnyName>(r#"<any-tag><one>...</one><two>...</two></any-tag>"#).unwrap();
+//! #
+//! # quick_xml::de::from_str::<AnyName>(r#"<any-tag one="..." two="..."/>"#).unwrap_err();
+//! # quick_xml::de::from_str::<AnyName>(r#"<any-tag one="..."><two>...</two></any-tag>"#).unwrap_err();
+//! ```
+//! ```
+//! # use serde::Deserialize;
+//! # type T = ();
+//! // Get only the one element, ignore the other
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! struct AnyName {
+//!   one: T,
+//! }
+//! # quick_xml::de::from_str::<AnyName>(r#"<any-tag><one>...</one><two>...</two></any-tag>"#).unwrap();
+//! # quick_xml::de::from_str::<AnyName>(r#"<any-tag one="..."><one>...</one></any-tag>"#).unwrap();
+//! ```
+//! ```
+//! # use serde::Deserialize;
+//! // Ignore all elements
+//! // You can also use the `()` type (unit type)
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! struct AnyName;
+//! # quick_xml::de::from_str::<AnyName>(r#"<any-tag one="..." two="..."/>"#).unwrap();
+//! # quick_xml::de::from_str::<AnyName>(r#"<any-tag><one>...</one><two>...</two></any-tag>"#).unwrap();
+//! # quick_xml::de::from_str::<AnyName>(r#"<any-tag one="..."><two>...</two></any-tag>"#).unwrap();
+//! # quick_xml::de::from_str::<AnyName>(r#"<any-tag one="..."><one>...</one></any-tag>"#).unwrap();
+//! ```
+//!
+//! All these structs can be used to deserialize from an XML on the
+//! left side depending on amount of information that you want to get.
+//! Of course, you can combine them with attributes extractor structs (see above).
+//!
+//! <div style="background:rgba(120,145,255,0.45);padding:0.75em;">
+//!
+//! NOTE: XML allows you to have an attribute and an element with the same name
+//! inside the one element. quick-xml deals with that by prepending a `@` prefix
+//! to the name of attributes.
+//! </div>
+//! </td>
+//! </tr>
+//! <!-- 5 ===================================================================================== -->
+//! <tr>
+//! <td>
+//! An XML with an attribute and a child element named equally:
+//!
+//! ```xml
+//! <any-tag field="...">
+//!   <field>...</field>
+//! </any-tag>
+//! ```
+//! </td>
+//! <td>
+//!
+//! You MUST specify `#[serde(rename = "@field")]` on a field that will be used
+//! for an attribute:
+//!
+//! ```
+//! # use pretty_assertions::assert_eq;
+//! # use serde::Deserialize;
+//! # type T = ();
+//! # type U = ();
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! struct AnyName {
+//!   #[serde(rename = "@field")]
+//!   attribute: T,
+//!   field: U,
+//! }
+//! # assert_eq!(
+//! #   AnyName { attribute: (), field: () },
+//! #   quick_xml::de::from_str(r#"
+//! #     <any-tag field="...">
+//! #       <field>...</field>
+//! #     </any-tag>
+//! #   "#).unwrap(),
+//! # );
+//! ```
+//! </td>
+//! </tr>
+//! <!-- ======================================================================================= -->
+//! <tr><th colspan="2">
+//!
+//! ## Optional attributes and elements
+//!
+//! </th></tr>
+//! <tr><th>To parse all these XML's...</th><th>...use that Rust type(s)</th></tr>
+//! <!-- 6 ===================================================================================== -->
+//! <tr>
+//! <td>
+//! An optional XML attribute that you want to capture.
+//! The root tag name does not matter:
+//!
+//! ```xml
+//! <any-tag optional="..."/>
+//! ```
+//! ```xml
+//! <any-tag/>
+//! ```
+//! </td>
+//! <td>
+//!
+//! A structure with an optional field, renamed according to the requirements
+//! for attributes:
+//!
+//! ```
+//! # use pretty_assertions::assert_eq;
+//! # use serde::Deserialize;
+//! # type T = ();
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! struct AnyName {
+//!   #[serde(rename = "@optional")]
+//!   optional: Option<T>,
+//! }
+//! # assert_eq!(AnyName { optional: Some(()) }, quick_xml::de::from_str(r#"<any-tag optional="..."/>"#).unwrap());
+//! # assert_eq!(AnyName { optional: None     }, quick_xml::de::from_str(r#"<any-tag/>"#).unwrap());
+//! ```
+//! When the XML attribute is present, type `T` will be deserialized from
+//! an attribute value (which is a string). Note, that if `T = String` or other
+//! string type, the empty attribute is mapped to a `Some("")`, whereas `None`
+//! represents the missed attribute:
+//! ```xml
+//! <any-tag optional="..."/><!-- Some("...") -->
+//! <any-tag optional=""/>   <!-- Some("") -->
+//! <any-tag/>               <!-- None -->
+//! ```
+//! </td>
+//! </tr>
+//! <!-- 7 ===================================================================================== -->
+//! <tr>
+//! <td>
+//! An optional XML elements that you want to capture.
+//! The root tag name does not matter:
+//!
+//! ```xml
+//! <any-tag/>
+//!   <optional>...</optional>
+//! </any-tag>
+//! ```
+//! ```xml
+//! <any-tag/>
+//!   <optional/>
+//! </any-tag>
+//! ```
+//! ```xml
+//! <any-tag/>
+//! ```
+//! </td>
+//! <td>
+//!
+//! A structure with an optional field:
+//!
+//! ```
+//! # use pretty_assertions::assert_eq;
+//! # use serde::Deserialize;
+//! # type T = ();
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! struct AnyName {
+//!   optional: Option<T>,
+//! }
+//! # assert_eq!(AnyName { optional: Some(()) }, quick_xml::de::from_str(r#"<any-tag><optional>...</optional></any-tag>"#).unwrap());
+//! # assert_eq!(AnyName { optional: None     }, quick_xml::de::from_str(r#"<any-tag/>"#).unwrap());
+//! ```
+//! When the XML element is present, type `T` will be deserialized from an
+//! element (which is a string or a multi-mapping -- i.e. mapping which can have
+//! duplicated keys).
+//! <div style="background:rgba(80, 240, 100, 0.20);padding:0.75em;">
+//!
+//! Currently some edge cases exists described in the issue [#497].
+//! </div>
+//! </td>
+//! </tr>
+//! <!-- ======================================================================================= -->
+//! <tr><th colspan="2">
+//!
+//! ## Choices (`xs:choice` XML Schema type)
+//!
+//! </th></tr>
+//! <tr><th>To parse all these XML's...</th><th>...use that Rust type(s)</th></tr>
+//! <!-- 8 ===================================================================================== -->
+//! <tr>
+//! <td>
+//! An XML with different root tag names, as well as text / CDATA content:
+//!
+//! ```xml
+//! <one field1="...">...</one>
+//! ```
+//! ```xml
+//! <two>
+//!   <field2>...</field2>
+//! </two>
+//! ```
+//! ```xml
+//! Text <![CDATA[or (mixed)
+//! CDATA]]> content
+//! ```
+//! </td>
+//! <td>
+//!
+//! An enum where each variant have a name of the possible root tag. The name of
+//! the enum itself does not matter.
+//!
+//! If you need to get a textual content, mark a variant with `#[serde(rename = "$text")]`.
+//!
+//! All these structs can be used to deserialize from any XML on the
+//! left side depending on amount of information that you want to get:
+//!
+//! ```
+//! # use pretty_assertions::assert_eq;
+//! # use serde::Deserialize;
+//! # type T = ();
+//! # type U = ();
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! #[serde(rename_all = "snake_case")]
+//! enum AnyName {
+//!   One { #[serde(rename = "@field1")] field1: T },
+//!   Two { field2: U },
+//!
+//!   /// Use unit variant, if you do not care of a content.
+//!   /// You can use tuple variant if you want to parse
+//!   /// textual content as an xs:list.
+//!   /// Struct variants are not supported and will return
+//!   /// Err(Unsupported)
+//!   #[serde(rename = "$text")]
+//!   Text(String),
+//! }
+//! # assert_eq!(AnyName::One { field1: () }, quick_xml::de::from_str(r#"<one field1="...">...</one>"#).unwrap());
+//! # assert_eq!(AnyName::Two { field2: () }, quick_xml::de::from_str(r#"<two><field2>...</field2></two>"#).unwrap());
+//! # assert_eq!(AnyName::Text("text".into()), quick_xml::de::from_str(r#"text"#).unwrap());
+//! # // TODO: After #474 parse mixed content
+//! ```
+//! ```
+//! # use pretty_assertions::assert_eq;
+//! # use serde::Deserialize;
+//! # type T = ();
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! struct Two {
+//!   field2: T,
+//! }
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! #[serde(rename_all = "snake_case")]
+//! enum AnyName {
+//!   // `field1` content discarded
+//!   One,
+//!   Two(Two),
+//!   #[serde(rename = "$text")]
+//!   Text,
+//! }
+//! # assert_eq!(AnyName::One,                     quick_xml::de::from_str(r#"<one field1="...">...</one>"#).unwrap());
+//! # assert_eq!(AnyName::Two(Two { field2: () }), quick_xml::de::from_str(r#"<two><field2>...</field2></two>"#).unwrap());
+//! # assert_eq!(AnyName::Text,                    quick_xml::de::from_str(r#"text"#).unwrap());
+//! # // TODO: After #474 parse mixed content
+//! ```
+//! ```
+//! # use pretty_assertions::assert_eq;
+//! # use serde::Deserialize;
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! #[serde(rename_all = "snake_case")]
+//! enum AnyName {
+//!   One,
+//!   // the <two> and textual content will be mapped to this
+//!   #[serde(other)]
+//!   Other,
+//! }
+//! # assert_eq!(AnyName::One,   quick_xml::de::from_str(r#"<one field1="...">...</one>"#).unwrap());
+//! # assert_eq!(AnyName::Other, quick_xml::de::from_str(r#"<two><field2>...</field2></two>"#).unwrap());
+//! # assert_eq!(AnyName::Other, quick_xml::de::from_str(r#"text"#).unwrap());
+//! # // TODO: After #474 parse mixed content
+//! ```
+//! <div style="background:rgba(120,145,255,0.45);padding:0.75em;">
+//!
+//! NOTE: You should have variants for all possible tag names in your enum
+//! or have an `#[serde(other)]` variant.
+//! <!-- TODO: document an error type if that requirement is violated -->
+//! </div>
+//! </td>
+//! </tr>
+//! <!-- 9 ===================================================================================== -->
+//! <tr>
+//! <td>
+//!
+//! `<xs:choice>` embedded in the other element, and at the same time you want
+//! to get access to other attributes that can appear in the same container
+//! (`<any-tag>`). Also this case can be described, as if you want to choose
+//! Rust enum variant based on a tag name:
+//!
+//! ```xml
+//! <any-tag field="...">
+//!   <one>...</one>
+//! </any-tag>
+//! ```
+//! ```xml
+//! <any-tag field="...">
+//!   <two>...</two>
+//! </any-tag>
+//! ```
+//! ```xml
+//! <any-tag field="...">
+//!   Text <![CDATA[or (mixed)
+//!   CDATA]]> content
+//! </any-tag>
+//! ```
+//! </td>
+//! <td>
+//!
+//! A structure with a field which type is an `enum`.
+//!
+//! If you need to get a textual content, mark a variant with `#[serde(rename = "$text")]`.
+//!
+//! Names of the enum, struct, and struct field with `Choice` type does not matter:
+//!
+//! ```
+//! # use pretty_assertions::assert_eq;
+//! # use serde::Deserialize;
+//! # type T = ();
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! #[serde(rename_all = "snake_case")]
+//! enum Choice {
+//!   One,
+//!   Two,
+//!
+//!   /// Use unit variant, if you do not care of a content.
+//!   /// You can use tuple variant if you want to parse
+//!   /// textual content as an xs:list.
+//!   /// Struct variants are not supported and will return
+//!   /// Err(Unsupported)
+//!   #[serde(rename = "$text")]
+//!   Text(String),
+//! }
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! struct AnyName {
+//!   #[serde(rename = "@field")]
+//!   field: T,
+//!
+//!   #[serde(rename = "$value")]
+//!   any_name: Choice,
+//! }
+//! # assert_eq!(
+//! #   AnyName { field: (), any_name: Choice::One },
+//! #   quick_xml::de::from_str(r#"<any-tag field="..."><one>...</one></any-tag>"#).unwrap(),
+//! # );
+//! # assert_eq!(
+//! #   AnyName { field: (), any_name: Choice::Two },
+//! #   quick_xml::de::from_str(r#"<any-tag field="..."><two>...</two></any-tag>"#).unwrap(),
+//! # );
+//! # assert_eq!(
+//! #   AnyName { field: (), any_name: Choice::Text("text".into()) },
+//! #   // TODO: After #474 parse mixed content
+//! #   quick_xml::de::from_str(r#"<any-tag field="...">text</any-tag>"#).unwrap(),
+//! # );
+//! ```
+//! </td>
+//! </tr>
+//! <!-- 10 ==================================================================================== -->
+//! <tr>
+//! <td>
+//!
+//! `<xs:choice>` embedded in the other element, and at the same time you want
+//! to get access to other elements that can appear in the same container
+//! (`<any-tag>`). Also this case can be described, as if you want to choose
+//! Rust enum variant based on a tag name:
+//!
+//! ```xml
+//! <any-tag>
+//!   <field>...</field>
+//!   <one>...</one>
+//! </any-tag>
+//! ```
+//! ```xml
+//! <any-tag>
+//!   <two>...</two>
+//!   <field>...</field>
+//! </any-tag>
+//! ```
+//! </td>
+//! <td>
+//!
+//! A structure with a field which type is an `enum`.
+//!
+//! Names of the enum, struct, and struct field with `Choice` type does not matter:
+//!
+//! ```
+//! # use pretty_assertions::assert_eq;
+//! # use serde::Deserialize;
+//! # type T = ();
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! #[serde(rename_all = "snake_case")]
+//! enum Choice {
+//!   One,
+//!   Two,
+//! }
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! struct AnyName {
+//!   field: T,
+//!
+//!   #[serde(rename = "$value")]
+//!   any_name: Choice,
+//! }
+//! # assert_eq!(
+//! #   AnyName { field: (), any_name: Choice::One },
+//! #   quick_xml::de::from_str(r#"<any-tag><field>...</field><one>...</one></any-tag>"#).unwrap(),
+//! # );
+//! # assert_eq!(
+//! #   AnyName { field: (), any_name: Choice::Two },
+//! #   quick_xml::de::from_str(r#"<any-tag><two>...</two><field>...</field></any-tag>"#).unwrap(),
+//! # );
+//! ```
+//!
+//! <div style="background:rgba(120,145,255,0.45);padding:0.75em;">
+//!
+//! NOTE: if your `Choice` enum would contain an `#[serde(other)]`
+//! variant, element `<field>` will be mapped to the `field` and not to the enum
+//! variant.
+//! </div>
+//!
+//! </td>
+//! </tr>
+//! <!-- 11 ==================================================================================== -->
+//! <tr>
+//! <td>
+//!
+//! `<xs:choice>` encapsulated in other element with a fixed name:
+//!
+//! ```xml
+//! <any-tag field="...">
+//!   <choice>
+//!     <one>...</one>
+//!   </choice>
+//! </any-tag>
+//! ```
+//! ```xml
+//! <any-tag field="...">
+//!   <choice>
+//!     <two>...</two>
+//!   </choice>
+//! </any-tag>
+//! ```
+//! </td>
+//! <td>
+//!
+//! A structure with a field of an intermediate type with one field of `enum` type.
+//! Actually, this example is not necessary, because you can construct it by yourself
+//! using the composition rules that were described above. However the XML construction
+//! described here is very common, so it is shown explicitly.
+//!
+//! Names of the enum and struct does not matter:
+//!
+//! ```
+//! # use pretty_assertions::assert_eq;
+//! # use serde::Deserialize;
+//! # type T = ();
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! #[serde(rename_all = "snake_case")]
+//! enum Choice {
+//!   One,
+//!   Two,
+//! }
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! struct Holder {
+//!   #[serde(rename = "$value")]
+//!   any_name: Choice,
+//! }
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! struct AnyName {
+//!   #[serde(rename = "@field")]
+//!   field: T,
+//!
+//!   choice: Holder,
+//! }
+//! # assert_eq!(
+//! #   AnyName { field: (), choice: Holder { any_name: Choice::One } },
+//! #   quick_xml::de::from_str(r#"<any-tag field="..."><choice><one>...</one></choice></any-tag>"#).unwrap(),
+//! # );
+//! # assert_eq!(
+//! #   AnyName { field: (), choice: Holder { any_name: Choice::Two } },
+//! #   quick_xml::de::from_str(r#"<any-tag field="..."><choice><two>...</two></choice></any-tag>"#).unwrap(),
+//! # );
+//! ```
+//! </td>
+//! </tr>
+//! <!-- 12 ==================================================================================== -->
+//! <tr>
+//! <td>
+//!
+//! `<xs:choice>` encapsulated in other element with a fixed name:
+//!
+//! ```xml
+//! <any-tag>
+//!   <field>...</field>
+//!   <choice>
+//!     <one>...</one>
+//!   </choice>
+//! </any-tag>
+//! ```
+//! ```xml
+//! <any-tag>
+//!   <choice>
+//!     <two>...</two>
+//!   </choice>
+//!   <field>...</field>
+//! </any-tag>
+//! ```
+//! </td>
+//! <td>
+//!
+//! A structure with a field of an intermediate type with one field of `enum` type.
+//! Actually, this example is not necessary, because you can construct it by yourself
+//! using the composition rules that were described above. However the XML construction
+//! described here is very common, so it is shown explicitly.
+//!
+//! Names of the enum and struct does not matter:
+//!
+//! ```
+//! # use pretty_assertions::assert_eq;
+//! # use serde::Deserialize;
+//! # type T = ();
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! #[serde(rename_all = "snake_case")]
+//! enum Choice {
+//!   One,
+//!   Two,
+//! }
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! struct Holder {
+//!   #[serde(rename = "$value")]
+//!   any_name: Choice,
+//! }
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! struct AnyName {
+//!   field: T,
+//!
+//!   choice: Holder,
+//! }
+//! # assert_eq!(
+//! #   AnyName { field: (), choice: Holder { any_name: Choice::One } },
+//! #   quick_xml::de::from_str(r#"<any-tag><field>...</field><choice><one>...</one></choice></any-tag>"#).unwrap(),
+//! # );
+//! # assert_eq!(
+//! #   AnyName { field: (), choice: Holder { any_name: Choice::Two } },
+//! #   quick_xml::de::from_str(r#"<any-tag><choice><two>...</two></choice><field>...</field></any-tag>"#).unwrap(),
+//! # );
+//! ```
+//! </td>
+//! </tr>
+//! <!-- ======================================================================================== -->
+//! <tr><th colspan="2">
+//!
+//! ## Sequences (`xs:all` and `xs:sequence` XML Schema types)
+//!
+//! </th></tr>
+//! <tr><th>To parse all these XML's...</th><th>...use that Rust type(s)</th></tr>
+//! <!-- 13 ==================================================================================== -->
+//! <tr>
+//! <td>
+//! A sequence inside of a tag without a dedicated name:
+//!
+//! ```xml
+//! <any-tag/>
+//! ```
+//! ```xml
+//! <any-tag>
+//!   <item/>
+//! </any-tag>
+//! ```
+//! ```xml
+//! <any-tag>
+//!   <item/>
+//!   <item/>
+//!   <item/>
+//! </any-tag>
+//! ```
+//! </td>
+//! <td>
+//!
+//! A structure with a field which have a sequence type, for example, [`Vec`].
+//! Because XML syntax does not distinguish between empty sequences and missed
+//! elements, we should indicate that on the Rust side, because serde will require
+//! that field `item` exists. You can do that in two possible ways:
+//!
+//! Use the `#[serde(default)]` attribute for a [field] or the entire [struct]:
+//! ```
+//! # use pretty_assertions::assert_eq;
+//! # use serde::Deserialize;
+//! # type Item = ();
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! struct AnyName {
+//!   #[serde(default)]
+//!   item: Vec<Item>,
+//! }
+//! # assert_eq!(
+//! #   AnyName { item: vec![] },
+//! #   quick_xml::de::from_str(r#"<any-tag/>"#).unwrap(),
+//! # );
+//! # assert_eq!(
+//! #   AnyName { item: vec![()] },
+//! #   quick_xml::de::from_str(r#"<any-tag><item/></any-tag>"#).unwrap(),
+//! # );
+//! # assert_eq!(
+//! #   AnyName { item: vec![(), (), ()] },
+//! #   quick_xml::de::from_str(r#"<any-tag><item/><item/><item/></any-tag>"#).unwrap(),
+//! # );
+//! ```
+//!
+//! Use the [`Option`]. In that case inner array will always contains at least one
+//! element after deserialization:
+//! ```ignore
+//! # use pretty_assertions::assert_eq;
+//! # use serde::Deserialize;
+//! # type Item = ();
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! struct AnyName {
+//!   item: Option<Vec<Item>>,
+//! }
+//! # assert_eq!(
+//! #   AnyName { item: None },
+//! #   quick_xml::de::from_str(r#"<any-tag/>"#).unwrap(),
+//! # );
+//! # assert_eq!(
+//! #   AnyName { item: Some(vec![()]) },
+//! #   quick_xml::de::from_str(r#"<any-tag><item/></any-tag>"#).unwrap(),
+//! # );
+//! # assert_eq!(
+//! #   AnyName { item: Some(vec![(), (), ()]) },
+//! #   quick_xml::de::from_str(r#"<any-tag><item/><item/><item/></any-tag>"#).unwrap(),
+//! # );
+//! ```
+//!
+//! See also [Frequently Used Patterns](#element-lists).
+//!
+//! [field]: https://serde.rs/field-attrs.html#default
+//! [struct]: https://serde.rs/container-attrs.html#default
+//! </td>
+//! </tr>
+//! <!-- 14 ==================================================================================== -->
+//! <tr>
+//! <td>
+//! A sequence with a strict order, probably with a mixed content
+//! (text / CDATA and tags):
+//!
+//! ```xml
+//! <one>...</one>
+//! text
+//! <![CDATA[cdata]]>
+//! <two>...</two>
+//! <one>...</one>
+//! ```
+//! <div style="background:rgba(120,145,255,0.45);padding:0.75em;">
+//!
+//! NOTE: this is just an example for showing mapping. XML does not allow
+//! multiple root tags -- you should wrap the sequence into a tag.
+//! </div>
+//! </td>
+//! <td>
+//!
+//! All elements mapped to the heterogeneous sequential type: tuple or named tuple.
+//! Each element of the tuple should be able to be deserialized from the nested
+//! element content (`...`), except the enum types which would be deserialized
+//! from the full element (`<one>...</one>`), so they could use the element name
+//! to choose the right variant:
+//!
+//! ```ignore
+//! // FIXME: #474
+//! # use pretty_assertions::assert_eq;
+//! # use serde::Deserialize;
+//! # type One = ();
+//! # type Two = ();
+//! # /*
+//! type One = ...;
+//! type Two = ...;
+//! # */
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! struct AnyName(One, String, Two, One);
+//! # assert_eq!(
+//! #   AnyName((), "text cdata".into(), (), ()),
+//! #   quick_xml::de::from_str(r#"<one>...</one>text <![CDATA[cdata]]><two>...</two><one>...</one>"#).unwrap(),
+//! # );
+//! ```
+//! ```ignore
+//! // FIXME: #474, Custom("unknown variant `two`,
+//! //                      expected `one`")
+//! # use pretty_assertions::assert_eq;
+//! # use serde::Deserialize;
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! #[serde(rename_all = "snake_case")]
+//! enum Choice {
+//!   One,
+//! }
+//! # type Two = ();
+//! # /*
+//! type Two = ...;
+//! # */
+//! type AnyName = (Choice, String, Two, Choice);
+//! # assert_eq!(
+//! #   (Choice::One, "text cdata".to_string(), (), Choice::One),
+//! #   quick_xml::de::from_str(r#"<one>...</one>text <![CDATA[cdata]]><two>...</two><one>...</one>"#).unwrap(),
+//! # );
+//! ```
+//! <div style="background:rgba(120,145,255,0.45);padding:0.75em;">
+//!
+//! NOTE: consequent text and CDATA nodes are merged into the one text node,
+//! so you cannot have two adjacent string types in your sequence.
+//! </div>
+//! <div style="background:rgba(80, 240, 100, 0.20);padding:0.75em;">
+//!
+//! Merging of the text / CDATA content is tracked in the issue [#474] and
+//! will be available in the next release.
+//! </div>
+//! </td>
+//! </tr>
+//! <!-- 15 ==================================================================================== -->
+//! <tr>
+//! <td>
+//! A sequence with a non-strict order, probably with a mixed content
+//! (text / CDATA and tags).
+//!
+//! ```xml
+//! <one>...</one>
+//! text
+//! <![CDATA[cdata]]>
+//! <two>...</two>
+//! <one>...</one>
+//! ```
+//! <div style="background:rgba(120,145,255,0.45);padding:0.75em;">
+//!
+//! NOTE: this is just an example for showing mapping. XML does not allow
+//! multiple root tags -- you should wrap the sequence into a tag.
+//! </div>
+//! </td>
+//! <td>
+//! A homogeneous sequence of elements with a fixed or dynamic size:
+//!
+//! ```ignore
+//! // FIXME: #474
+//! # use pretty_assertions::assert_eq;
+//! # use serde::Deserialize;
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! #[serde(rename_all = "snake_case")]
+//! enum Choice {
+//!   One,
+//!   Two,
+//!   #[serde(other)]
+//!   Other,
+//! }
+//! type AnyName = [Choice; 4];
+//! # assert_eq!(
+//! #   [Choice::One, Choice::Other, Choice::Two, Choice::One],
+//! #   quick_xml::de::from_str::<AnyName>(r#"<one>...</one>text <![CDATA[cdata]]><two>...</two><one>...</one>"#).unwrap(),
+//! # );
+//! ```
+//! ```ignore
+//! // FIXME: #474
+//! # use pretty_assertions::assert_eq;
+//! # use serde::Deserialize;
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! #[serde(rename_all = "snake_case")]
+//! enum Choice {
+//!   One,
+//!   Two,
+//!   #[serde(rename = "$text")]
+//!   Other(String),
+//! }
+//! type AnyName = Vec<Choice>;
+//! # assert_eq!(
+//! #   vec![
+//! #     Choice::One,
+//! #     Choice::Other("text cdata".into()),
+//! #     Choice::Two,
+//! #     Choice::One,
+//! #   ],
+//! #   quick_xml::de::from_str::<AnyName>(r#"<one>...</one>text <![CDATA[cdata]]><two>...</two><one>...</one>"#).unwrap(),
+//! # );
+//! ```
+//! <div style="background:rgba(120,145,255,0.45);padding:0.75em;">
+//!
+//! NOTE: consequent text and CDATA nodes are merged into the one text node,
+//! so you cannot have two adjacent string types in your sequence.
+//! </div>
+//! <div style="background:rgba(80, 240, 100, 0.20);padding:0.75em;">
+//!
+//! Merging of the text / CDATA content is tracked in the issue [#474] and
+//! will be available in the next release.
+//! </div>
+//! </td>
+//! </tr>
+//! <!-- 16 ==================================================================================== -->
+//! <tr>
+//! <td>
+//! A sequence with a strict order, probably with a mixed content,
+//! (text and tags) inside of the other element:
+//!
+//! ```xml
+//! <any-tag attribute="...">
+//!   <one>...</one>
+//!   text
+//!   <![CDATA[cdata]]>
+//!   <two>...</two>
+//!   <one>...</one>
+//! </any-tag>
+//! ```
+//! </td>
+//! <td>
+//!
+//! A structure where all child elements mapped to the one field which have
+//! a heterogeneous sequential type: tuple or named tuple. Each element of the
+//! tuple should be able to be deserialized from the full element (`<one>...</one>`).
+//!
+//! You MUST specify `#[serde(rename = "$value")]` on that field:
+//!
+//! ```ignore
+//! // FIXME: #474, Custom("duplicate field `$value`")
+//! # use pretty_assertions::assert_eq;
+//! # use serde::Deserialize;
+//! # type One = ();
+//! # type Two = ();
+//! # /*
+//! type One = ...;
+//! type Two = ...;
+//! # */
+//!
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! struct AnyName {
+//!   #[serde(rename = "@attribute")]
+//! # attribute: (),
+//! # /*
+//!   attribute: ...,
+//! # */
+//!   // Does not (yet?) supported by the serde
+//!   // https://github.com/serde-rs/serde/issues/1905
+//!   // #[serde(flatten)]
+//!   #[serde(rename = "$value")]
+//!   any_name: (One, String, Two, One),
+//! }
+//! # assert_eq!(
+//! #   AnyName { attribute: (), any_name: ((), "text cdata".into(), (), ()) },
+//! #   quick_xml::de::from_str("\
+//! #     <any-tag attribute='...'>\
+//! #       <one>...</one>\
+//! #       text \
+//! #       <![CDATA[cdata]]>\
+//! #       <two>...</two>\
+//! #       <one>...</one>\
+//! #     </any-tag>"
+//! #   ).unwrap(),
+//! # );
+//! ```
+//! ```ignore
+//! // FIXME: #474, Custom("duplicate field `$value`")
+//! # use pretty_assertions::assert_eq;
+//! # use serde::Deserialize;
+//! # type One = ();
+//! # type Two = ();
+//! # /*
+//! type One = ...;
+//! type Two = ...;
+//! # */
+//!
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! struct NamedTuple(One, String, Two, One);
+//!
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! struct AnyName {
+//!   #[serde(rename = "@attribute")]
+//! # attribute: (),
+//! # /*
+//!   attribute: ...,
+//! # */
+//!   // Does not (yet?) supported by the serde
+//!   // https://github.com/serde-rs/serde/issues/1905
+//!   // #[serde(flatten)]
+//!   #[serde(rename = "$value")]
+//!   any_name: NamedTuple,
+//! }
+//! # assert_eq!(
+//! #   AnyName { attribute: (), any_name: NamedTuple((), "text cdata".into(), (), ()) },
+//! #   quick_xml::de::from_str("\
+//! #     <any-tag attribute='...'>\
+//! #       <one>...</one>\
+//! #       text \
+//! #       <![CDATA[cdata]]>\
+//! #       <two>...</two>\
+//! #       <one>...</one>\
+//! #     </any-tag>"
+//! #   ).unwrap(),
+//! # );
+//! ```
+//! <div style="background:rgba(120,145,255,0.45);padding:0.75em;">
+//!
+//! NOTE: consequent text and CDATA nodes are merged into the one text node,
+//! so you cannot have two adjacent string types in your sequence.
+//! </div>
+//! <div style="background:rgba(80, 240, 100, 0.20);padding:0.75em;">
+//!
+//! Merging of the text / CDATA content is tracked in the issue [#474] and
+//! will be available in the next release.
+//! </div>
+//! </td>
+//! </tr>
+//! <!-- 17 ==================================================================================== -->
+//! <tr>
+//! <td>
+//! A sequence with a non-strict order, probably with a mixed content
+//! (text / CDATA and tags) inside of the other element:
+//!
+//! ```xml
+//! <any-tag>
+//!   <one>...</one>
+//!   text
+//!   <![CDATA[cdata]]>
+//!   <two>...</two>
+//!   <one>...</one>
+//! </any-tag>
+//! ```
+//! </td>
+//! <td>
+//!
+//! A structure where all child elements mapped to the one field which have
+//! a homogeneous sequential type: array-like container. A container type `T`
+//! should be able to be deserialized from the nested element content (`...`),
+//! except if it is an enum type which would be deserialized from the full
+//! element (`<one>...</one>`).
+//!
+//! You MUST specify `#[serde(rename = "$value")]` on that field:
+//!
+//! ```ignore
+//! // FIXME: #474
+//! # use pretty_assertions::assert_eq;
+//! # use serde::Deserialize;
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! #[serde(rename_all = "snake_case")]
+//! enum Choice {
+//!   One,
+//!   Two,
+//!   #[serde(rename = "$text")]
+//!   Other(String),
+//! }
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! struct AnyName {
+//!   #[serde(rename = "@attribute")]
+//! # attribute: (),
+//! # /*
+//!   attribute: ...,
+//! # */
+//!   // Does not (yet?) supported by the serde
+//!   // https://github.com/serde-rs/serde/issues/1905
+//!   // #[serde(flatten)]
+//!   #[serde(rename = "$value")]
+//!   any_name: [Choice; 4],
+//! }
+//! # assert_eq!(
+//! #   AnyName { attribute: (), any_name: [
+//! #     Choice::One,
+//! #     Choice::Other("text cdata".into()),
+//! #     Choice::Two,
+//! #     Choice::One,
+//! #   ] },
+//! #   quick_xml::de::from_str("\
+//! #     <any-tag attribute='...'>\
+//! #       <one>...</one>\
+//! #       text \
+//! #       <![CDATA[cdata]]>\
+//! #       <two>...</two>\
+//! #       <one>...</one>\
+//! #     </any-tag>"
+//! #   ).unwrap(),
+//! # );
+//! ```
+//! ```ignore
+//! // FIXME: #474
+//! # use pretty_assertions::assert_eq;
+//! # use serde::Deserialize;
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! #[serde(rename_all = "snake_case")]
+//! enum Choice {
+//!   One,
+//!   Two,
+//!   #[serde(rename = "$text")]
+//!   Other(String),
+//! }
+//! # #[derive(Debug, PartialEq)]
+//! #[derive(Deserialize)]
+//! struct AnyName {
+//!   #[serde(rename = "@attribute")]
+//! # attribute: (),
+//! # /*
+//!   attribute: ...,
+//! # */
+//!   // Does not (yet?) supported by the serde
+//!   // https://github.com/serde-rs/serde/issues/1905
+//!   // #[serde(flatten)]
+//!   #[serde(rename = "$value")]
+//!   any_name: Vec<Choice>,
+//! }
+//! # assert_eq!(
+//! #   AnyName { attribute: (), any_name: vec![
+//! #     Choice::One,
+//! #     Choice::Other("text cdata".into()),
+//! #     Choice::Two,
+//! #     Choice::One,
+//! #   ] },
+//! #   quick_xml::de::from_str("\
+//! #     <any-tag attribute='...'>\
+//! #       <one>...</one>\
+//! #       text \
+//! #       <![CDATA[cdata]]>\
+//! #       <two>...</two>\
+//! #       <one>...</one>\
+//! #     </any-tag>"
+//! #   ).unwrap(),
+//! # );
+//! ```
+//! <div style="background:rgba(120,145,255,0.45);padding:0.75em;">
+//!
+//! NOTE: consequent text and CDATA nodes are merged into the one text node,
+//! so you cannot have two adjacent string types in your sequence.
+//! </div>
+//! <div style="background:rgba(80, 240, 100, 0.20);padding:0.75em;">
+//!
+//! Merging of the text / CDATA content is tracked in the issue [#474] and
+//! will be available in the next release.
+//! </div>
+//! </td>
+//! </tr>
+//! </tbody>
+//! </table>
+//!
+//!
+//!
+//! Composition Rules
+//! =================
+//!
+//! XML format is very different from other formats supported by `serde`.
+//! One such difference it is how data in the serialized form is related to
+//! the Rust type. Usually each byte in the data can be associated only with
+//! one field in the data structure. However, XML is an exception.
+//!
+//! For example, took this XML:
+//!
+//! ```xml
+//! <any>
+//!   <key attr="value"/>
+//! </any>
+//! ```
+//!
+//! and try to deserialize it to the struct `AnyName`:
+//!
+//! ```no_run
+//! # use serde::Deserialize;
+//! #[derive(Deserialize)]
+//! struct AnyName { // AnyName calls `deserialize_struct` on `<any><key attr="value"/></any>`
+//!                  //                         Used data:          ^^^^^^^^^^^^^^^^^^^
+//!   key: Inner,    // Inner   calls `deserialize_struct` on `<key attr="value"/>`
+//!                  //                         Used data:          ^^^^^^^^^^^^
+//! }
+//! #[derive(Deserialize)]
+//! struct Inner {
+//!   #[serde(rename = "@attr")]
+//!   attr: String,  // String  calls `deserialize_string` on `value`
+//!                  //                         Used data:     ^^^^^
+//! }
+//! ```
+//!
+//! Comments shows what methods of a [`Deserializer`] called by each struct
+//! `deserialize` method and which input their seen. **Used data** shows, what
+//! content is actually used for deserializing. As you see, name of the inner
+//! `<key>` tag used both as a map key / outer struct field name and as part
+//! of the inner struct (although _value_ of the tag, i.e. `key` is not used
+//! by it).
+//!
+//!
+//!
+//! Difference between `$text` and `$value` special names
+//! =====================================================
 //!
 //! quick-xml supports two special names for fields -- `$text` and `$value`.
 //! Although they may seem the same, there is a distinction. Two different
@@ -53,9 +1441,12 @@
 //! ```
 //!
 //! ## `$value`
-//! > Note: a name `#content` would better explain the purpose of that field,
-//! > but `$value` is used for compatibility with other XML serde crates, which
-//! > uses that name. This allow you to switch XML crate more smoothly if required.
+//! <div style="background:rgba(120,145,255,0.45);padding:0.75em;">
+//!
+//! NOTE: a name `#content` would better explain the purpose of that field,
+//! but `$value` is used for compatibility with other XML serde crates, which
+//! uses that name. This allow you to switch XML crate more smoothly if required.
+//! </div>
 //!
 //! Representation of primitive types in `$value` does not differ from their
 //! representation in `$text` field. The difference is how sequences are serialized.
@@ -226,7 +1617,111 @@
 //! that is not enforced, so you can theoretically have both, but you should
 //! avoid that.
 //!
+//!
+//!
+//! Frequently Used Patterns
+//! ========================
+//!
+//! Some XML constructs used so frequent, that it is worth to document the recommended
+//! way to represent them in the Rust. The sections below describes them.
+//!
+//! ## `<element>` lists
+//! Many XML formats wrap lists of elements in the additional container,
+//! although this is not required by the XML rules:
+//!
+//! ```xml
+//! <root>
+//!   <field1/>
+//!   <field2/>
+//!   <list><!-- Container -->
+//!     <element/>
+//!     <element/>
+//!     <element/>
+//!   </list>
+//!   <field3/>
+//! </root>
+//! ```
+//! In this case, there is a great desire to describe this XML in this way:
+//! ```
+//! /// Represents <element/>
+//! type Element = ();
+//!
+//! /// Represents <root>...</root>
+//! struct AnyName {
+//!     // Incorrect
+//!     list: Vec<Element>,
+//! }
+//! ```
+//! This will not work, because potentially `<list>` element can have attributes
+//! and other elements inside. You should define the struct for the `<list>`
+//! explicitly, as you do that in the XSD for that XML:
+//! ```
+//! /// Represents <element/>
+//! type Element = ();
+//!
+//! /// Represents <root>...</root>
+//! struct AnyName {
+//!     // Correct
+//!     list: List,
+//! }
+//! /// Represents <list>...</list>
+//! struct List {
+//!     element: Vec<Element>,
+//! }
+//! ```
+//!
+//! If you want to simplify your API, you could write a simple function for unwrapping
+//! inner list and apply it via [`deserialize_with`]:
+//!
+//! ```
+//! # use pretty_assertions::assert_eq;
+//! use quick_xml::de::from_str;
+//! use serde::{Deserialize, Deserializer};
+//!
+//! /// Represents <element/>
+//! type Element = ();
+//!
+//! /// Represents <root>...</root>
+//! #[derive(Deserialize, Debug, PartialEq)]
+//! struct AnyName {
+//!     #[serde(deserialize_with = "unwrap_list")]
+//!     list: Vec<Element>,
+//! }
+//!
+//! fn unwrap_list<'de, D>(deserializer: D) -> Result<Vec<Element>, D::Error>
+//! where
+//!     D: Deserializer<'de>,
+//! {
+//!     /// Represents <list>...</list>
+//!     #[derive(Deserialize)]
+//!     struct List {
+//!         // default allows empty list
+//!         #[serde(default)]
+//!         element: Vec<Element>,
+//!     }
+//!     Ok(List::deserialize(deserializer)?.element)
+//! }
+//!
+//! assert_eq!(
+//!     AnyName { list: vec![(), (), ()] },
+//!     from_str("
+//!         <root>
+//!           <list>
+//!             <element/>
+//!             <element/>
+//!             <element/>
+//!           </list>
+//!         </root>
+//!     ").unwrap(),
+//! );
+//! ```
+//!
+//! Instead of writing such functions manually, you also could try <https://lib.rs/crates/serde-query>.
+//!
 //! [specification]: https://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition
+//! [`deserialize_with`]: https://serde.rs/field-attrs.html#deserialize_with
+//! [#474]: https://github.com/tafia/quick-xml/issues/474
+//! [#497]: https://github.com/tafia/quick-xml/issues/497
 
 // Macros should be defined before the modules that using them
 // Also, macros should be imported before using them
@@ -239,7 +1734,7 @@ macro_rules! deserialize_type {
             V: Visitor<'de>,
         {
             // No need to unescape because valid integer representations cannot be escaped
-            let text = self.next_text(false)?;
+            let text = self.read_string(false)?;
             visitor.$visit(text.parse()?)
         }
     };
@@ -272,7 +1767,7 @@ macro_rules! deserialize_primitives {
             V: Visitor<'de>,
         {
             // No need to unescape because valid boolean representations cannot be escaped
-            let text = self.next_text(false)?;
+            let text = self.read_string(false)?;
 
             str2bool(&text, visitor)
         }
@@ -297,7 +1792,7 @@ macro_rules! deserialize_primitives {
         where
             V: Visitor<'de>,
         {
-            let text = self.next_text(true)?;
+            let text = self.read_string(true)?;
             match text {
                 Cow::Borrowed(string) => visitor.visit_borrowed_str(string),
                 Cow::Owned(string) => visitor.visit_string(string),
@@ -320,6 +1815,50 @@ macro_rules! deserialize_primitives {
             self.deserialize_bytes(visitor)
         }
 
+        /// Representation of the named units the same as [unnamed units](#method.deserialize_unit)
+        fn deserialize_unit_struct<V>(
+            self,
+            _name: &'static str,
+            visitor: V,
+        ) -> Result<V::Value, DeError>
+        where
+            V: Visitor<'de>,
+        {
+            self.deserialize_unit(visitor)
+        }
+
+        fn deserialize_newtype_struct<V>(
+            self,
+            _name: &'static str,
+            visitor: V,
+        ) -> Result<V::Value, DeError>
+        where
+            V: Visitor<'de>,
+        {
+            self.deserialize_tuple(1, visitor)
+        }
+
+        /// Representation of tuples the same as [sequences](#method.deserialize_seq).
+        fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, DeError>
+        where
+            V: Visitor<'de>,
+        {
+            self.deserialize_seq(visitor)
+        }
+
+        /// Representation of named tuples the same as [unnamed tuples](#method.deserialize_tuple).
+        fn deserialize_tuple_struct<V>(
+            self,
+            _name: &'static str,
+            len: usize,
+            visitor: V,
+        ) -> Result<V::Value, DeError>
+        where
+            V: Visitor<'de>,
+        {
+            self.deserialize_tuple(len, visitor)
+        }
+
         /// Identifiers represented as [strings](#method.deserialize_str).
         fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, DeError>
         where
@@ -330,7 +1869,17 @@ macro_rules! deserialize_primitives {
     };
 }
 
-mod escape;
+macro_rules! deserialize_option {
+    ($de:expr, $deserializer:ident, $visitor:ident) => {
+        match $de.peek()? {
+            DeEvent::Text(t) if t.is_empty() => $visitor.visit_none(),
+            DeEvent::CData(t) if t.is_empty() => $visitor.visit_none(),
+            DeEvent::Eof => $visitor.visit_none(),
+            _ => $visitor.visit_some($deserializer),
+        }
+    };
+}
+
 mod key;
 mod map;
 mod simple_type;
@@ -611,6 +2160,7 @@ where
     /// should be replayed after calling [`Self::start_replay()`].
     #[cfg(feature = "overlapped-lists")]
     #[inline]
+    #[must_use = "returned checkpoint should be used in `start_replay`"]
     fn skip_checkpoint(&self) -> usize {
         self.write.len()
     }
@@ -638,16 +2188,21 @@ where
                         DeEvent::End(ref e) if e.name().as_ref() == end => {
                             self.skip_event(event)?;
                             if depth == 0 {
-                                return Ok(());
+                                break;
                             }
                             depth -= 1;
                         }
+                        DeEvent::Eof => {
+                            self.skip_event(event)?;
+                            break;
+                        }
                         _ => self.skip_event(event)?,
                     }
                 }
             }
-            _ => Ok(()),
+            _ => (),
         }
+        Ok(())
     }
 
     #[cfg(feature = "overlapped-lists")]
@@ -684,23 +2239,9 @@ where
         }
     }
 
-    fn next_start(&mut self) -> Result<Option<BytesStart<'de>>, DeError> {
-        loop {
-            let e = self.next()?;
-            match e {
-                DeEvent::Start(e) => return Ok(Some(e)),
-                DeEvent::End(e) => {
-                    return Err(DeError::UnexpectedEnd(e.name().as_ref().to_owned()))
-                }
-                DeEvent::Eof => return Ok(None),
-                _ => (), // ignore texts
-            }
-        }
-    }
-
     #[inline]
-    fn next_text(&mut self, unescape: bool) -> Result<Cow<'de, str>, DeError> {
-        self.next_text_impl(unescape, true)
+    fn read_string(&mut self, unescape: bool) -> Result<Cow<'de, str>, DeError> {
+        self.read_string_impl(unescape, true)
     }
 
     /// Consumes a one XML element or an XML tree, returns associated text or
@@ -735,7 +2276,7 @@ where
     /// |[`DeEvent::Text`] |`text content`             |Unescapes `text content` and returns it, consumes events up to `</tag>`
     /// |[`DeEvent::CData`]|`<![CDATA[cdata content]]>`|Returns `cdata content` unchanged, consumes events up to `</tag>`
     /// |[`DeEvent::Eof`]  |                           |Emits [`UnexpectedEof`](DeError::UnexpectedEof)
-    fn next_text_impl(
+    fn read_string_impl(
         &mut self,
         unescape: bool,
         allow_start: bool,
@@ -783,7 +2324,7 @@ where
                 }
                 Some(DeEvent::End(e)) if e.name() == name => {
                     if depth == 0 {
-                        return Ok(());
+                        break;
                     }
                     depth -= 1;
                 }
@@ -793,9 +2334,29 @@ where
 
                 // If we do not have skipped events, use effective reading that will
                 // not allocate memory for events
-                None => return self.reader.read_to_end(name),
+                None => {
+                    // We should close all opened tags, because we could buffer
+                    // Start events, but not the corresponding End events. So we
+                    // keep reading events until we exit all nested tags.
+                    // `read_to_end()` will return an error if an Eof was encountered
+                    // preliminary (in case of malformed XML).
+                    //
+                    // <tag><tag></tag></tag>
+                    // ^^^^^^^^^^             - buffered in `self.read`, when `self.read_to_end()` is called, depth = 2
+                    //           ^^^^^^       - read by the first call of `self.reader.read_to_end()`
+                    //                 ^^^^^^ - read by the second call of `self.reader.read_to_end()`
+                    loop {
+                        self.reader.read_to_end(name)?;
+                        if depth == 0 {
+                            break;
+                        }
+                        depth -= 1;
+                    }
+                    break;
+                }
             }
         }
+        Ok(())
     }
     #[cfg(not(feature = "overlapped-lists"))]
     fn read_to_end(&mut self, name: QName) -> Result<(), DeError> {
@@ -811,6 +2372,7 @@ where
 
 impl<'de> Deserializer<'de, SliceReader<'de>> {
     /// Create new deserializer that will borrow data from the specified string
+    #[allow(clippy::should_implement_trait)]
     pub fn from_str(s: &'de str) -> Self {
         let mut reader = Reader::from_str(s);
         reader
@@ -860,15 +2422,17 @@ where
     where
         V: Visitor<'de>,
     {
-        // Try to go to the next `<tag ...>...</tag>` or `<tag .../>`
-        if let Some(e) = self.next_start()? {
-            let name = e.name().as_ref().to_vec();
-            let map = map::MapAccess::new(self, e, fields)?;
-            let value = visitor.visit_map(map)?;
-            self.read_to_end(QName(&name))?;
-            Ok(value)
-        } else {
-            Err(DeError::ExpectedStart)
+        match self.next()? {
+            DeEvent::Start(e) => {
+                let name = e.name().as_ref().to_vec();
+                let map = map::MapAccess::new(self, e, fields)?;
+                let value = visitor.visit_map(map)?;
+                self.read_to_end(QName(&name))?;
+                Ok(value)
+            }
+            DeEvent::End(e) => Err(DeError::UnexpectedEnd(e.name().as_ref().to_owned())),
+            DeEvent::Text(_) | DeEvent::CData(_) => Err(DeError::ExpectedStart),
+            DeEvent::Eof => Err(DeError::UnexpectedEof),
         }
     }
 
@@ -905,50 +2469,6 @@ where
         }
     }
 
-    /// Representation of the names units the same as [unnamed units](#method.deserialize_unit)
-    fn deserialize_unit_struct<V>(
-        self,
-        _name: &'static str,
-        visitor: V,
-    ) -> Result<V::Value, DeError>
-    where
-        V: Visitor<'de>,
-    {
-        self.deserialize_unit(visitor)
-    }
-
-    fn deserialize_newtype_struct<V>(
-        self,
-        _name: &'static str,
-        visitor: V,
-    ) -> Result<V::Value, DeError>
-    where
-        V: Visitor<'de>,
-    {
-        self.deserialize_tuple(1, visitor)
-    }
-
-    /// Representation of tuples the same as [sequences](#method.deserialize_seq).
-    fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, DeError>
-    where
-        V: Visitor<'de>,
-    {
-        self.deserialize_seq(visitor)
-    }
-
-    /// Representation of named tuples the same as [unnamed tuples](#method.deserialize_tuple).
-    fn deserialize_tuple_struct<V>(
-        self,
-        _name: &'static str,
-        len: usize,
-        visitor: V,
-    ) -> Result<V::Value, DeError>
-    where
-        V: Visitor<'de>,
-    {
-        self.deserialize_tuple(len, visitor)
-    }
-
     fn deserialize_enum<V>(
         self,
         _name: &'static str,
@@ -958,8 +2478,7 @@ where
     where
         V: Visitor<'de>,
     {
-        let value = visitor.visit_enum(var::EnumAccess::new(self))?;
-        Ok(value)
+        visitor.visit_enum(var::EnumAccess::new(self))
     }
 
     fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, DeError>
@@ -980,12 +2499,7 @@ where
     where
         V: Visitor<'de>,
     {
-        match self.peek()? {
-            DeEvent::Text(t) if t.is_empty() => visitor.visit_none(),
-            DeEvent::CData(t) if t.is_empty() => visitor.visit_none(),
-            DeEvent::Eof => visitor.visit_none(),
-            _ => visitor.visit_some(self),
-        }
+        deserialize_option!(self, self, visitor)
     }
 
     /// Always call `visitor.visit_unit()` because returned value ignored in any case.
@@ -1607,51 +3121,83 @@ mod tests {
                 e => panic!("Expected `Err(TooManyEvents(3))`, but found {:?}", e),
             }
         }
+
+        /// Without handling Eof in `skip` this test failed with memory allocation
+        #[test]
+        fn invalid_xml() {
+            use crate::de::DeEvent::*;
+
+            let mut de = Deserializer::from_str("<root>");
+
+            // Cache all events
+            let checkpoint = de.skip_checkpoint();
+            de.skip().unwrap();
+            de.start_replay(checkpoint);
+            assert_eq!(de.read, vec![Start(BytesStart::new("root")), Eof]);
+        }
     }
 
-    #[test]
-    fn read_to_end() {
+    mod read_to_end {
+        use super::*;
         use crate::de::DeEvent::*;
+        use pretty_assertions::assert_eq;
 
-        let mut de = Deserializer::from_str(
-            r#"
-            <root>
-                <tag a="1"><tag>text</tag>content</tag>
-                <tag a="2"><![CDATA[cdata content]]></tag>
-                <self-closed/>
-            </root>
-            "#,
-        );
+        #[test]
+        fn complex() {
+            let mut de = Deserializer::from_str(
+                r#"
+                <root>
+                    <tag a="1"><tag>text</tag>content</tag>
+                    <tag a="2"><![CDATA[cdata content]]></tag>
+                    <self-closed/>
+                </root>
+                "#,
+            );
 
-        assert_eq!(de.next().unwrap(), Start(BytesStart::new("root")));
+            assert_eq!(de.next().unwrap(), Start(BytesStart::new("root")));
 
-        assert_eq!(
-            de.next().unwrap(),
-            Start(BytesStart::from_content(r#"tag a="1""#, 3))
-        );
-        assert_eq!(de.read_to_end(QName(b"tag")).unwrap(), ());
+            assert_eq!(
+                de.next().unwrap(),
+                Start(BytesStart::from_content(r#"tag a="1""#, 3))
+            );
+            assert_eq!(de.read_to_end(QName(b"tag")).unwrap(), ());
 
-        assert_eq!(
-            de.next().unwrap(),
-            Start(BytesStart::from_content(r#"tag a="2""#, 3))
-        );
-        assert_eq!(de.next().unwrap(), CData(BytesCData::new("cdata content")));
-        assert_eq!(de.next().unwrap(), End(BytesEnd::new("tag")));
+            assert_eq!(
+                de.next().unwrap(),
+                Start(BytesStart::from_content(r#"tag a="2""#, 3))
+            );
+            assert_eq!(de.next().unwrap(), CData(BytesCData::new("cdata content")));
+            assert_eq!(de.next().unwrap(), End(BytesEnd::new("tag")));
+
+            assert_eq!(de.next().unwrap(), Start(BytesStart::new("self-closed")));
+            assert_eq!(de.read_to_end(QName(b"self-closed")).unwrap(), ());
+
+            assert_eq!(de.next().unwrap(), End(BytesEnd::new("root")));
+            assert_eq!(de.next().unwrap(), Eof);
+        }
+
+        #[test]
+        fn invalid_xml() {
+            let mut de = Deserializer::from_str("<tag><tag></tag>");
 
-        assert_eq!(de.next().unwrap(), Start(BytesStart::new("self-closed")));
-        assert_eq!(de.read_to_end(QName(b"self-closed")).unwrap(), ());
+            assert_eq!(de.next().unwrap(), Start(BytesStart::new("tag")));
+            assert_eq!(de.peek().unwrap(), &Start(BytesStart::new("tag")));
 
-        assert_eq!(de.next().unwrap(), End(BytesEnd::new("root")));
-        assert_eq!(de.next().unwrap(), Eof);
+            match de.read_to_end(QName(b"tag")) {
+                Err(DeError::UnexpectedEof) => (),
+                x => panic!("Expected `Err(UnexpectedEof)`, but found {:?}", x),
+            }
+            assert_eq!(de.next().unwrap(), Eof);
+        }
     }
 
     #[test]
     fn borrowing_reader_parity() {
-        let s = r##"
+        let s = r#"
             <item name="hello" source="world.rs">Some text</item>
             <item2/>
             <item3 value="world" />
-    	"##;
+        "#;
 
         let mut reader1 = IoReader {
             reader: Reader::from_reader(s.as_bytes()),
@@ -1675,12 +3221,12 @@ mod tests {
 
     #[test]
     fn borrowing_reader_events() {
-        let s = r##"
+        let s = r#"
             <item name="hello" source="world.rs">Some text</item>
             <item2></item2>
             <item3/>
             <item4 value="world" />
-        "##;
+        "#;
 
         let mut reader = SliceReader {
             reader: Reader::from_str(s),
@@ -1723,31 +3269,10 @@ mod tests {
         )
     }
 
-    #[test]
-    fn borrowing_read_to_end() {
-        let s = " <item /> ";
-        let mut reader = SliceReader {
-            reader: Reader::from_str(s),
-        };
-
-        reader
-            .reader
-            .trim_text(true)
-            .expand_empty_elements(true)
-            .check_end_names(true);
-
-        assert_eq!(
-            reader.next().unwrap(),
-            DeEvent::Start(BytesStart::from_content("item ", 4))
-        );
-        reader.read_to_end(QName(b"item")).unwrap();
-        assert_eq!(reader.next().unwrap(), DeEvent::Eof);
-    }
-
-    /// Ensures, that [`Deserializer::next_text()`] never can get an `End` event,
+    /// Ensures, that [`Deserializer::read_string()`] never can get an `End` event,
     /// because parser reports error early
     #[test]
-    fn next_text() {
+    fn read_string() {
         match from_str::<String>(r#"</root>"#) {
             Err(DeError::InvalidXml(Error::EndEventMismatch { expected, found })) => {
                 assert_eq!(expected, "");
diff --git a/src/de/simple_type.rs b/src/de/simple_type.rs
index d7e4ca3..c3ea9c9 100644
--- a/src/de/simple_type.rs
+++ b/src/de/simple_type.rs
@@ -522,15 +522,16 @@ pub struct SimpleTypeDeserializer<'de, 'a> {
 
 impl<'de, 'a> SimpleTypeDeserializer<'de, 'a> {
     /// Creates a deserializer from a value, that possible borrowed from input
-    pub fn from_cow(value: Cow<'de, [u8]>, escaped: bool, decoder: Decoder) -> Self {
+    pub fn from_text_content(value: Cow<'de, str>) -> Self {
         let content = match value {
-            Cow::Borrowed(slice) => CowRef::Input(slice),
-            Cow::Owned(content) => CowRef::Owned(content),
+            Cow::Borrowed(slice) => CowRef::Input(slice.as_bytes()),
+            Cow::Owned(content) => CowRef::Owned(content.into_bytes()),
         };
-        Self::new(content, escaped, decoder)
+        Self::new(content, false, Decoder::utf8())
     }
 
     /// Creates a deserializer from a part of value at specified range
+    #[allow(clippy::ptr_arg)]
     pub fn from_part(
         value: &'a Cow<'de, [u8]>,
         range: Range<usize>,
diff --git a/src/de/var.rs b/src/de/var.rs
index 2034ced..8a7b019 100644
--- a/src/de/var.rs
+++ b/src/de/var.rs
@@ -1,9 +1,11 @@
 use crate::{
-    de::{escape::EscapedDeserializer, DeEvent, Deserializer, XmlRead},
+    de::key::QNameDeserializer,
+    de::simple_type::SimpleTypeDeserializer,
+    de::{DeEvent, Deserializer, XmlRead, TEXT_KEY},
     errors::serialize::DeError,
 };
-use serde::de::{self, DeserializeSeed, Deserializer as SerdeDeserializer, Visitor};
-use std::borrow::Cow;
+use serde::de::value::StrDeserializer;
+use serde::de::{self, DeserializeSeed, Deserializer as _, Visitor};
 
 /// An enum access
 pub struct EnumAccess<'de, 'a, R>
@@ -34,21 +36,25 @@ where
         V: DeserializeSeed<'de>,
     {
         let decoder = self.de.reader.decoder();
-        let de = match self.de.peek()? {
-            DeEvent::Text(t) => EscapedDeserializer::new(Cow::Borrowed(t), decoder, true),
-            // Escape sequences does not processed inside CDATA section
-            DeEvent::CData(t) => EscapedDeserializer::new(Cow::Borrowed(t), decoder, false),
-            DeEvent::Start(e) => {
-                EscapedDeserializer::new(Cow::Borrowed(e.local_name().into_inner()), decoder, false)
-            }
-            _ => {
-                return Err(DeError::Unsupported(
-                    "Invalid event for Enum, expecting `Text` or `Start`".into(),
-                ))
-            }
+        let (name, is_text) = match self.de.peek()? {
+            DeEvent::Start(e) => (
+                seed.deserialize(QNameDeserializer::from_elem(e.name(), decoder)?)?,
+                false,
+            ),
+            DeEvent::Text(_) | DeEvent::CData(_) => (
+                seed.deserialize(StrDeserializer::<DeError>::new(TEXT_KEY))?,
+                true,
+            ),
+            DeEvent::End(e) => return Err(DeError::UnexpectedEnd(e.name().into_inner().to_vec())),
+            DeEvent::Eof => return Err(DeError::UnexpectedEof),
         };
-        let name = seed.deserialize(de)?;
-        Ok((name, VariantAccess { de: self.de }))
+        Ok((
+            name,
+            VariantAccess {
+                de: self.de,
+                is_text,
+            },
+        ))
     }
 }
 
@@ -57,6 +63,9 @@ where
     R: XmlRead<'de>,
 {
     de: &'a mut Deserializer<'de, R>,
+    /// `true` if variant should be deserialized from a textual content
+    /// and `false` if from tag
+    is_text: bool,
 }
 
 impl<'de, 'a, R> de::VariantAccess<'de> for VariantAccess<'de, 'a, R>
@@ -67,9 +76,13 @@ where
 
     fn unit_variant(self) -> Result<(), DeError> {
         match self.de.next()? {
+            // Consume subtree
             DeEvent::Start(e) => self.de.read_to_end(e.name()),
+            // Does not needed to deserialize using SimpleTypeDeserializer, because
+            // it returns `()` when `deserialize_unit()` is requested
             DeEvent::Text(_) | DeEvent::CData(_) => Ok(()),
-            _ => unreachable!(),
+            // SAFETY: the other events are filtered in `variant_seed()`
+            _ => unreachable!("Only `Start`, `Text` or `CData` events are possible here"),
         }
     }
 
@@ -77,14 +90,38 @@ where
     where
         T: DeserializeSeed<'de>,
     {
-        seed.deserialize(&mut *self.de)
+        if self.is_text {
+            match self.de.next()? {
+                DeEvent::Text(e) => {
+                    seed.deserialize(SimpleTypeDeserializer::from_text_content(e.decode(true)?))
+                }
+                DeEvent::CData(e) => {
+                    seed.deserialize(SimpleTypeDeserializer::from_text_content(e.decode()?))
+                }
+                // SAFETY: the other events are filtered in `variant_seed()`
+                _ => unreachable!("Only `Text` or `CData` events are possible here"),
+            }
+        } else {
+            seed.deserialize(&mut *self.de)
+        }
     }
 
     fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value, DeError>
     where
         V: Visitor<'de>,
     {
-        self.de.deserialize_tuple(len, visitor)
+        if self.is_text {
+            match self.de.next()? {
+                DeEvent::Text(e) => SimpleTypeDeserializer::from_text_content(e.decode(true)?)
+                    .deserialize_tuple(len, visitor),
+                DeEvent::CData(e) => SimpleTypeDeserializer::from_text_content(e.decode()?)
+                    .deserialize_tuple(len, visitor),
+                // SAFETY: the other events are filtered in `variant_seed()`
+                _ => unreachable!("Only `Text` or `CData` events are possible here"),
+            }
+        } else {
+            self.de.deserialize_tuple(len, visitor)
+        }
     }
 
     fn struct_variant<V>(
@@ -95,6 +132,17 @@ where
     where
         V: Visitor<'de>,
     {
-        self.de.deserialize_struct("", fields, visitor)
+        if self.is_text {
+            match self.de.next()? {
+                DeEvent::Text(e) => SimpleTypeDeserializer::from_text_content(e.decode(true)?)
+                    .deserialize_struct("", fields, visitor),
+                DeEvent::CData(e) => SimpleTypeDeserializer::from_text_content(e.decode()?)
+                    .deserialize_struct("", fields, visitor),
+                // SAFETY: the other events are filtered in `variant_seed()`
+                _ => unreachable!("Only `Text` or `CData` events are possible here"),
+            }
+        } else {
+            self.de.deserialize_struct("", fields, visitor)
+        }
     }
 }
diff --git a/src/errors.rs b/src/errors.rs
index 1f60c0b..0afd5a0 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -7,12 +7,15 @@ use std::fmt;
 use std::io::Error as IoError;
 use std::str::Utf8Error;
 use std::string::FromUtf8Error;
+use std::sync::Arc;
 
 /// The error type used by this crate.
-#[derive(Debug)]
+#[derive(Clone, Debug)]
 pub enum Error {
-    /// IO error
-    Io(IoError),
+    /// IO error.
+    ///
+    /// `Arc<IoError>` instead of `IoError` since `IoError` is not `Clone`.
+    Io(Arc<IoError>),
     /// Input decoding error. If `encoding` feature is disabled, contains `None`,
     /// otherwise contains the UTF-8 decoding error
     NonDecodable(Option<Utf8Error>),
@@ -45,7 +48,7 @@ impl From<IoError> for Error {
     /// Creates a new `Error::Io` from the given error
     #[inline]
     fn from(error: IoError) -> Error {
-        Error::Io(error)
+        Error::Io(Arc::new(error))
     }
 }
 
@@ -140,7 +143,7 @@ pub mod serialize {
     use std::num::{ParseFloatError, ParseIntError};
 
     /// (De)serialization error
-    #[derive(Debug)]
+    #[derive(Clone, Debug)]
     pub enum DeError {
         /// Serde custom error
         Custom(String),
diff --git a/src/escapei.rs b/src/escapei.rs
index d1d966f..ce779f0 100644
--- a/src/escapei.rs
+++ b/src/escapei.rs
@@ -8,7 +8,7 @@ use std::ops::Range;
 use pretty_assertions::assert_eq;
 
 /// Error for XML escape / unescape.
-#[derive(Debug)]
+#[derive(Clone, Debug)]
 pub enum EscapeError {
     /// Entity with Null character
     EntityWithNull(Range<usize>),
@@ -117,8 +117,8 @@ pub(crate) fn _escape<F: Fn(u8) -> bool>(raw: &str, escape_chars: F) -> Cow<str>
             // in elements of xs:lists, because those characters works as
             // delimiters of list elements
             b'\t' => escaped.extend_from_slice(b"&#9;"),
-            b'\r' => escaped.extend_from_slice(b"&#10;"),
-            b'\n' => escaped.extend_from_slice(b"&#13;"),
+            b'\n' => escaped.extend_from_slice(b"&#10;"),
+            b'\r' => escaped.extend_from_slice(b"&#13;"),
             b' ' => escaped.extend_from_slice(b"&#32;"),
             _ => unreachable!(
                 "Only '<', '>','\', '&', '\"', '\\t', '\\r', '\\n', and ' ' are escaped"
@@ -181,8 +181,7 @@ where
 
                 // search for character correctness
                 let pat = &raw[start + 1..end];
-                if pat.starts_with('#') {
-                    let entity = &pat[1..]; // starts after the #
+                if let Some(entity) = pat.strip_prefix('#') {
                     let codepoint = parse_number(entity, start..end)?;
                     unescaped.push_str(codepoint.encode_utf8(&mut [0u8; 4]));
                 } else if let Some(value) = named_entity(pat) {
@@ -1691,8 +1690,8 @@ fn named_entity(name: &str) -> Option<&str> {
 }
 
 fn parse_number(bytes: &str, range: Range<usize>) -> Result<char, EscapeError> {
-    let code = if bytes.starts_with('x') {
-        parse_hexadecimal(&bytes[1..])
+    let code = if let Some(hex_digits) = bytes.strip_prefix('x') {
+        parse_hexadecimal(hex_digits)
     } else {
         parse_decimal(bytes)
     }?;
@@ -1741,7 +1740,13 @@ fn parse_decimal(bytes: &str) -> Result<u32, EscapeError> {
 
 #[test]
 fn test_unescape() {
-    assert_eq!(unescape("test").unwrap(), Cow::Borrowed("test"));
+    let unchanged = unescape("test").unwrap();
+    // assert_eq does not check that Cow is borrowed, but we explicitly use Cow
+    // because it influences diff
+    // TODO: use assert_matches! when stabilized and other features will bump MSRV
+    assert_eq!(unchanged, Cow::Borrowed("test"));
+    assert!(matches!(unchanged, Cow::Borrowed(_)));
+
     assert_eq!(unescape("&lt;test&gt;").unwrap(), "<test>");
     assert_eq!(unescape("&#x30;").unwrap(), "0");
     assert_eq!(unescape("&#48;").unwrap(), "0");
@@ -1755,10 +1760,13 @@ fn test_unescape_with() {
         _ => None,
     };
 
-    assert_eq!(
-        unescape_with("test", custom_entities).unwrap(),
-        Cow::Borrowed("test")
-    );
+    let unchanged = unescape_with("test", custom_entities).unwrap();
+    // assert_eq does not check that Cow is borrowed, but we explicitly use Cow
+    // because it influences diff
+    // TODO: use assert_matches! when stabilized and other features will bump MSRV
+    assert_eq!(unchanged, Cow::Borrowed("test"));
+    assert!(matches!(unchanged, Cow::Borrowed(_)));
+
     assert_eq!(
         unescape_with("&lt;test&gt;", custom_entities).unwrap(),
         "<test>"
@@ -1771,7 +1779,13 @@ fn test_unescape_with() {
 
 #[test]
 fn test_escape() {
-    assert_eq!(escape("test"), Cow::Borrowed("test"));
+    let unchanged = escape("test");
+    // assert_eq does not check that Cow is borrowed, but we explicitly use Cow
+    // because it influences diff
+    // TODO: use assert_matches! when stabilized and other features will bump MSRV
+    assert_eq!(unchanged, Cow::Borrowed("test"));
+    assert!(matches!(unchanged, Cow::Borrowed(_)));
+
     assert_eq!(escape("<test>"), "&lt;test&gt;");
     assert_eq!(escape("\"a\"bc"), "&quot;a&quot;bc");
     assert_eq!(escape("\"a\"b&c"), "&quot;a&quot;b&amp;c");
@@ -1783,7 +1797,13 @@ fn test_escape() {
 
 #[test]
 fn test_partial_escape() {
-    assert_eq!(partial_escape("test"), Cow::Borrowed("test"));
+    let unchanged = partial_escape("test");
+    // assert_eq does not check that Cow is borrowed, but we explicitly use Cow
+    // because it influences diff
+    // TODO: use assert_matches! when stabilized and other features will bump MSRV
+    assert_eq!(unchanged, Cow::Borrowed("test"));
+    assert!(matches!(unchanged, Cow::Borrowed(_)));
+
     assert_eq!(partial_escape("<test>"), "&lt;test&gt;");
     assert_eq!(partial_escape("\"a\"bc"), "\"a\"bc");
     assert_eq!(partial_escape("\"a\"b&c"), "\"a\"b&amp;c");
diff --git a/src/events/attributes.rs b/src/events/attributes.rs
index 7eb2b27..8c99b8b 100644
--- a/src/events/attributes.rs
+++ b/src/events/attributes.rs
@@ -19,7 +19,7 @@ use std::{borrow::Cow, ops::Range};
 ///
 /// [`unescape_value`]: Self::unescape_value
 /// [`decode_and_unescape_value`]: Self::decode_and_unescape_value
-#[derive(Clone, PartialEq)]
+#[derive(Clone, Eq, PartialEq)]
 pub struct Attribute<'a> {
     /// The key to uniquely define the attribute.
     ///
@@ -241,7 +241,7 @@ impl<'a> FusedIterator for Attributes<'a> {}
 ///
 /// Recovery position in examples shows the position from which parsing of the
 /// next attribute will be attempted.
-#[derive(Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
 pub enum AttrError {
     /// Attribute key was not followed by `=`, position relative to the start of
     /// the owning tag is provided.
@@ -537,6 +537,7 @@ impl IterState {
 
     /// Skip all characters up to first space symbol or end-of-input
     #[inline]
+    #[allow(clippy::manual_map)]
     fn skip_value(&self, slice: &[u8], offset: usize) -> Option<usize> {
         let mut iter = (offset..).zip(slice[offset..].iter());
 
@@ -776,7 +777,7 @@ impl IterState {
             None => {
                 // Because we reach end-of-input, stop iteration on next call
                 self.state = State::Done;
-                return Some(Err(AttrError::ExpectedQuote(slice.len(), quote)));
+                Some(Err(AttrError::ExpectedQuote(slice.len(), quote)))
             }
         }
     }
diff --git a/src/events/mod.rs b/src/events/mod.rs
index 7ebed26..1b813a8 100644
--- a/src/events/mod.rs
+++ b/src/events/mod.rs
@@ -119,7 +119,7 @@ impl<'a> BytesStart<'a> {
     /// Converts the event into an owned event without taking ownership of Event
     pub fn to_owned(&self) -> BytesStart<'static> {
         BytesStart {
-            buf: Cow::Owned(self.buf.to_owned().into()),
+            buf: Cow::Owned(self.buf.clone().into_owned()),
             name_len: self.name_len,
         }
     }
@@ -360,35 +360,28 @@ impl<'a> BytesDecl<'a> {
     /// # Examples
     ///
     /// ```
-    /// use std::borrow::Cow;
     /// use quick_xml::Error;
     /// use quick_xml::events::{BytesDecl, BytesStart};
     ///
     /// // <?xml version='1.1'?>
     /// let decl = BytesDecl::from_start(BytesStart::from_content(" version='1.1'", 0));
-    /// assert_eq!(
-    ///     decl.version().unwrap(),
-    ///     Cow::Borrowed(b"1.1".as_ref())
-    /// );
+    /// assert_eq!(decl.version().unwrap(), b"1.1".as_ref());
     ///
     /// // <?xml version='1.0' version='1.1'?>
     /// let decl = BytesDecl::from_start(BytesStart::from_content(" version='1.0' version='1.1'", 0));
-    /// assert_eq!(
-    ///     decl.version().unwrap(),
-    ///     Cow::Borrowed(b"1.0".as_ref())
-    /// );
+    /// assert_eq!(decl.version().unwrap(), b"1.0".as_ref());
     ///
     /// // <?xml encoding='utf-8'?>
     /// let decl = BytesDecl::from_start(BytesStart::from_content(" encoding='utf-8'", 0));
     /// match decl.version() {
-    ///     Err(Error::XmlDeclWithoutVersion(Some(key))) => assert_eq!(key, "encoding".to_string()),
+    ///     Err(Error::XmlDeclWithoutVersion(Some(key))) => assert_eq!(key, "encoding"),
     ///     _ => assert!(false),
     /// }
     ///
     /// // <?xml encoding='utf-8' version='1.1'?>
     /// let decl = BytesDecl::from_start(BytesStart::from_content(" encoding='utf-8' version='1.1'", 0));
     /// match decl.version() {
-    ///     Err(Error::XmlDeclWithoutVersion(Some(key))) => assert_eq!(key, "encoding".to_string()),
+    ///     Err(Error::XmlDeclWithoutVersion(Some(key))) => assert_eq!(key, "encoding"),
     ///     _ => assert!(false),
     /// }
     ///
diff --git a/src/name.rs b/src/name.rs
index ac1c714..ebf2e13 100644
--- a/src/name.rs
+++ b/src/name.rs
@@ -16,7 +16,7 @@ use std::fmt::{self, Debug, Formatter};
 ///
 /// [qualified name]: https://www.w3.org/TR/xml-names11/#dt-qualname
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
+#[cfg_attr(feature = "serde-types", derive(serde::Deserialize, serde::Serialize))]
 pub struct QName<'a>(pub &'a [u8]);
 impl<'a> QName<'a> {
     /// Converts this name to an internal slice representation.
@@ -133,7 +133,7 @@ impl<'a> AsRef<[u8]> for QName<'a> {
 ///
 /// [local (unqualified) name]: https://www.w3.org/TR/xml-names11/#dt-localname
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
+#[cfg_attr(feature = "serde-types", derive(serde::Deserialize, serde::Serialize))]
 pub struct LocalName<'a>(&'a [u8]);
 impl<'a> LocalName<'a> {
     /// Converts this name to an internal slice representation.
@@ -183,7 +183,7 @@ impl<'a> From<QName<'a>> for LocalName<'a> {
 ///
 /// [namespace prefix]: https://www.w3.org/TR/xml-names11/#dt-prefix
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
+#[cfg_attr(feature = "serde-types", derive(serde::Deserialize, serde::Serialize))]
 pub struct Prefix<'a>(&'a [u8]);
 impl<'a> Prefix<'a> {
     /// Extracts internal slice
@@ -225,7 +225,7 @@ pub enum PrefixDeclaration<'a> {
 ///
 /// [namespace name]: https://www.w3.org/TR/xml-names11/#dt-NSName
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
+#[cfg_attr(feature = "serde-types", derive(serde::Deserialize, serde::Serialize))]
 pub struct Namespace<'a>(pub &'a [u8]);
 impl<'a> Namespace<'a> {
     /// Converts this namespace to an internal slice representation.
diff --git a/src/reader/buffered_reader.rs b/src/reader/buffered_reader.rs
index 6bd21b9..d17946d 100644
--- a/src/reader/buffered_reader.rs
+++ b/src/reader/buffered_reader.rs
@@ -27,7 +27,7 @@ macro_rules! impl_buffered_source {
                         Ok(())
                     },
                     Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
-                    Err(e) => Err(Error::Io(e)),
+                    Err(e) => Err(Error::Io(e.into())),
                 };
             }
         }
@@ -43,7 +43,7 @@ macro_rules! impl_buffered_source {
                         Ok(None)
                     },
                     Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
-                    Err(e) => Err(Error::Io(e)),
+                    Err(e) => Err(Error::Io(e.into())),
                 };
             }
         }
@@ -69,7 +69,7 @@ macro_rules! impl_buffered_source {
                         Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
                         Err(e) => {
                             *position += read;
-                            return Err(Error::Io(e));
+                            return Err(Error::Io(e.into()));
                         }
                     };
 
@@ -136,7 +136,7 @@ macro_rules! impl_buffered_source {
                     Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
                     Err(e) => {
                         *position += read;
-                        return Err(Error::Io(e));
+                        return Err(Error::Io(e.into()));
                     }
                 }
             }
@@ -181,7 +181,7 @@ macro_rules! impl_buffered_source {
                     Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
                     Err(e) => {
                         *position += read;
-                        return Err(Error::Io(e));
+                        return Err(Error::Io(e.into()));
                     }
                 };
             }
@@ -207,7 +207,7 @@ macro_rules! impl_buffered_source {
                         }
                     }
                     Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
-                    Err(e) => Err(Error::Io(e)),
+                    Err(e) => Err(Error::Io(e.into())),
                 };
             }
         }
@@ -232,7 +232,7 @@ macro_rules! impl_buffered_source {
                     Ok(n) if n.is_empty() => Ok(None),
                     Ok(n) => Ok(Some(n[0])),
                     Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
-                    Err(e) => Err(Error::Io(e)),
+                    Err(e) => Err(Error::Io(e.into())),
                 };
             }
         }
@@ -398,7 +398,7 @@ impl<R: BufRead> Reader<R> {
 impl Reader<BufReader<File>> {
     /// Creates an XML reader from a file path.
     pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
-        let file = File::open(path).map_err(Error::Io)?;
+        let file = File::open(path)?;
         let reader = BufReader::new(file);
         Ok(Self::from_reader(reader))
     }
diff --git a/src/reader/mod.rs b/src/reader/mod.rs
index 77ed187..d928230 100644
--- a/src/reader/mod.rs
+++ b/src/reader/mod.rs
@@ -802,7 +802,7 @@ impl BangType {
         None
     }
     #[inline]
-    fn to_err(self) -> Error {
+    fn to_err(&self) -> Error {
         let bang_str = match self {
             Self::CData => "CData",
             Self::Comment => "Comment",
@@ -849,10 +849,7 @@ impl ReadElementState {
 /// A function to check whether the byte is a whitespace (blank, new line, carriage return or tab)
 #[inline]
 pub(crate) fn is_whitespace(b: u8) -> bool {
-    match b {
-        b' ' | b'\r' | b'\n' | b'\t' => true,
-        _ => false,
-    }
+    matches!(b, b' ' | b'\r' | b'\n' | b'\t')
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/reader/ns_reader.rs b/src/reader/ns_reader.rs
index 4ce816f..09457f2 100644
--- a/src/reader/ns_reader.rs
+++ b/src/reader/ns_reader.rs
@@ -538,6 +538,7 @@ impl NsReader<BufReader<File>> {
 impl<'i> NsReader<&'i [u8]> {
     /// Creates an XML reader from a string slice.
     #[inline]
+    #[allow(clippy::should_implement_trait)]
     pub fn from_str(s: &'i str) -> Self {
         Self::new(Reader::from_str(s))
     }
diff --git a/src/reader/parser.rs b/src/reader/parser.rs
index dc5e37a..38b6f49 100644
--- a/src/reader/parser.rs
+++ b/src/reader/parser.rs
@@ -142,31 +142,40 @@ impl Parser {
         } else {
             &buf[1..]
         };
-        if self.check_end_names {
-            let decoder = self.decoder();
-            let mismatch_err = |expected: String, found: &[u8], offset: &mut usize| {
-                *offset -= buf.len();
-                Err(Error::EndEventMismatch {
-                    expected,
-                    found: decoder.decode(found).unwrap_or_default().into_owned(),
-                })
-            };
-            match self.opened_starts.pop() {
-                Some(start) => {
+
+        let decoder = self.decoder();
+        let mismatch_err = |expected: String, found: &[u8], offset: &mut usize| {
+            *offset -= buf.len();
+            Err(Error::EndEventMismatch {
+                expected,
+                found: decoder.decode(found).unwrap_or_default().into_owned(),
+            })
+        };
+
+        // Get the index in self.opened_buffer of the name of the last opened tag
+        match self.opened_starts.pop() {
+            Some(start) => {
+                if self.check_end_names {
                     let expected = &self.opened_buffer[start..];
                     if name != expected {
                         let expected = decoder.decode(expected).unwrap_or_default().into_owned();
-                        mismatch_err(expected, name, &mut self.offset)
-                    } else {
+                        // #513: In order to allow error recovery we should drop content of the buffer
                         self.opened_buffer.truncate(start);
-                        Ok(Event::End(BytesEnd::wrap(name.into())))
+
+                        return mismatch_err(expected, name, &mut self.offset);
                     }
                 }
-                None => mismatch_err("".to_string(), &buf[1..], &mut self.offset),
+
+                self.opened_buffer.truncate(start);
+            }
+            None => {
+                if self.check_end_names {
+                    return mismatch_err("".to_string(), &buf[1..], &mut self.offset);
+                }
             }
-        } else {
-            Ok(Event::End(BytesEnd::wrap(name.into())))
         }
+
+        Ok(Event::End(BytesEnd::wrap(name.into())))
     }
 
     /// reads `BytesElement` starting with a `?`,
@@ -212,10 +221,11 @@ impl Parser {
                 Ok(Event::Empty(BytesStart::wrap(&buf[..len - 1], end)))
             }
         } else {
-            if self.check_end_names {
-                self.opened_starts.push(self.opened_buffer.len());
-                self.opened_buffer.extend(&buf[..name_end]);
-            }
+            // #514: Always store names event when .check_end_names == false,
+            // because checks can be temporary disabled and when they would be
+            // enabled, we should have that information
+            self.opened_starts.push(self.opened_buffer.len());
+            self.opened_buffer.extend(&buf[..name_end]);
             Ok(Event::Start(BytesStart::wrap(buf, name_end)))
         }
     }
diff --git a/src/reader/slice_reader.rs b/src/reader/slice_reader.rs
index fd4dbaa..dc0a5b8 100644
--- a/src/reader/slice_reader.rs
+++ b/src/reader/slice_reader.rs
@@ -21,6 +21,7 @@ use memchr;
 /// itself can be used to borrow from.
 impl<'a> Reader<&'a [u8]> {
     /// Creates an XML reader from a string slice.
+    #[allow(clippy::should_implement_trait)]
     pub fn from_str(s: &'a str) -> Self {
         // Rust strings are guaranteed to be UTF-8, so lock the encoding
         #[cfg(feature = "encoding")]
@@ -212,6 +213,7 @@ impl<'a> Reader<&'a [u8]> {
     ///         <p>Usual XML rules does not apply inside it
     ///         <p>For example, elements not needed to be &quot;closed&quot;
     ///     "#));
+    /// assert!(matches!(text, Cow::Borrowed(_)));
     ///
     /// // Now we can enable checks again
     /// reader.check_end_names(true);
diff --git a/src/se/element.rs b/src/se/element.rs
index 5703329..f2d9d8d 100644
--- a/src/se/element.rs
+++ b/src/se/element.rs
@@ -339,7 +339,7 @@ impl<'k, W: Write> Struct<'k, W> {
     /// If `key` has a magic value [`TEXT_KEY`], then `value` serialized as a
     /// [simple type].
     ///
-    /// If `key` has a magic value [`CONTENT_KEY`], then `value` serialized as a
+    /// If `key` has a magic value [`VALUE_KEY`], then `value` serialized as a
     /// [content] without wrapping in tags, otherwise it is wrapped in
     /// `<${key}>...</${key}>`.
     ///
@@ -627,9 +627,9 @@ mod tests {
                 <root>2</root>\
                 <root>3</root>");
         serialize_as!(seq_empty: Vec::<usize>::new() => "");
-        serialize_as!(tuple: ("<\"&'>", "with\t\r\n spaces", 3usize)
+        serialize_as!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
             => "<root>&lt;&quot;&amp;&apos;&gt;</root>\
-                <root>with\t\r\n spaces</root>\
+                <root>with\t\n\r spaces</root>\
                 <root>3</root>");
         serialize_as!(tuple_struct: Tuple("first", 42)
             => "<root>first</root>\
@@ -747,7 +747,7 @@ mod tests {
                 // Sequences are serialized separated by spaces, all spaces inside are escaped
                 text!(seq: vec![1, 2, 3] => "1 2 3");
                 text!(seq_empty: Vec::<usize>::new());
-                text!(tuple: ("<\"&'>", "with\t\r\n spaces", 3usize)
+                text!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
                     => "&lt;&quot;&amp;&apos;&gt; \
                         with&#9;&#10;&#13;&#32;spaces \
                         3");
@@ -874,7 +874,7 @@ mod tests {
                 // Sequences are serialized separated by spaces, all spaces inside are escaped
                 text!(seq: vec![1, 2, 3] => "1 2 3");
                 text!(seq_empty: Vec::<usize>::new() => "");
-                text!(tuple: ("<\"&'>", "with\t\r\n spaces", 3usize)
+                text!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
                     => "&lt;&quot;&amp;&apos;&gt; \
                         with&#9;&#10;&#13;&#32;spaces \
                         3");
@@ -1001,7 +1001,7 @@ mod tests {
                 // Sequences are serialized separated by spaces, all spaces inside are escaped
                 text!(seq: vec![1, 2, 3] => "1 2 3");
                 text!(seq_empty: Vec::<usize>::new() => "");
-                text!(tuple: ("<\"&'>", "with\t\r\n spaces", 3usize)
+                text!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
                     => "&lt;&quot;&amp;&apos;&gt; \
                         with&#9;&#10;&#13;&#32;spaces \
                         3");
@@ -1123,9 +1123,9 @@ mod tests {
                 // Note that sequences of primitives serialized without delimiters!
                 value!(seq: vec![1, 2, 3] => "123");
                 value!(seq_empty: Vec::<usize>::new());
-                value!(tuple: ("<\"&'>", "with\t\r\n spaces", 3usize)
+                value!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
                     => "&lt;&quot;&amp;&apos;&gt;\
-                        with\t\r\n spaces\
+                        with\t\n\r spaces\
                         3");
                 value!(tuple_struct: Tuple("first", 42) => "first42");
                 value!(enum_tuple: Enum::Tuple("first", 42)
@@ -1237,9 +1237,9 @@ mod tests {
                 // Note that sequences of primitives serialized without delimiters!
                 value!(seq: vec![1, 2, 3] => "123");
                 value!(seq_empty: Vec::<usize>::new() => "");
-                value!(tuple: ("<\"&'>", "with\t\r\n spaces", 3usize)
+                value!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
                     => "&lt;&quot;&amp;&apos;&gt;\
-                        with\t\r\n spaces\
+                        with\t\n\r spaces\
                         3");
                 value!(tuple_struct: Tuple("first", 42) => "first42");
                 value!(enum_tuple: Enum::Tuple("first", 42)
@@ -1359,9 +1359,9 @@ mod tests {
                 // Note that sequences of primitives serialized without delimiters!
                 value!(seq: vec![1, 2, 3] => "123");
                 value!(seq_empty: Vec::<usize>::new() => "");
-                value!(tuple: ("<\"&'>", "with\t\r\n spaces", 3usize)
+                value!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
                     => "&lt;&quot;&amp;&apos;&gt;\
-                        with\t\r\n spaces\
+                        with\t\n\r spaces\
                         3");
                 value!(tuple_struct: Tuple("first", 42) => "first42");
                 value!(enum_tuple: Enum::Tuple("first", 42)
@@ -1588,9 +1588,9 @@ mod tests {
                 <root>2</root>\n\
                 <root>3</root>");
         serialize_as!(seq_empty: Vec::<usize>::new() => "");
-        serialize_as!(tuple: ("<\"&'>", "with\t\r\n spaces", 3usize)
+        serialize_as!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
             => "<root>&lt;&quot;&amp;&apos;&gt;</root>\n\
-                <root>with\t\r\n spaces</root>\n\
+                <root>with\t\n\r spaces</root>\n\
                 <root>3</root>");
         serialize_as!(tuple_struct: Tuple("first", 42)
             => "<root>first</root>\n\
@@ -1708,7 +1708,7 @@ mod tests {
                 // Sequences are serialized separated by spaces, all spaces inside are escaped
                 text!(seq: vec![1, 2, 3] => "1 2 3");
                 text!(seq_empty: Vec::<usize>::new());
-                text!(tuple: ("<\"&'>", "with\t\r\n spaces", 3usize)
+                text!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
                     => "&lt;&quot;&amp;&apos;&gt; \
                         with&#9;&#10;&#13;&#32;spaces \
                         3");
@@ -1847,7 +1847,7 @@ mod tests {
                 // Sequences are serialized separated by spaces, all spaces inside are escaped
                 text!(seq: vec![1, 2, 3] => "1 2 3");
                 text!(seq_empty: Vec::<usize>::new());
-                text!(tuple: ("<\"&'>", "with\t\r\n spaces", 3usize)
+                text!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
                     => "&lt;&quot;&amp;&apos;&gt; \
                         with&#9;&#10;&#13;&#32;spaces \
                         3");
@@ -1986,7 +1986,7 @@ mod tests {
                 // Sequences are serialized separated by spaces, all spaces inside are escaped
                 text!(seq: vec![1, 2, 3] => "1 2 3");
                 text!(seq_empty: Vec::<usize>::new());
-                text!(tuple: ("<\"&'>", "with\t\r\n spaces", 3usize)
+                text!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
                     => "&lt;&quot;&amp;&apos;&gt; \
                         with&#9;&#10;&#13;&#32;spaces \
                         3");
@@ -2107,9 +2107,9 @@ mod tests {
 
                 value!(seq: vec![1, 2, 3] => "1\n  2\n  3");
                 value!(seq_empty: Vec::<usize>::new());
-                value!(tuple: ("<\"&'>", "with\t\r\n spaces", 3usize)
+                value!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
                     => "&lt;&quot;&amp;&apos;&gt;\n  \
-                        with\t\r\n spaces\n  \
+                        with\t\n\r spaces\n  \
                         3");
                 value!(tuple_struct: Tuple("first", 42) => "first\n  42");
                 value!(enum_tuple: Enum::Tuple("first", 42)
@@ -2233,9 +2233,9 @@ mod tests {
                 // Note that sequences of primitives serialized without delimiters!
                 value!(seq: vec![1, 2, 3] => "1\n  2\n  3");
                 value!(seq_empty: Vec::<usize>::new());
-                value!(tuple: ("<\"&'>", "with\t\r\n spaces", 3usize)
+                value!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
                     => "&lt;&quot;&amp;&apos;&gt;\n  \
-                        with\t\r\n spaces\n  \
+                        with\t\n\r spaces\n  \
                         3");
                 value!(tuple_struct: Tuple("first", 42) => "first\n  42");
                 value!(enum_tuple: Enum::Tuple("first", 42)
@@ -2367,9 +2367,9 @@ mod tests {
                 // Note that sequences of primitives serialized without delimiters!
                 value!(seq: vec![1, 2, 3] => "1\n  2\n  3");
                 value!(seq_empty: Vec::<usize>::new());
-                value!(tuple: ("<\"&'>", "with\t\r\n spaces", 3usize)
+                value!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
                     => "&lt;&quot;&amp;&apos;&gt;\n  \
-                        with\t\r\n spaces\n  \
+                        with\t\n\r spaces\n  \
                         3");
                 value!(tuple_struct: Tuple("first", 42) => "first\n  42");
                 value!(enum_tuple: Enum::Tuple("first", 42)
diff --git a/src/se/simple_type.rs b/src/se/simple_type.rs
index 17f6dc0..55832ed 100644
--- a/src/se/simple_type.rs
+++ b/src/se/simple_type.rs
@@ -587,7 +587,7 @@ mod tests {
             #[test]
             fn text() {
                 assert_eq!(
-                    escape_item("text<\"'&> \t\r\ntext", QuoteTarget::Text, QuoteLevel::Full),
+                    escape_item("text<\"'&> \t\n\rtext", QuoteTarget::Text, QuoteLevel::Full),
                     "text&lt;&quot;&apos;&amp;&gt;&#32;&#9;&#10;&#13;text"
                 );
             }
@@ -596,7 +596,7 @@ mod tests {
             fn double_quote_attr() {
                 assert_eq!(
                     escape_item(
-                        "text<\"'&> \t\r\ntext",
+                        "text<\"'&> \t\n\rtext",
                         QuoteTarget::DoubleQAttr,
                         QuoteLevel::Full
                     ),
@@ -608,7 +608,7 @@ mod tests {
             fn single_quote_attr() {
                 assert_eq!(
                     escape_item(
-                        "text<\"'&> \t\r\ntext",
+                        "text<\"'&> \t\n\rtext",
                         QuoteTarget::SingleQAttr,
                         QuoteLevel::Full
                     ),
@@ -625,7 +625,7 @@ mod tests {
             fn text() {
                 assert_eq!(
                     escape_item(
-                        "text<\"'&> \t\r\ntext",
+                        "text<\"'&> \t\n\rtext",
                         QuoteTarget::Text,
                         QuoteLevel::Partial
                     ),
@@ -637,7 +637,7 @@ mod tests {
             fn double_quote_attr() {
                 assert_eq!(
                     escape_item(
-                        "text<\"'&> \t\r\ntext",
+                        "text<\"'&> \t\n\rtext",
                         QuoteTarget::DoubleQAttr,
                         QuoteLevel::Partial
                     ),
@@ -649,7 +649,7 @@ mod tests {
             fn single_quote_attr() {
                 assert_eq!(
                     escape_item(
-                        "text<\"'&> \t\r\ntext",
+                        "text<\"'&> \t\n\rtext",
                         QuoteTarget::SingleQAttr,
                         QuoteLevel::Partial
                     ),
@@ -666,7 +666,7 @@ mod tests {
             fn text() {
                 assert_eq!(
                     escape_item(
-                        "text<\"'&> \t\r\ntext",
+                        "text<\"'&> \t\n\rtext",
                         QuoteTarget::Text,
                         QuoteLevel::Minimal
                     ),
@@ -678,7 +678,7 @@ mod tests {
             fn double_quote_attr() {
                 assert_eq!(
                     escape_item(
-                        "text<\"'&> \t\r\ntext",
+                        "text<\"'&> \t\n\rtext",
                         QuoteTarget::DoubleQAttr,
                         QuoteLevel::Minimal
                     ),
@@ -690,7 +690,7 @@ mod tests {
             fn single_quote_attr() {
                 assert_eq!(
                     escape_item(
-                        "text<\"'&> \t\r\ntext",
+                        "text<\"'&> \t\n\rtext",
                         QuoteTarget::SingleQAttr,
                         QuoteLevel::Minimal
                     ),
@@ -710,8 +710,8 @@ mod tests {
             #[test]
             fn text() {
                 assert_eq!(
-                    escape_list("text<\"'&> \t\r\ntext", QuoteTarget::Text, QuoteLevel::Full),
-                    "text&lt;&quot;&apos;&amp;&gt; \t\r\ntext"
+                    escape_list("text<\"'&> \t\n\rtext", QuoteTarget::Text, QuoteLevel::Full),
+                    "text&lt;&quot;&apos;&amp;&gt; \t\n\rtext"
                 );
             }
 
@@ -719,11 +719,11 @@ mod tests {
             fn double_quote_attr() {
                 assert_eq!(
                     escape_list(
-                        "text<\"'&> \t\r\ntext",
+                        "text<\"'&> \t\n\rtext",
                         QuoteTarget::DoubleQAttr,
                         QuoteLevel::Full
                     ),
-                    "text&lt;&quot;&apos;&amp;&gt; \t\r\ntext"
+                    "text&lt;&quot;&apos;&amp;&gt; \t\n\rtext"
                 );
             }
 
@@ -731,11 +731,11 @@ mod tests {
             fn single_quote_attr() {
                 assert_eq!(
                     escape_list(
-                        "text<\"'&> \t\r\ntext",
+                        "text<\"'&> \t\n\rtext",
                         QuoteTarget::SingleQAttr,
                         QuoteLevel::Full
                     ),
-                    "text&lt;&quot;&apos;&amp;&gt; \t\r\ntext"
+                    "text&lt;&quot;&apos;&amp;&gt; \t\n\rtext"
                 );
             }
         }
@@ -748,11 +748,11 @@ mod tests {
             fn text() {
                 assert_eq!(
                     escape_list(
-                        "text<\"'&> \t\r\ntext",
+                        "text<\"'&> \t\n\rtext",
                         QuoteTarget::Text,
                         QuoteLevel::Partial
                     ),
-                    "text&lt;\"'&amp;&gt; \t\r\ntext"
+                    "text&lt;\"'&amp;&gt; \t\n\rtext"
                 );
             }
 
@@ -760,11 +760,11 @@ mod tests {
             fn double_quote_attr() {
                 assert_eq!(
                     escape_list(
-                        "text<\"'&> \t\r\ntext",
+                        "text<\"'&> \t\n\rtext",
                         QuoteTarget::DoubleQAttr,
                         QuoteLevel::Partial
                     ),
-                    "text&lt;&quot;'&amp;&gt; \t\r\ntext"
+                    "text&lt;&quot;'&amp;&gt; \t\n\rtext"
                 );
             }
 
@@ -772,11 +772,11 @@ mod tests {
             fn single_quote_attr() {
                 assert_eq!(
                     escape_list(
-                        "text<\"'&> \t\r\ntext",
+                        "text<\"'&> \t\n\rtext",
                         QuoteTarget::SingleQAttr,
                         QuoteLevel::Partial
                     ),
-                    "text&lt;\"&apos;&amp;&gt; \t\r\ntext"
+                    "text&lt;\"&apos;&amp;&gt; \t\n\rtext"
                 );
             }
         }
@@ -789,11 +789,11 @@ mod tests {
             fn text() {
                 assert_eq!(
                     escape_list(
-                        "text<\"'&> \t\r\ntext",
+                        "text<\"'&> \t\n\rtext",
                         QuoteTarget::Text,
                         QuoteLevel::Minimal
                     ),
-                    "text&lt;\"'&amp;> \t\r\ntext"
+                    "text&lt;\"'&amp;> \t\n\rtext"
                 );
             }
 
@@ -801,11 +801,11 @@ mod tests {
             fn double_quote_attr() {
                 assert_eq!(
                     escape_list(
-                        "text<\"'&> \t\r\ntext",
+                        "text<\"'&> \t\n\rtext",
                         QuoteTarget::DoubleQAttr,
                         QuoteLevel::Minimal
                     ),
-                    "text&lt;&quot;'&amp;> \t\r\ntext"
+                    "text&lt;&quot;'&amp;> \t\n\rtext"
                 );
             }
 
@@ -813,11 +813,11 @@ mod tests {
             fn single_quote_attr() {
                 assert_eq!(
                     escape_list(
-                        "text<\"'&> \t\r\ntext",
+                        "text<\"'&> \t\n\rtext",
                         QuoteTarget::SingleQAttr,
                         QuoteLevel::Minimal
                     ),
-                    "text&lt;\"&apos;&amp;> \t\r\ntext"
+                    "text&lt;\"&apos;&amp;> \t\n\rtext"
                 );
             }
         }
@@ -925,7 +925,7 @@ mod tests {
 
         err!(seq: vec![1, 2, 3]
             => Unsupported("sequence cannot be serialized as an `xs:list` item"));
-        err!(tuple: ("<\"&'>", "with\t\r\n spaces", 3usize)
+        err!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
             => Unsupported("tuple cannot be serialized as an `xs:list` item"));
         err!(tuple_struct: Tuple("first", 42)
             => Unsupported("tuple struct `Tuple` cannot be serialized as an `xs:list` item"));
@@ -1043,7 +1043,7 @@ mod tests {
         serialize_as!(seq_empty: Vec::<usize>::new() => "");
         serialize_as!(seq_with_1_empty_str: vec![""] => "");
         serialize_as!(seq_with_2_empty_strs: vec!["", ""] => " ");
-        serialize_as!(tuple: ("<\"&'>", "with\t\r\n spaces", 3usize)
+        serialize_as!(tuple: ("<\"&'>", "with\t\n\r spaces", 3usize)
             => "&lt;&quot;&amp;&apos;&gt; with&#9;&#10;&#13;&#32;spaces 3");
         serialize_as!(tuple_struct: Tuple("first", 42) => "first 42");
         err!(enum_tuple: Enum::Tuple("first", 42)
diff --git a/src/utils.rs b/src/utils.rs
index 185cff4..75f4ced 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -6,11 +6,12 @@ use serde::de::{Deserialize, Deserializer, Error, Visitor};
 #[cfg(feature = "serialize")]
 use serde::ser::{Serialize, Serializer};
 
+#[allow(clippy::ptr_arg)]
 pub fn write_cow_string(f: &mut Formatter, cow_string: &Cow<[u8]>) -> fmt::Result {
     match cow_string {
         Cow::Owned(s) => {
             write!(f, "Owned(")?;
-            write_byte_string(f, &s)?;
+            write_byte_string(f, s)?;
         }
         Cow::Borrowed(s) => {
             write!(f, "Borrowed(")?;
@@ -149,7 +150,7 @@ mod tests {
     #[test]
     fn write_byte_string0() {
         let bytes = ByteBuf(vec![10, 32, 32, 32, 32, 32, 32, 32, 32]);
-        assert_eq!(format!("{:?}", bytes), "\"0xA        \"".to_owned());
+        assert_eq!(format!("{:?}", bytes), "\"0xA        \"");
     }
 
     #[test]
@@ -160,7 +161,7 @@ mod tests {
         ]);
         assert_eq!(
             format!("{:?}", bytes),
-            r##""http://www.w3.org/2002/07/owl#""##.to_owned()
+            r##""http://www.w3.org/2002/07/owl#""##
         );
     }
 
@@ -169,6 +170,6 @@ mod tests {
         let bytes = ByteBuf(vec![
             67, 108, 97, 115, 115, 32, 73, 82, 73, 61, 34, 35, 66, 34,
         ]);
-        assert_eq!(format!("{:?}", bytes), r##""Class IRI=\"#B\"""##.to_owned());
+        assert_eq!(format!("{:?}", bytes), r##""Class IRI=\"#B\"""##);
     }
 }
diff --git a/src/writer.rs b/src/writer.rs
index 2c633c7..781a728 100644
--- a/src/writer.rs
+++ b/src/writer.rs
@@ -3,7 +3,7 @@
 use std::io::Write;
 
 use crate::encoding::UTF8_BOM;
-use crate::errors::{Error, Result};
+use crate::errors::Result;
 use crate::events::{attributes::Attribute, BytesCData, BytesStart, BytesText, Event};
 
 /// XML writer. Writes XML [`Event`]s to a [`std::io::Write`] implementor.
@@ -163,15 +163,15 @@ impl<W: Write> Writer<W> {
     /// Writes bytes
     #[inline]
     pub(crate) fn write(&mut self, value: &[u8]) -> Result<()> {
-        self.writer.write_all(value).map_err(Error::Io)
+        self.writer.write_all(value).map_err(Into::into)
     }
 
     #[inline]
     fn write_wrapped(&mut self, before: &[u8], value: &[u8], after: &[u8]) -> Result<()> {
         if let Some(ref i) = self.indent {
             if i.should_line_break {
-                self.writer.write_all(b"\n").map_err(Error::Io)?;
-                self.writer.write_all(i.current()).map_err(Error::Io)?;
+                self.writer.write_all(b"\n")?;
+                self.writer.write_all(i.current())?;
             }
         }
         self.write(before)?;
@@ -193,8 +193,8 @@ impl<W: Write> Writer<W> {
     /// [`new_with_indent`]: Self::new_with_indent
     pub fn write_indent(&mut self) -> Result<()> {
         if let Some(ref i) = self.indent {
-            self.writer.write_all(b"\n").map_err(Error::Io)?;
-            self.writer.write_all(i.current()).map_err(Error::Io)?;
+            self.writer.write_all(b"\n")?;
+            self.writer.write_all(i.current())?;
         }
         Ok(())
     }


Test patch:
diff --git a/tests/issues.rs b/tests/issues.rs
new file mode 100644
index 0000000..a19355b
--- /dev/null
+++ b/tests/issues.rs
@@ -0,0 +1,107 @@
+//! Regression tests found in various issues.
+//!
+//! Name each module / test as `issue<GH number>` and keep sorted by issue number
+
+use std::sync::mpsc;
+
+use quick_xml::events::{BytesStart, Event};
+use quick_xml::name::QName;
+use quick_xml::reader::Reader;
+use quick_xml::Error;
+
+/// Regression test for https://github.com/tafia/quick-xml/issues/115
+#[test]
+fn issue115() {
+    let mut r = Reader::from_str("<tag1 attr1='line 1\nline 2'></tag1>");
+    match r.read_event() {
+        Ok(Event::Start(e)) if e.name() == QName(b"tag1") => {
+            let v = e.attributes().map(|a| a.unwrap().value).collect::<Vec<_>>();
+            assert_eq!(v[0].clone().into_owned(), b"line 1\nline 2");
+        }
+        _ => (),
+    }
+}
+
+/// Regression test for https://github.com/tafia/quick-xml/issues/360
+#[test]
+fn issue360() {
+    let (tx, rx) = mpsc::channel::<Event>();
+
+    std::thread::spawn(move || {
+        let mut r = Reader::from_str("<tag1 attr1='line 1\nline 2'></tag1>");
+        loop {
+            let event = r.read_event().unwrap();
+            if event == Event::Eof {
+                tx.send(event).unwrap();
+                break;
+            } else {
+                tx.send(event).unwrap();
+            }
+        }
+    });
+    for event in rx.iter() {
+        println!("{:?}", event);
+    }
+}
+
+/// Regression test for https://github.com/tafia/quick-xml/issues/514
+mod issue514 {
+    use super::*;
+    use pretty_assertions::assert_eq;
+
+    /// Check that there is no unexpected error
+    #[test]
+    fn no_mismatch() {
+        let mut reader = Reader::from_str("<some-tag><html>...</html></some-tag>");
+
+        let outer_start = BytesStart::new("some-tag");
+        let outer_end = outer_start.to_end().into_owned();
+
+        let html_start = BytesStart::new("html");
+        let html_end = html_start.to_end().into_owned();
+
+        assert_eq!(reader.read_event().unwrap(), Event::Start(outer_start));
+        assert_eq!(reader.read_event().unwrap(), Event::Start(html_start));
+
+        reader.check_end_names(false);
+
+        assert_eq!(reader.read_text(html_end.name()).unwrap(), "...");
+
+        reader.check_end_names(true);
+
+        assert_eq!(reader.read_event().unwrap(), Event::End(outer_end));
+        assert_eq!(reader.read_event().unwrap(), Event::Eof);
+    }
+
+    /// Canary check that legitimate error is reported
+    #[test]
+    fn mismatch() {
+        let mut reader = Reader::from_str("<some-tag><html>...</html></other-tag>");
+
+        let outer_start = BytesStart::new("some-tag");
+
+        let html_start = BytesStart::new("html");
+        let html_end = html_start.to_end().into_owned();
+
+        assert_eq!(reader.read_event().unwrap(), Event::Start(outer_start));
+        assert_eq!(reader.read_event().unwrap(), Event::Start(html_start));
+
+        reader.check_end_names(false);
+
+        assert_eq!(reader.read_text(html_end.name()).unwrap(), "...");
+
+        reader.check_end_names(true);
+
+        match reader.read_event() {
+            Err(Error::EndEventMismatch { expected, found }) => {
+                assert_eq!(expected, "some-tag");
+                assert_eq!(found, "other-tag");
+            }
+            x => panic!(
+                r#"Expected `Err(EndEventMismatch("some-tag", "other-tag")))`, but found {:?}"#,
+                x
+            ),
+        }
+        assert_eq!(reader.read_event().unwrap(), Event::Eof);
+    }
+}
diff --git a/tests/serde-de.rs b/tests/serde-de.rs
index 7ec1426..f78c212 100644
--- a/tests/serde-de.rs
+++ b/tests/serde-de.rs
@@ -30,19 +30,6 @@ where
     result
 }
 
-#[test]
-fn string_borrow() {
-    #[derive(Debug, Deserialize, PartialEq)]
-    struct BorrowedText<'a> {
-        #[serde(rename = "$text")]
-        text: &'a str,
-    }
-
-    let borrowed_item: BorrowedText = from_str("<text>Hello world</text>").unwrap();
-
-    assert_eq!(borrowed_item.text, "Hello world");
-}
-
 /// Tests for deserializing into specially named field `$text` which represent
 /// textual content of an XML element
 mod text {
@@ -4857,6 +4844,86 @@ mod struct_ {
         );
     }
 
+    /// Checks that excess data before the struct correctly handled.
+    /// Any data not allowed before the struct
+    mod excess_data_before {
+        use super::*;
+        use pretty_assertions::assert_eq;
+
+        /// Space-only text events does not treated as data
+        #[test]
+        fn text_spaces_only() {
+            let data: Elements = from_str(
+                // Comment for prevent unnecessary formatting - we use the same style in all tests
+                " \t\n\r<root><float>42</float><string>answer</string></root>",
+            )
+            .unwrap();
+            assert_eq!(
+                data,
+                Elements {
+                    float: 42.0,
+                    string: "answer".into()
+                }
+            );
+        }
+
+        /// Text events with non-space characters are not allowed
+        #[test]
+        fn text_non_spaces() {
+            match from_str::<Elements>(
+                "\nexcess text\t<root><float>42</float><string>answer</string></root>",
+            ) {
+                Err(DeError::ExpectedStart) => (),
+                x => panic!("Expected Err(ExpectedStart), but got {:?}", x),
+            };
+        }
+
+        /// CDATA events are not allowed
+        #[test]
+        fn cdata() {
+            match from_str::<Elements>(
+                "<![CDATA[excess cdata]]><root><float>42</float><string>answer</string></root>",
+            ) {
+                Err(DeError::ExpectedStart) => (),
+                x => panic!("Expected Err(ExpectedStart), but got {:?}", x),
+            };
+        }
+
+        /// Comments are ignored, so they are allowed
+        #[test]
+        fn comment() {
+            let data: Elements = from_str(
+                // Comment for prevent unnecessary formatting - we use the same style in all tests
+                "<!--comment--><root><float>42</float><string>answer</string></root>",
+            )
+            .unwrap();
+            assert_eq!(
+                data,
+                Elements {
+                    float: 42.0,
+                    string: "answer".into()
+                }
+            );
+        }
+
+        /// Processing instructions are ignored, so they are allowed
+        #[test]
+        fn pi() {
+            let data: Elements = from_str(
+                // Comment for prevent unnecessary formatting - we use the same style in all tests
+                "<?pi?><root><float>42</float><string>answer</string></root>",
+            )
+            .unwrap();
+            assert_eq!(
+                data,
+                Elements {
+                    float: 42.0,
+                    string: "answer".into()
+                }
+            );
+        }
+    }
+
     maplike_errors!(Attributes, Mixed);
 }
 
@@ -5004,6 +5071,8 @@ mod enum_ {
         float: String,
     }
 
+    /// Enum tag selector is a name of the `<element>` or text / CDATA content
+    /// for a `$text` variant
     mod externally_tagged {
         use super::*;
         use pretty_assertions::assert_eq;
@@ -5202,8 +5271,142 @@ mod enum_ {
                 );
             }
         }
+
+        /// Test deserialization of the specially named variant `$text`
+        mod text {
+            use super::*;
+
+            mod unit {
+                use super::*;
+                use pretty_assertions::assert_eq;
+
+                #[derive(Debug, Deserialize, PartialEq)]
+                enum Text {
+                    #[serde(rename = "$text")]
+                    Unit,
+                }
+
+                #[test]
+                fn text() {
+                    let data: Text = from_str(" text ").unwrap();
+                    assert_eq!(data, Text::Unit);
+                }
+
+                #[test]
+                fn cdata() {
+                    let data: Text = from_str("<![CDATA[ cdata ]]>").unwrap();
+                    assert_eq!(data, Text::Unit);
+                }
+
+                #[test]
+                #[ignore = "awaiting fix of https://github.com/tafia/quick-xml/issues/474"]
+                fn mixed() {
+                    let data: Text = from_str(" te <![CDATA[ cdata ]]> xt ").unwrap();
+                    assert_eq!(data, Text::Unit);
+                }
+            }
+
+            mod newtype {
+                use super::*;
+                use pretty_assertions::assert_eq;
+
+                #[derive(Debug, Deserialize, PartialEq)]
+                enum Text {
+                    #[serde(rename = "$text")]
+                    Newtype(String),
+                }
+
+                #[test]
+                fn text() {
+                    let data: Text = from_str(" text ").unwrap();
+                    assert_eq!(data, Text::Newtype("text".into()));
+                }
+
+                #[test]
+                fn cdata() {
+                    let data: Text = from_str("<![CDATA[ cdata ]]>").unwrap();
+                    assert_eq!(data, Text::Newtype(" cdata ".into()));
+                }
+
+                #[test]
+                #[ignore = "awaiting fix of https://github.com/tafia/quick-xml/issues/474"]
+                fn mixed() {
+                    let data: Text = from_str(" te <![CDATA[ cdata ]]> xt ").unwrap();
+                    assert_eq!(data, Text::Newtype("te  cdata  xt".into()));
+                }
+            }
+
+            /// Tuple variant deserialized as an `xs:list`, that is why spaces
+            /// are trimmed even in CDATA sections
+            mod tuple {
+                use super::*;
+                use pretty_assertions::assert_eq;
+
+                #[derive(Debug, Deserialize, PartialEq)]
+                enum Text {
+                    #[serde(rename = "$text")]
+                    Tuple(f64, String),
+                }
+
+                #[test]
+                fn text() {
+                    let data: Text = from_str(" 4.2 text ").unwrap();
+                    assert_eq!(data, Text::Tuple(4.2, "text".into()));
+                }
+
+                #[test]
+                fn cdata() {
+                    let data: Text = from_str("<![CDATA[ 4.2 cdata ]]>").unwrap();
+                    assert_eq!(data, Text::Tuple(4.2, "cdata".into()));
+                }
+
+                #[test]
+                #[ignore = "awaiting fix of https://github.com/tafia/quick-xml/issues/474"]
+                fn mixed() {
+                    let data: Text = from_str(" 4.2 <![CDATA[ cdata ]]>").unwrap();
+                    assert_eq!(data, Text::Tuple(4.2, "cdata".into()));
+                }
+            }
+
+            /// Struct variant cannot be directly deserialized from `Text` / `CData` events
+            mod struct_ {
+                use super::*;
+
+                #[derive(Debug, Deserialize, PartialEq)]
+                enum Text {
+                    #[serde(rename = "$text")]
+                    Struct { float: f64, string: String },
+                }
+
+                #[test]
+                fn text() {
+                    match from_str::<Text>(" text ") {
+                        Err(DeError::Unsupported(_)) => {}
+                        x => panic!("Expected `Err(Unsupported(_))`, but found {:?}", x),
+                    }
+                }
+
+                #[test]
+                fn cdata() {
+                    match from_str::<Text>("<![CDATA[ cdata ]]>") {
+                        Err(DeError::Unsupported(_)) => {}
+                        x => panic!("Expected `Err(Unsupported(_))`, but found {:?}", x),
+                    }
+                }
+
+                #[test]
+                fn mixed() {
+                    match from_str::<Text>(" te <![CDATA[ cdata ]]> xt ") {
+                        Err(DeError::Unsupported(_)) => {}
+                        x => panic!("Expected `Err(Unsupported(_))`, but found {:?}", x),
+                    }
+                }
+            }
+        }
     }
 
+    /// Enum tag selector either an attribute "tag", or a tag "tag".
+    /// `$text` variant could be defined, but that name has no special meaning
     mod internally_tagged {
         use super::*;
 
@@ -5301,7 +5504,7 @@ mod enum_ {
             fn attributes() {
                 let data: NodeAttr = from_str(
                     // Comment for prevent unnecessary formatting - we use the same style in all tests
-                    r#"<root tag="Newtype" value="true"/>"#,
+                    r#"<root tag="Newtype"><value>true</value></root>"#,
                 )
                 .unwrap();
                 assert_eq!(data, NodeAttr::Newtype(NewtypeContent { value: true }));
@@ -5419,6 +5622,8 @@ mod enum_ {
         }
     }
 
+    /// Enum tag selector either an attribute "tag", or a tag "tag".
+    /// `$text` variant could be defined, but that name has no special meaning
     mod adjacently_tagged {
         use super::*;
 
@@ -5676,6 +5881,8 @@ mod enum_ {
         }
     }
 
+    /// Enum tags does not exist.
+    /// `$text` variant could be defined, but that name has no special meaning
     mod untagged {
         use super::*;
         use pretty_assertions::assert_eq;
@@ -5993,10 +6200,13 @@ mod xml_schema_lists {
             list!(bool_: bool = "<root>true false  true</root>" => vec![true, false, true]);
             list!(char_: char = "<root>4 2  j</root>" => vec!['4', '2', 'j']);
 
+            // Expanding of entity references happens before list parsing
+            // This is confirmed by XmlBeans (mature Java library) as well
             list!(string: String = "<root>first second  third&#x20;3</root>" => vec![
                 "first".to_string(),
                 "second".to_string(),
-                "third 3".to_string(),
+                "third".to_string(),
+                "3".to_string(),
             ]);
             err!(byte_buf: ByteBuf = "<root>first second  third&#x20;3</root>"
                 => Unsupported("byte arrays are not supported as `xs:list` items"));
@@ -6067,3 +6277,126 @@ fn from_str_should_ignore_encoding() {
         }
     );
 }
+
+/// Checks that deserializer is able to borrow data from the input
+mod borrow {
+    use super::*;
+
+    /// Struct that should borrow input to be able to deserialize successfully.
+    /// serde implicitly borrow `&str` and `&[u8]` even without `#[serde(borrow)]`
+    #[derive(Debug, Deserialize, PartialEq)]
+    struct BorrowedElement<'a> {
+        string: &'a str,
+    }
+
+    /// Struct that should borrow input to be able to deserialize successfully.
+    /// serde implicitly borrow `&str` and `&[u8]` even without `#[serde(borrow)]`
+    #[derive(Debug, Deserialize, PartialEq)]
+    struct BorrowedAttribute<'a> {
+        #[serde(rename = "@string")]
+        string: &'a str,
+    }
+
+    /// Deserialization of all XML's in that module expected to pass because
+    /// unescaping is not required, so deserialized `Borrowed*` types can hold
+    /// references to the original buffer with an XML text
+    mod non_escaped {
+        use super::*;
+        use pretty_assertions::assert_eq;
+
+        #[test]
+        fn top_level() {
+            let data: &str = from_str(r#"<root>without escape sequences</root>"#).unwrap();
+            assert_eq!(data, "without escape sequences",);
+        }
+
+        #[test]
+        fn element() {
+            let data: BorrowedElement = from_str(
+                r#"
+                <root>
+                    <string>without escape sequences</string>
+                </root>"#,
+            )
+            .unwrap();
+            assert_eq!(
+                data,
+                BorrowedElement {
+                    string: "without escape sequences",
+                }
+            );
+        }
+
+        #[test]
+        fn attribute() {
+            let data: BorrowedAttribute =
+                from_str(r#"<root string="without escape sequences"/>"#).unwrap();
+            assert_eq!(
+                data,
+                BorrowedAttribute {
+                    string: "without escape sequences",
+                }
+            );
+        }
+    }
+
+    /// Deserialization of all XML's in that module expected to fail because
+    /// values requires unescaping that will lead to allocating an internal
+    /// buffer by deserializer, but the `Borrowed*` types couldn't take ownership
+    /// on it.
+    ///
+    /// The same behavior demonstrates the `serde_json` crate
+    mod escaped {
+        use super::*;
+        use pretty_assertions::assert_eq;
+
+        #[test]
+        fn top_level() {
+            match from_str::<&str>(
+                r#"<root>with escape sequence: &lt;</root>"#,
+            ) {
+                Err(DeError::Custom(reason)) => assert_eq!(
+                    reason,
+                    "invalid type: string \"with escape sequence: <\", expected a borrowed string"
+                ),
+                e => panic!(
+                    "Expected `Err(Custom(invalid type: string \"with escape sequence: <\", expected a borrowed string))`, but found {:?}",
+                    e
+                ),
+            }
+        }
+
+        #[test]
+        fn element() {
+            match from_str::<BorrowedElement>(
+                r#"
+                <root>
+                    <string>with escape sequence: &lt;</string>
+                </root>"#,
+            ) {
+                Err(DeError::Custom(reason)) => assert_eq!(
+                    reason,
+                    "invalid type: string \"with escape sequence: <\", expected a borrowed string"
+                ),
+                e => panic!(
+                    "Expected `Err(Custom(invalid type: string \"with escape sequence: <\", expected a borrowed string))`, but found {:?}",
+                    e
+                ),
+            }
+        }
+
+        #[test]
+        fn attribute() {
+            match from_str::<BorrowedAttribute>(r#"<root string="with &quot;escape&quot; sequences"/>"#) {
+                Err(DeError::Custom(reason)) => assert_eq!(
+                    reason,
+                    "invalid type: string \"with \\\"escape\\\" sequences\", expected a borrowed string"
+                ),
+                e => panic!(
+                    "Expected `Err(Custom(invalid type: string \"with \"escape\" sequences\", expected a borrowed string))`, but found {:?}",
+                    e
+                ),
+            }
+        }
+    }
+}
diff --git a/tests/serde-issues.rs b/tests/serde-issues.rs
new file mode 100644
index 0000000..223183f
--- /dev/null
+++ b/tests/serde-issues.rs
@@ -0,0 +1,337 @@
+//! Regression tests found in various issues with serde integration.
+//!
+//! Name each module / test as `issue<GH number>` and keep sorted by issue number
+
+use pretty_assertions::assert_eq;
+use quick_xml::de::from_str;
+use quick_xml::se::to_string;
+use serde::{Deserialize, Serialize};
+use std::collections::HashMap;
+
+/// Regression tests for https://github.com/tafia/quick-xml/issues/252.
+mod issue252 {
+    use super::*;
+    use pretty_assertions::assert_eq;
+
+    #[test]
+    fn attributes() {
+        #[derive(Serialize, Debug, PartialEq)]
+        struct OptionalAttributes {
+            #[serde(rename = "@a")]
+            a: Option<&'static str>,
+
+            #[serde(rename = "@b")]
+            #[serde(skip_serializing_if = "Option::is_none")]
+            b: Option<&'static str>,
+        }
+
+        assert_eq!(
+            to_string(&OptionalAttributes { a: None, b: None }).unwrap(),
+            r#"<OptionalAttributes a=""/>"#
+        );
+        assert_eq!(
+            to_string(&OptionalAttributes {
+                a: Some(""),
+                b: Some("")
+            })
+            .unwrap(),
+            r#"<OptionalAttributes a="" b=""/>"#
+        );
+        assert_eq!(
+            to_string(&OptionalAttributes {
+                a: Some("a"),
+                b: Some("b")
+            })
+            .unwrap(),
+            r#"<OptionalAttributes a="a" b="b"/>"#
+        );
+    }
+
+    #[test]
+    fn elements() {
+        #[derive(Serialize, Debug, PartialEq)]
+        struct OptionalElements {
+            a: Option<&'static str>,
+
+            #[serde(skip_serializing_if = "Option::is_none")]
+            b: Option<&'static str>,
+        }
+
+        assert_eq!(
+            to_string(&OptionalElements { a: None, b: None }).unwrap(),
+            r#"<OptionalElements><a/></OptionalElements>"#
+        );
+        assert_eq!(
+            to_string(&OptionalElements {
+                a: Some(""),
+                b: Some("")
+            })
+            .unwrap(),
+            r#"<OptionalElements><a/><b/></OptionalElements>"#
+        );
+        assert_eq!(
+            to_string(&OptionalElements {
+                a: Some("a"),
+                b: Some("b")
+            })
+            .unwrap(),
+            r#"<OptionalElements><a>a</a><b>b</b></OptionalElements>"#
+        );
+    }
+}
+
+/// Regression test for https://github.com/tafia/quick-xml/issues/343.
+#[test]
+fn issue343() {
+    #[derive(Debug, Deserialize, Serialize, PartialEq)]
+    struct Users {
+        users: HashMap<String, User>,
+    }
+    #[derive(Debug, Deserialize, Serialize, PartialEq)]
+    struct Max(u16);
+
+    #[derive(Debug, Deserialize, Serialize, PartialEq)]
+    struct User {
+        max: Max,
+    }
+
+    let xml = "<Users>\
+                        <users>\
+                            <roger>\
+                                <max>10</max>\
+                            </roger>\
+                        </users>\
+                    </Users>";
+    let users: Users = from_str(xml).unwrap();
+
+    assert_eq!(
+        users,
+        Users {
+            users: HashMap::from([("roger".to_string(), User { max: Max(10) })]),
+        }
+    );
+    assert_eq!(to_string(&users).unwrap(), xml);
+}
+
+/// Regression test for https://github.com/tafia/quick-xml/issues/349.
+#[test]
+fn issue349() {
+    #[derive(Debug, Deserialize, Serialize, PartialEq)]
+    struct Entity {
+        id: Id,
+    }
+    #[derive(Debug, Deserialize, Serialize, PartialEq)]
+    struct Id {
+        #[serde(rename = "$value")]
+        content: Enum,
+    }
+    #[derive(Debug, Deserialize, Serialize, PartialEq)]
+    #[serde(rename_all = "kebab-case")]
+    enum Enum {
+        A(String),
+        B(String),
+    }
+
+    assert_eq!(
+        from_str::<Entity>("<entity><id><a>Id</a></id></entity>").unwrap(),
+        Entity {
+            id: Id {
+                content: Enum::A("Id".to_string()),
+            }
+        }
+    );
+}
+
+/// Regression test for https://github.com/tafia/quick-xml/issues/429.
+#[test]
+fn issue429() {
+    #[derive(Debug, Deserialize, Serialize, PartialEq)]
+    enum State {
+        A,
+        B,
+        C,
+    }
+
+    #[derive(Debug, Deserialize, Serialize, PartialEq)]
+    struct StateOuter {
+        #[serde(rename = "$text")]
+        state: State,
+    }
+
+    #[derive(Debug, Deserialize, Serialize, PartialEq)]
+    pub struct Root {
+        state: StateOuter,
+    }
+
+    assert_eq!(
+        from_str::<Root>("<root><state>B</state></root>").unwrap(),
+        Root {
+            state: StateOuter { state: State::B }
+        }
+    );
+
+    assert_eq!(
+        to_string(&Root {
+            state: StateOuter { state: State::B }
+        })
+        .unwrap(),
+        "<Root><state>B</state></Root>"
+    );
+}
+
+/// Regression test for https://github.com/tafia/quick-xml/issues/500.
+#[test]
+fn issue500() {
+    #[derive(Debug, Deserialize, Serialize, PartialEq)]
+    struct TagOne {}
+
+    #[derive(Debug, Deserialize, Serialize, PartialEq)]
+    struct TagTwo {}
+
+    #[derive(Debug, Deserialize, Serialize, PartialEq)]
+    enum Tag {
+        TagOne(TagOne),
+        TagTwo(TagTwo),
+    }
+
+    #[derive(Debug, Deserialize, Serialize, PartialEq)]
+    struct Root {
+        #[serde(rename = "$value", default)]
+        data: Vec<Tag>,
+    }
+
+    let data: Root = from_str(
+        "\
+        <root>\
+            <TagOne></TagOne>\
+            <TagTwo></TagTwo>\
+            <TagOne></TagOne>\
+        </root>\
+    ",
+    )
+    .unwrap();
+
+    assert_eq!(
+        data,
+        Root {
+            data: vec![
+                Tag::TagOne(TagOne {}),
+                Tag::TagTwo(TagTwo {}),
+                Tag::TagOne(TagOne {}),
+            ],
+        }
+    );
+
+    let data: Vec<Tag> = from_str(
+        "\
+        <TagOne></TagOne>\
+        <TagTwo></TagTwo>\
+        <TagOne></TagOne>\
+    ",
+    )
+    .unwrap();
+
+    assert_eq!(
+        data,
+        vec![
+            Tag::TagOne(TagOne {}),
+            Tag::TagTwo(TagTwo {}),
+            Tag::TagOne(TagOne {}),
+        ]
+    );
+}
+
+/// Regression test for https://github.com/tafia/quick-xml/issues/510.
+#[test]
+fn issue510() {
+    #[derive(Debug, PartialEq, Serialize, Deserialize)]
+    #[serde(rename = "ENTRY")]
+    struct Entry {
+        #[serde(rename = "CUE_V2")]
+        cues: Option<Vec<Cue>>,
+    }
+
+    #[derive(Debug, PartialEq, Serialize, Deserialize)]
+    // #[serde_with::serde_as]
+    struct Cue {
+        #[serde(rename = "@NAME")]
+        name: String,
+    }
+
+    let data: Entry = from_str(
+        "\
+        <ENTRY>\
+            <CUE_V2 NAME='foo'></CUE_V2>\
+            <CUE_V2 NAME='bar'></CUE_V2>\
+        </ENTRY>\
+    ",
+    )
+    .unwrap();
+
+    assert_eq!(
+        data,
+        Entry {
+            cues: Some(vec![
+                Cue {
+                    name: "foo".to_string(),
+                },
+                Cue {
+                    name: "bar".to_string(),
+                },
+            ]),
+        }
+    );
+}
+
+/// Regression test for https://github.com/tafia/quick-xml/issues/537.
+///
+/// This test checks that special `xmlns:xxx` attributes uses full name of
+/// an attribute (xmlns:xxx) as a field name instead of just local name of
+/// an attribute (xxx)
+mod issue537 {
+    use super::*;
+    use pretty_assertions::assert_eq;
+
+    #[derive(Debug, PartialEq, Deserialize, Serialize)]
+    struct Bindings<'a> {
+        /// Default namespace binding
+        #[serde(rename = "@xmlns")]
+        xmlns: &'a str,
+
+        /// Named namespace binding
+        #[serde(rename = "@xmlns:named")]
+        xmlns_named: &'a str,
+
+        /// Usual attribute
+        #[serde(rename = "@attribute")]
+        attribute: &'a str,
+    }
+
+    #[test]
+    fn de() {
+        assert_eq!(
+            from_str::<Bindings>(
+                r#"<Bindings xmlns="default" xmlns:named="named" attribute="attribute"/>"#
+            )
+            .unwrap(),
+            Bindings {
+                xmlns: "default",
+                xmlns_named: "named",
+                attribute: "attribute",
+            }
+        );
+    }
+
+    #[test]
+    fn se() {
+        assert_eq!(
+            to_string(&Bindings {
+                xmlns: "default",
+                xmlns_named: "named",
+                attribute: "attribute",
+            })
+            .unwrap(),
+            r#"<Bindings xmlns="default" xmlns:named="named" attribute="attribute"/>"#
+        );
+    }
+}
diff --git a/tests/serde-migrated.rs b/tests/serde-migrated.rs
index 4fdcb9b..6033d16 100644
--- a/tests/serde-migrated.rs
+++ b/tests/serde-migrated.rs
@@ -117,80 +117,6 @@ fn test_parse_string_not_trim() {
     test_parse_ok(&[("<bla>     </bla>", "     ".to_string())]);
 }
 
-#[test]
-#[ignore] // FIXME
-fn test_parse_enum() {
-    use Animal::*;
-
-    #[derive(PartialEq, Debug, Serialize, Deserialize)]
-    enum Animal {
-        Dog,
-        Frog(String),
-        Ant(Simple),
-        Cat { age: usize, name: String },
-    }
-
-    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_option() {
     test_parse_ok(&[
diff --git a/tests/unit_tests.rs b/tests/unit_tests.rs
index 4881ba0..502cd50 100644
--- a/tests/unit_tests.rs
+++ b/tests/unit_tests.rs
@@ -332,7 +332,7 @@ fn test_new_xml_decl_full() {
     let result = writer.into_inner();
     assert_eq!(
         String::from_utf8(result).expect("utf-8 output"),
-        "<?xml version=\"1.2\" encoding=\"utf-X\" standalone=\"yo\"?>".to_owned(),
+        "<?xml version=\"1.2\" encoding=\"utf-X\" standalone=\"yo\"?>",
         "writer output (LHS)"
     );
 }
@@ -347,7 +347,7 @@ fn test_new_xml_decl_standalone() {
     let result = writer.into_inner();
     assert_eq!(
         String::from_utf8(result).expect("utf-8 output"),
-        "<?xml version=\"1.2\" standalone=\"yo\"?>".to_owned(),
+        "<?xml version=\"1.2\" standalone=\"yo\"?>",
         "writer output (LHS)"
     );
 }
@@ -362,7 +362,7 @@ fn test_new_xml_decl_encoding() {
     let result = writer.into_inner();
     assert_eq!(
         String::from_utf8(result).expect("utf-8 output"),
-        "<?xml version=\"1.2\" encoding=\"utf-X\"?>".to_owned(),
+        "<?xml version=\"1.2\" encoding=\"utf-X\"?>",
         "writer output (LHS)"
     );
 }
@@ -377,7 +377,7 @@ fn test_new_xml_decl_version() {
     let result = writer.into_inner();
     assert_eq!(
         String::from_utf8(result).expect("utf-8 output"),
-        "<?xml version=\"1.2\"?>".to_owned(),
+        "<?xml version=\"1.2\"?>",
         "writer output (LHS)"
     );
 }
@@ -395,7 +395,7 @@ fn test_new_xml_decl_empty() {
     let result = writer.into_inner();
     assert_eq!(
         String::from_utf8(result).expect("utf-8 output"),
-        "<?xml version=\"\" encoding=\"\" standalone=\"\"?>".to_owned(),
+        "<?xml version=\"\" encoding=\"\" standalone=\"\"?>",
         "writer output (LHS)"
     );
 }
@@ -533,7 +533,7 @@ fn test_read_write_roundtrip_results_in_identity() -> Result<()> {
     }
 
     let result = writer.into_inner().into_inner();
-    assert_eq!(result, input.as_bytes());
+    assert_eq!(String::from_utf8(result).unwrap(), input);
     Ok(())
 }
 
@@ -559,7 +559,7 @@ fn test_read_write_roundtrip() -> Result<()> {
     }
 
     let result = writer.into_inner().into_inner();
-    assert_eq!(String::from_utf8(result).unwrap(), input.to_string());
+    assert_eq!(String::from_utf8(result).unwrap(), input);
     Ok(())
 }
 
@@ -589,7 +589,7 @@ fn test_read_write_roundtrip_escape_text() -> Result<()> {
     }
 
     let result = writer.into_inner().into_inner();
-    assert_eq!(String::from_utf8(result).unwrap(), input.to_string());
+    assert_eq!(String::from_utf8(result).unwrap(), input);
     Ok(())
 }
 
diff --git a/tests/xmlrs_reader_tests.rs b/tests/xmlrs_reader_tests.rs
index b5fc0bc..799bfcd 100644
--- a/tests/xmlrs_reader_tests.rs
+++ b/tests/xmlrs_reader_tests.rs
@@ -433,7 +433,7 @@ fn test_bytes(input: &[u8], output: &[u8], trim: bool) {
                 Ok(c) => format!("Characters({})", &c),
                 Err(err) => format!("FailedUnescape({:?}; {})", e.as_ref(), err),
             },
-            Ok((_, Event::Eof)) => format!("EndDocument"),
+            Ok((_, Event::Eof)) => "EndDocument".to_string(),
             Err(e) => format!("Error: {}", e),
         };
         if let Some((n, spec)) = spec_lines.next() {