//! ```
//! use serde::Deserialize;
//! use robinson::serde::from_str;
//!
//! #[derive(Deserialize)]
//! struct Record {
//!     field: String,
//! }
//!
//! let record = from_str::<Record>("<record><field>foobar</field></record>").unwrap();
//!
//! assert_eq!(record.field, "foobar");
//! ```
#[cfg(feature = "raw-node")]
mod raw_node;

use std::borrow::Cow;
use std::char::ParseCharError;
use std::error::Error as StdError;
use std::fmt;
use std::iter::{Peekable, once};
use std::marker::PhantomData;
use std::num::{NonZeroUsize, ParseFloatError, ParseIntError};
use std::str::{FromStr, ParseBoolError};

use serde_core::de;

use crate::{Attribute, Document, Error as XmlError, Node, strings::cmp_opt_names};

#[cfg(feature = "raw-node")]
pub use raw_node::RawNode;

pub fn from_str<T>(text: &str) -> Result<T, Box<Error>>
where
    T: de::DeserializeOwned,
{
    defaults().from_str(text)
}

pub fn from_doc<'de, 'input, T>(document: &'de Document<'input>) -> Result<T, Box<Error>>
where
    T: de::Deserialize<'de>,
{
    defaults().from_doc(document)
}

pub fn from_node<'de, 'input, T>(node: Node<'de, 'input>) -> Result<T, Box<Error>>
where
    T: de::Deserialize<'de>,
{
    defaults().from_node(node)
}

pub trait Options: Sized {
    #[allow(clippy::wrong_self_convention)]
    fn from_str<T>(self, text: &str) -> Result<T, Box<Error>>
    where
        T: de::DeserializeOwned,
    {
        let document = Document::parse(text).map_err(Error::ParseXml)?;
        self.from_doc(&document)
    }

    #[allow(clippy::wrong_self_convention)]
    fn from_doc<'de, 'input, T>(self, document: &'de Document<'input>) -> Result<T, Box<Error>>
    where
        T: de::Deserialize<'de>,
    {
        let node = document.root_element();
        self.from_node(node)
    }

    #[allow(clippy::wrong_self_convention)]
    fn from_node<'de, 'input, T>(self, node: Node<'de, 'input>) -> Result<T, Box<Error>>
    where
        T: de::Deserialize<'de>,
    {
        let len = node.document().len();

        let deserializer = Deserializer {
            source: Source::Node(node),
            temp: &mut Temp::new(len),
            options: PhantomData::<Self>,
        };

        T::deserialize(deserializer)
    }

    fn namespaces(self) -> Namespaces<Self> {
        Namespaces(PhantomData)
    }

    fn prefix_attr(self) -> PrefixAttr<Self> {
        PrefixAttr(PhantomData)
    }

    fn only_children(self) -> OnlyChildren<Self> {
        OnlyChildren(PhantomData)
    }

    #[doc(hidden)]
    const NAMESPACES: bool = false;

    #[doc(hidden)]
    const PREFIX_ATTR: bool = false;

    #[doc(hidden)]
    const ONLY_CHILDREN: bool = false;
}

#[doc(hidden)]
#[derive(Clone, Copy, Default, Debug)]
pub struct Defaults;

pub fn defaults() -> Defaults {
    Defaults
}

impl Options for Defaults {}

#[doc(hidden)]
#[derive(Clone, Copy, Default, Debug)]
pub struct Namespaces<O>(PhantomData<O>);

impl<O> Options for Namespaces<O>
where
    O: Options,
{
    const NAMESPACES: bool = true;
    const PREFIX_ATTR: bool = O::PREFIX_ATTR;
    const ONLY_CHILDREN: bool = O::ONLY_CHILDREN;
}

#[doc(hidden)]
#[derive(Clone, Copy, Default, Debug)]
pub struct PrefixAttr<O>(PhantomData<O>);

impl<O> Options for PrefixAttr<O>
where
    O: Options,
{
    const NAMESPACES: bool = O::NAMESPACES;
    const PREFIX_ATTR: bool = true;
    const ONLY_CHILDREN: bool = O::ONLY_CHILDREN;
}

#[doc(hidden)]
#[derive(Clone, Copy, Default, Debug)]
pub struct OnlyChildren<O>(PhantomData<O>);

