1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
use std::{borrow::Cow, fmt};

use thiserror::Error;

pub use macros::{FromXml, ToXml};

#[doc(hidden)]
pub mod de;
mod impls;
use de::Context;
pub use de::Deserializer;
pub use impls::{display_to_xml, from_xml_str, OptionAccumulator};
#[doc(hidden)]
pub mod ser;
pub use ser::Serializer;

pub trait ToXml {
    fn serialize<W: fmt::Write + ?Sized>(
        &self,
        field: Option<Id<'_>>,
        serializer: &mut Serializer<W>,
    ) -> Result<(), Error>;

    fn present(&self) -> bool {
        true
    }
}

impl<'a, T: ToXml + ?Sized> ToXml for &'a T {
    fn serialize<W: fmt::Write + ?Sized>(
        &self,
        field: Option<Id<'_>>,
        serializer: &mut Serializer<W>,
    ) -> Result<(), Error> {
        (*self).serialize(field, serializer)
    }
}

pub trait FromXml<'xml>: Sized {
    fn matches(id: Id<'_>, field: Option<Id<'_>>) -> bool;

    fn deserialize<'cx>(
        into: &mut Self::Accumulator,
        field: &'static str,
        deserializer: &mut Deserializer<'cx, 'xml>,
    ) -> Result<(), Error>;

    type Accumulator: Accumulate<Self>;
    const KIND: Kind;
}

/// A type implementing `Accumulate<T>` is used to accumulate a value of type `T`.
pub trait Accumulate<T>: Default {
    fn try_done(self, field: &'static str) -> Result<T, Error>;
}

impl<T> Accumulate<T> for Option<T> {
    fn try_done(self, field: &'static str) -> Result<T, Error> {
        self.ok_or(Error::MissingValue(field))
    }
}

impl<T> Accumulate<Vec<T>> for Vec<T> {
    fn try_done(self, _: &'static str) -> Result<Vec<T>, Error> {
        Ok(self)
    }
}

impl<'a, T> Accumulate<Cow<'a, [T]>> for Vec<T>
where
    [T]: ToOwned<Owned = Vec<T>>,
{
    fn try_done(self, _: &'static str) -> Result<Cow<'a, [T]>, Error> {
        Ok(Cow::Owned(self))
    }
}

impl<T> Accumulate<Option<T>> for Option<T> {
    fn try_done(self, _: &'static str) -> Result<Option<T>, Error> {
        Ok(self)
    }
}

pub fn from_str<'xml, T: FromXml<'xml>>(input: &'xml str) -> Result<T, Error> {
    let (mut context, root) = Context::new(input)?;
    let id = context.element_id(&root)?;

    if !T::matches(id, None) {
        return Err(Error::UnexpectedValue(match id.ns.is_empty() {
            true => format!("unexpected root element {:?}", id.name),
            false => format!(
                "unexpected root element {:?} in namespace {:?}",
                id.name, id.ns
            ),
        }));
    }

    let mut value = T::Accumulator::default();
    T::deserialize(
        &mut value,
        "<root element>",
        &mut Deserializer::new(root, &mut context),
    )?;
    value.try_done("<root element>")
}

pub fn to_string(value: &(impl ToXml + ?Sized)) -> Result<String, Error> {
    let mut output = String::new();
    to_writer(value, &mut output)?;
    Ok(output)
}

pub fn to_writer(
    value: &(impl ToXml + ?Sized),
    output: &mut (impl fmt::Write + ?Sized),
) -> Result<(), Error> {
    value.serialize(None, &mut Serializer::new(output))
}

pub trait FromXmlOwned: for<'xml> FromXml<'xml> {}

impl<T> FromXmlOwned for T where T: for<'xml> FromXml<'xml> {}

#[derive(Clone, Debug, Eq, Error, PartialEq)]
pub enum Error {
    #[error("format: {0}")]
    Format(#[from] fmt::Error),
    #[error("invalid entity: {0}")]
    InvalidEntity(String),
    #[error("parse: {0}")]
    Parse(#[from] xmlparser::Error),
    #[error("other: {0}")]
    Other(std::string::String),
    #[error("unexpected end of stream")]
    UnexpectedEndOfStream,
    #[error("unexpected value: '{0}'")]
    UnexpectedValue(String),
    #[error("unexpected tag: {0}")]
    UnexpectedTag(String),
    #[error("missing tag")]
    MissingTag,
    #[error("missing value: {0}")]
    MissingValue(&'static str),
    #[error("unexpected token: {0}")]
    UnexpectedToken(String),
    #[error("unknown prefix: {0}")]
    UnknownPrefix(String),
    #[error("unexpected node: {0}")]
    UnexpectedNode(String),
    #[error("unexpected state: {0}")]
    UnexpectedState(&'static str),
    #[error("expected scalar, found {0}")]
    ExpectedScalar(String),
    #[error("duplicate value")]
    DuplicateValue,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Kind {
    Scalar,
    Element,
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Id<'a> {
    pub ns: &'a str,
    pub name: &'a str,
}