impl<O> Options for OnlyChildren<O>
where
    O: Options,
{
    const NAMESPACES: bool = O::NAMESPACES;
    const PREFIX_ATTR: bool = O::PREFIX_ATTR;
    const ONLY_CHILDREN: bool = true;
}

struct Deserializer<'doc, 'input, 'temp, O> {
    source: Source<'doc, 'input>,
    temp: &'temp mut Temp,
    options: PhantomData<O>,
}

#[derive(Clone, Copy)]
enum Source<'doc, 'input> {
    Node(Node<'doc, 'input>),
    Attribute(Attribute<'doc, 'input>),
    Content(Node<'doc, 'input>),
}

impl Source<'_, '_> {
    fn name<'a, O>(&'a self, buffer: &'a mut String) -> &'a str
    where
        O: Options,
    {
        match self {
            Self::Node(node) => {
                let name = node.name().unwrap();

                match name.namespace {
                    Some(namespace) if O::NAMESPACES => {
                        buffer.clear();

                        buffer.reserve(namespace.len() + 2 + name.local.len());

                        buffer.push('{');
                        buffer.push_str(namespace);
                        buffer.push('}');

                        buffer.push_str(name.local);

                        &*buffer
                    }
                    _ => name.local,
                }
            }
            Self::Attribute(attr) => {
                let name = attr.name();

                match name.namespace {
                    Some(namespace) if O::NAMESPACES => {
                        buffer.clear();

                        if O::PREFIX_ATTR {
                            buffer.reserve(3 + namespace.len() + name.local.len());

                            buffer.push('@');
                        } else {
                            buffer.reserve(2 + namespace.len() + name.local.len());
                        }

                        buffer.push('{');
                        buffer.push_str(namespace);
                        buffer.push('}');

                        buffer.push_str(name.local);

                        &*buffer
                    }
                    _ => {
                        if O::PREFIX_ATTR {
                            buffer.clear();

                            buffer.reserve(1 + name.local.len());

                            buffer.push('@');
                            buffer.push_str(name.local);

                            &*buffer
                        } else {
                            name.local
                        }
                    }
                }
            }
            Self::Content(_) => "#content",
        }
    }
}

struct Temp {
    visited: Box<[usize]>,
    buffer: String,
}

impl Temp {
    fn new(len: NonZeroUsize) -> Self {
        let len = len.get().div_ceil(USIZE_BITS);

        Self {
            visited: (0..len).map(|_idx| 0).collect(),
            buffer: String::new(),
        }
    }

    fn set_visited(&mut self, node: usize) {
        let idx = node / USIZE_BITS;
        let bit = node % USIZE_BITS;

        self.visited[idx] |= 1 << bit;
    }

    fn is_visited(&self, node: usize) -> bool {
        let idx = node / USIZE_BITS;
        let bit = node % USIZE_BITS;

        self.visited[idx] & (1 << bit) != 0
    }
}

const USIZE_BITS: usize = usize::BITS as usize;

impl<'doc, 'input, O> Deserializer<'doc, 'input, '_, O>
where
    O: Options,
{
    fn name(&mut self) -> &str {
        self.source.name::<O>(&mut self.temp.buffer)
    }

    fn node(&self) -> Result<Node<'doc, 'input>, Box<Error>> {
        match self.source {
            Source::Node(node) | Source::Content(node) => Ok(node),
            Source::Attribute(_) => Error::MissingNode.into(),
        }
    }

    fn children(
        &self,
    ) -> Result<impl Iterator<Item = Source<'doc, 'input>> + use<'doc, 'input, O>, Box<Error>> {
        let node = self.node()?;

        let children = node
            .children()
            .filter(|node| node.is_element())
            .map(Source::Node);

        Ok(children)
    }

    fn children_and_attributes(
        &self,
    ) -> Result<impl Iterator<Item = Source<'doc, 'input>> + use<'doc, 'input, O>, Box<Error>> {
        let node = self.node()?;

        let children = node
            .children()
            .filter(|node| node.is_element())
            .map(Source::Node);

        let attributes = node.attributes().map(Source::Attribute);

        let content = once(Source::Content(node));

        Ok(children.chain(attributes).chain(content))
    }

    fn siblings(
        &self,
    ) -> Result<impl Iterator<Item = Node<'doc, 'input>> + use<'doc, 'input, O>, Box<Error>> {
        let node = self.node()?;
        let name = node.name();

        Ok(node.next_siblings().filter(move |node1| {
            let name1 = node1.name();

            if O::NAMESPACES {
                name == name1
            } else {
                cmp_opt_names(name.map(|name| name.local), name1.map(|name1| name1.local))
            }
        }))
    }

    fn text(&self) -> Cow<'doc, str> {
        match self.source {
            Source::Node(node) | Source::Content(node) => {
                node.child_text().unwrap_or(Cow::Borrowed(""))
            }
            Source::Attribute(attr) => Cow::Borrowed(attr.value()),
        }
    }

    fn parse<T>(&self, map_err: fn(T::Err) -> Error) -> Result<T, Box<Error>>
    where
        T: FromStr,
    {
        self.text()
            .trim()
            .parse()
            .map_err(|err| map_err(err).into())
    }
}

impl<'de, O> de::Deserializer<'de> for Deserializer<'de, '_, '_, O>
where
    O: Options,
{
    type Error = Box<Error>;

    fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_bool(self.parse(Error::ParseBool)?)
    }

    fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_i8(self.parse(Error::ParseInt)?)
    }

    fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_i16(self.parse(Error::ParseInt)?)
    }

    fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_i32(self.parse(Error::ParseInt)?)
    }

    fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_i64(self.parse(Error::ParseInt)?)
    }

    fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_u8(self.parse(Error::ParseInt)?)
    }

    fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_u16(self.parse(Error::ParseInt)?)
    }

    fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_u32(self.parse(Error::ParseInt)?)
    }

    fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_u64(self.parse(Error::ParseInt)?)
    }

    fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_f32(self.parse(Error::ParseFloat)?)
    }

    fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_f64(self.parse(Error::ParseFloat)?)
    }

    fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_char(self.parse(Error::ParseChar)?)
    }

    fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self.text() {
            Cow::Borrowed(text) => visitor.visit_borrowed_str(text),
            Cow::Owned(text) => visitor.visit_string(text),
        }
    }

    fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_str(visitor)
    }

    fn deserialize_bytes<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        Error::NotSupported.into()
    }

    fn deserialize_byte_buf<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        Error::NotSupported.into()
    }

    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_some(self)
    }

    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_unit()
    }

    fn deserialize_unit_struct<V>(
        self,
        _name: &'static str,
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_unit(visitor)
    }

    fn deserialize_newtype_struct<V>(
        self,
        _name: &'static str,
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_newtype_struct(self)
    }

    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_seq(SeqAccess {
            source: self.siblings()?,
            temp: self.temp,
            options: PhantomData::<O>,
        })
    }

    fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_seq(visitor)
    }

    fn deserialize_tuple_struct<V>(
        self,
        _name: &'static str,
        _len: usize,
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_seq(visitor)
    }

    fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        if O::ONLY_CHILDREN {
            visitor.visit_map(MapAccess {
                source: self.children()?.peekable(),
                temp: self.temp,
                options: PhantomData::<O>,
            })
        } else {
            visitor.visit_map(MapAccess {
                source: self.children_and_attributes()?.peekable(),
                temp: self.temp,
                options: PhantomData::<O>,
            })
        }
    }

    fn deserialize_struct<V>(
        self,
        #[allow(unused_variables)] name: &'static str,
        _fields: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        #[cfg(feature = "raw-node")]
        let res =
            raw_node::deserialize_struct(self, name, move |this| this.deserialize_map(visitor));

        #[cfg(not(feature = "raw-node"))]
        let res = self.deserialize_map(visitor);

        res
    }

    fn deserialize_enum<V>(
        self,
        _name: &'static str,
        variants: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        if O::ONLY_CHILDREN {
            visitor.visit_enum(EnumAccess {
                source: self.children()?,
                variants,
                temp: self.temp,
                options: PhantomData::<O>,
            })
        } else {
            visitor.visit_enum(EnumAccess {
                source: self.children_and_attributes()?,
                variants,
                temp: self.temp,
                options: PhantomData::<O>,
            })
        }
    }

    fn deserialize_identifier<V>(mut self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_str(self.name())
    }

    fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        Error::NotSupported.into()
    }

    fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_unit(visitor)
    }
}

struct SeqAccess<'doc, 'input, 'temp, I, O>
where
    I: Iterator<Item = Node<'doc, 'input>>,
    'input: 'doc,
{
    source: I,
    temp: &'temp mut Temp,
    options: PhantomData<O>,
}

impl<'de, 'input, I, O> de::SeqAccess<'de> for SeqAccess<'de, 'input, '_, I, O>
where
    I: Iterator<Item = Node<'de, 'input>>,
    O: Options,
{
    type Error = Box<Error>;

    fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
    where
        T: de::DeserializeSeed<'de>,
    {
        match self.source.next() {
            None => Ok(None),
            Some(node) => {
                self.temp.set_visited(node.id().get());

                let deserializer = Deserializer {
                    source: Source::Node(node),
                    temp: &mut *self.temp,
                    options: PhantomData::<O>,
                };
                seed.deserialize(deserializer).map(Some)
            }
        }
    }
}

struct MapAccess<'doc, 'input, 'temp, I, O>
where
    I: Iterator<Item = Source<'doc, 'input>>,
    'input: 'doc,
{
    source: Peekable<I>,
    temp: &'temp mut Temp,
    options: PhantomData<O>,
}

impl<'de, 'input, I, O> de::MapAccess<'de> for MapAccess<'de, 'input, '_, I, O>
where
    I: Iterator<Item = Source<'de, 'input>>,
    O: Options,
{
    type Error = Box<Error>;

    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
    where
        K: de::DeserializeSeed<'de>,
    {
        loop {
            match self.source.peek() {
                None => return Ok(None),
                Some(source) => {
                    if let Source::Node(node) = source
                        && self.temp.is_visited(node.id().get())
                    {
                        self.source.next().unwrap();
                        continue;
                    }

                    let deserailizer = Deserializer {
                        source: *source,
                        temp: &mut *self.temp,
                        options: PhantomData::<O>,
                    };
                    return seed.deserialize(deserailizer).map(Some);
                }
            }
        }
    }

    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
    where
        V: de::DeserializeSeed<'de>,
    {
        let source = self.source.next().unwrap();

        let deserializer = Deserializer {
            source,
            temp: &mut *self.temp,
            options: PhantomData::<O>,
        };
        seed.deserialize(deserializer)
    }
}

struct EnumAccess<'doc, 'input, 'temp, I, O>
where
    I: Iterator<Item = Source<'doc, 'input>>,
    'input: 'doc,
{
    source: I,
    variants: &'static [&'static str],
    temp: &'temp mut Temp,
    options: PhantomData<O>,
}

impl<'de, 'input, 'temp, I, O> de::EnumAccess<'de> for EnumAccess<'de, 'input, 'temp, I, O>
where
    I: Iterator<Item = Source<'de, 'input>>,
    O: Options,
{
    type Error = Box<Error>;
    type Variant = Deserializer<'de, 'input, 'temp, O>;

    fn variant_seed<V>(mut self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
    where
        V: de::DeserializeSeed<'de>,
    {
        let source = self
            .source
            .find(|source| {
                self.variants
                    .contains(&source.name::<O>(&mut self.temp.buffer))
            })
            .ok_or(Error::MissingChildOrAttribute)?;

        let deserializer = Deserializer {
            source,
            temp: &mut *self.temp,
            options: PhantomData::<O>,
        };
        let value = seed.deserialize(deserializer)?;

        let deserializer = Deserializer {
            source,
            temp: &mut *self.temp,
            options: PhantomData::<O>,
        };
        Ok((value, deserializer))
    }
}

impl<'de, O> de::VariantAccess<'de> for Deserializer<'de, '_, '_, O>
where
    O: Options,
{
    type Error = Box<Error>;

    fn unit_variant(self) -> Result<(), Self::Error> {
        Ok(())
    }

    fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
    where
        T: de::DeserializeSeed<'de>,
    {
        seed.deserialize(self)
    }

    fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        de::Deserializer::deserialize_tuple(self, len, visitor)
    }

    fn struct_variant<V>(
        self,
        fields: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        de::Deserializer::deserialize_struct(self, "", fields, visitor)
    }
}

#[derive(Debug)]
pub enum Error {
    MissingNode,
    MissingChildOrAttribute,
    ParseXml(Box<XmlError>),
    ParseBool(ParseBoolError),
    ParseInt(ParseIntError),
    ParseFloat(ParseFloatError),
    ParseChar(ParseCharError),
    NotSupported,
    Custom(String),
}

impl<T> From<Error> for Result<T, Box<Error>> {
    #[cold]
    #[inline(never)]
    fn from(err: Error) -> Self {
        Err(Box::new(err))
    }
}

impl de::Error for Box<Error> {
    #[cold]
    #[inline(never)]
    fn custom<T: fmt::Display>(msg: T) -> Self {
        Box::new(Error::Custom(msg.to_string()))
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Self::MissingNode => write!(fmt, "missing node"),
            Self::MissingChildOrAttribute => write!(fmt, "missing child or attribute"),
            Self::ParseXml(err) => write!(fmt, "XML parse error: {err}"),
            Self::ParseBool(err) => write!(fmt, "bool parse error: {err}"),
            Self::ParseInt(err) => write!(fmt, "int parse error: {err}"),
            Self::ParseFloat(err) => write!(fmt, "float parse error: {err}"),
            Self::ParseChar(err) => write!(fmt, "char parse error: {err}"),
            Self::NotSupported => write!(fmt, "not supported"),
            Self::Custom(msg) => write!(fmt, "custom error: {msg}"),
        }
    }
}

impl StdError for Error {
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        match self {
            Self::ParseXml(err) => Some(err),
            Self::ParseBool(err) => Some(err),
            Self::ParseInt(err) => Some(err),
            Self::ParseFloat(err) => Some(err),
            Self::ParseChar(err) => Some(err),
            _ => None,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use serde::Deserialize;

    #[test]
    fn parse_bool() {
        let val = from_str::<bool>("<root>false</root>").unwrap();
        assert!(!val);
        let val = from_str::<bool>("<root>\n\ttrue\n</root>").unwrap();
        assert!(val);

        let res = from_str::<bool>("<root>foobar</root>");
        assert!(matches!(*res.unwrap_err(), Error::ParseBool(_err)));
    }

    #[test]
    fn parse_char() {
        let val = from_str::<char>("<root>x</root>").unwrap();
        assert_eq!(val, 'x');
        let val = from_str::<char>("<root>\n\ty\n</root>").unwrap();
        assert_eq!(val, 'y');

        let res = from_str::<char>("<root>xyz</root>");
        assert!(matches!(*res.unwrap_err(), Error::ParseChar(_err)));
    }

    #[test]
    fn empty_text() {
        let val = from_str::<String>("<root></root>").unwrap();
        assert!(val.is_empty());
    }

    #[test]
    fn children_and_attributes() {
        #[derive(Deserialize)]
        struct Root {
            attr: i32,
            child: u64,
        }

        let val = from_str::<Root>(r#"<root attr="23"><child>42</child></root>"#).unwrap();
        assert_eq!(val.attr, 23);
        assert_eq!(val.child, 42);
    }

    #[test]
    fn children_with_attributes() {
        #[derive(Deserialize)]
        struct Root {
            child: Child,
        }

        #[derive(Deserialize)]
        struct Child {
            attr: i32,
            #[serde(rename = "#content")]
            text: u64,
        }

        let val = from_str::<Root>(r#"<root><child attr="23">42</child></root>"#).unwrap();
        assert_eq!(val.child.attr, 23);
        assert_eq!(val.child.text, 42);
    }

    #[test]
    fn multiple_children() {
        #[derive(Deserialize)]
        struct Root {
            child: Vec<i32>,
            another_child: String,
        }

        let val = from_str::<Root>(r#"<root><child>23</child><another_child>foobar</another_child><child>42</child></root>"#).unwrap();
        assert_eq!(val.child, [23, 42]);
        assert_eq!(val.another_child, "foobar");
    }

    #[test]
    fn multiple_lists_of_multiple_children() {
        #[derive(Deserialize)]
        struct Root {
            child: Vec<i32>,
            another_child: Vec<String>,
        }

        let val = from_str::<Root>(r#"<root><child>23</child><another_child>foo</another_child><child>42</child><another_child>bar</another_child></root>"#).unwrap();
        assert_eq!(val.child, [23, 42]);
        assert_eq!(val.another_child, ["foo", "bar"]);
    }

    #[test]
    fn zero_of_multiple_children() {
        #[derive(Deserialize)]
        struct Root {
            #[serde(default)]
            child: Vec<i32>,
        }

        let val = from_str::<Root>(r#"<root></root>"#).unwrap();
        assert_eq!(val.child, []);
    }

    #[test]
    fn optional_child() {
        #[derive(Deserialize)]
        struct Root {
            child: Option<f32>,
        }

        let val = from_str::<Root>(r#"<root><child>23.42</child></root>"#).unwrap();
        assert_eq!(val.child, Some(23.42));

        let val = from_str::<Root>(r#"<root></root>"#).unwrap();
        assert_eq!(val.child, None);
    }

    #[test]
    fn optional_attribute() {
        #[derive(Deserialize)]
        struct Root {
            attr: Option<f64>,
        }

        let val = from_str::<Root>(r#"<root attr="23.42"></root>"#).unwrap();
        assert_eq!(val.attr, Some(23.42));

        let val = from_str::<Root>(r#"<root></root>"#).unwrap();
        assert_eq!(val.attr, None);
    }

    #[test]
    fn child_variants() {
        #[derive(Debug, PartialEq, Deserialize)]
        enum Root {
            Foo(Foo),
            Bar(Bar),
        }

        #[derive(Debug, PartialEq, Deserialize)]
        struct Foo {
            attr: i64,
        }

        #[derive(Debug, PartialEq, Deserialize)]
        struct Bar {
            child: u32,
        }

        let val = from_str::<Root>(r#"<root><Foo attr="23" /></root>"#).unwrap();
        assert_eq!(val, Root::Foo(Foo { attr: 23 }));

        let val = from_str::<Root>(r#"<root><Bar><child>42</child></Bar></root>"#).unwrap();
        assert_eq!(val, Root::Bar(Bar { child: 42 }));
    }

    #[test]
    fn attribute_variants() {
        #[derive(Debug, PartialEq, Deserialize)]
        enum Root {
            Foo(u32),
            Bar(i64),
        }

        let val = from_str::<Root>(r#"<root Foo="23" />"#).unwrap();
        assert_eq!(val, Root::Foo(23));

        let val = from_str::<Root>(r#"<root Bar="42" />"#).unwrap();
        assert_eq!(val, Root::Bar(42));
    }

    #[test]
    fn mixed_enum_and_struct_children() {
        #[derive(Debug, PartialEq, Deserialize)]
        enum Foobar {
            Foo(u32),
            Bar(i64),
        }

        #[derive(Deserialize)]
        struct Root {
            #[serde(rename = "#content")]
            foobar: Foobar,
            qux: f32,
        }

        let val = from_str::<Root>(r#"<root><qux>42.0</qux><Foo>23</Foo></root>"#).unwrap();
        assert_eq!(val.foobar, Foobar::Foo(23));
        assert_eq!(val.qux, 42.0);
    }

    #[test]
    fn mixed_enum_and_repeated_struct_children() {
        #[derive(Debug, PartialEq, Deserialize)]
        enum Foobar {
            Foo(u32),
            Bar(i64),
        }

        #[derive(Deserialize)]
        struct Root {
            #[serde(rename = "#content")]
            foobar: Foobar,
            qux: Vec<f32>,
            baz: String,
        }

        let val = from_str::<Root>(
            r#"<root><Bar>42</Bar><qux>1.0</qux><baz>baz</baz><qux>2.0</qux><qux>3.0</qux></root>"#,
        )
        .unwrap();
        assert_eq!(val.foobar, Foobar::Bar(42));
        assert_eq!(val.qux, [1.0, 2.0, 3.0]);
        assert_eq!(val.baz, "baz");
    }

    #[test]
    fn repeated_enum_and_struct_children() {
        #[derive(Debug, PartialEq, Deserialize)]
        enum Foobar {
            Foo(Vec<u32>),
            Bar(i64),
        }

        #[derive(Deserialize)]
        struct Root {
            #[serde(rename = "#content")]
            foobar: Foobar,
            baz: String,
        }

        let val =
            from_str::<Root>(r#"<root><Foo>42</Foo><baz>baz</baz><Foo>23</Foo></root>"#).unwrap();
        assert_eq!(val.foobar, Foobar::Foo(vec![42, 23]));
        assert_eq!(val.baz, "baz");
    }

    #[test]
    fn borrowed_str() {
        let doc = Document::parse("<root><child>foobar</child></root>").unwrap();

        #[derive(Deserialize)]
        struct Root<'a> {
            child: &'a str,
        }

        let val = from_doc::<Root>(&doc).unwrap();
        assert_eq!(val.child, "foobar");
    }

    #[test]
    fn unit_struct() {
        #[derive(Deserialize)]
        #[allow(dead_code)]
        struct Root {
            child: Child,
        }

        #[derive(Deserialize)]
        struct Child;

        from_str::<Root>(r#"<root><child /></root>"#).unwrap();

        from_str::<Root>(r#"<root><child>foobar</child></root>"#).unwrap();
    }

    #[test]
    fn unit_variant() {
        #[derive(Debug, Deserialize)]
        enum Root {
            Child,
        }

        from_str::<Root>(r#"<root><Child /></root>"#).unwrap();

        from_str::<Root>(r#"<root><Child>foobar</Child></root>"#).unwrap();
    }

    #[test]
    fn children_with_namespaces() {
        #[derive(Deserialize)]
        struct Root {
            #[serde(rename = "{http://name.space}child")]
            child: u64,
        }

        let val = defaults()
            .namespaces()
            .from_str::<Root>(r#"<root xmlns="http://name.space"><child>42</child></root>"#)
            .unwrap();
        assert_eq!(val.child, 42);

        let val = defaults()
            .namespaces()
            .from_str::<Root>(r#"<root xmlns:namespace="http://name.space"><namespace:child>42</namespace:child></root>"#)
            .unwrap();
        assert_eq!(val.child, 42);
    }

    #[test]
    fn attributes_with_namespaces() {
        #[derive(Deserialize)]
        struct Root {
            #[serde(rename = "{http://name.space}attr")]
            attr: i32,
        }

        let val = defaults()
            .namespaces()
            .from_str::<Root>(
                r#"<root xmlns:namespace="http://name.space" namespace:attr="23"></root>"#,
            )
            .unwrap();
        assert_eq!(val.attr, 23);
    }

    #[test]
    fn prefixed_attributes() {
        #[derive(Deserialize)]
        struct Root {
            #[serde(rename = "@attr")]
            attr: i32,
        }

        let val = defaults()
            .prefix_attr()
            .from_str::<Root>(r#"<root attr="23"></root>"#)
            .unwrap();
        assert_eq!(val.attr, 23);
    }

    #[test]
    fn prefixed_attributes_with_namespaces() {
        #[derive(Deserialize)]
        struct Root {
            #[serde(rename = "@{http://name.space}attr")]
            attr: i32,
        }

        let val = defaults()
            .namespaces()
            .prefix_attr()
            .from_str::<Root>(
                r#"<root xmlns:namespace="http://name.space" namespace:attr="23"></root>"#,
            )
            .unwrap();
        assert_eq!(val.attr, 23);
    }

    #[test]
    fn only_children_skips_attributes() {
        #[derive(Deserialize)]
        struct Root {
            child: u64,
            attr: Option<i32>,
        }

        let val = defaults()
            .from_str::<Root>(r#"<root attr="23"><child>42</child></root>"#)
            .unwrap();
        assert_eq!(val.child, 42);
        assert_eq!(val.attr, Some(23));

        let val = defaults()
            .only_children()
            .from_str::<Root>(r#"<root attr="23"><child>42</child></root>"#)
            .unwrap();
        assert_eq!(val.child, 42);
        assert_eq!(val.attr, None);
    }

    #[test]
    fn only_children_skips_content() {
        #[derive(Deserialize)]
        struct Root {
            child: u64,
            #[serde(rename = "#content")]
            text: Option<String>,
        }

        let val = defaults()
            .from_str::<Root>(r#"<root>text<child>42</child></root>"#)
            .unwrap();
        assert_eq!(val.child, 42);
        assert_eq!(val.text.as_deref(), Some("text"));

        let val = defaults()
            .only_children()
            .from_str::<Root>(r#"<root>text<child>42</child></root>"#)
            .unwrap();
        assert_eq!(val.child, 42);
        assert_eq!(val.text.as_deref(), None);
    }

    #[test]
    fn repeated_namespaced_elements() {
        #[derive(Deserialize)]
        struct Root {
            #[serde(rename = "{http://foo}child")]
            foo: Vec<u64>,
            #[serde(rename = "{http://bar}child")]
            bar: Vec<u64>,
        }

        let val = defaults()
            .namespaces()
            .from_str::<Root>(
                r#"<root xmlns:foo="http://foo" xmlns:bar="http://bar">
    <foo:child>1</foo:child>
    <bar:child>2</bar:child>
    <bar:child>3</bar:child>
    <foo:child>4</foo:child>
</root>"#,
            )
            .unwrap();
        assert_eq!(val.foo, [1, 4]);
        assert_eq!(val.bar, [2, 3]);
    }
}
