1use ::quick_xml::name::ResolveResult;
5use core::str;
6
7use xmlity::{ser::IncludePrefix, ExpandedName, LocalName, Prefix, QName, XmlNamespace};
8
9pub mod de;
10pub mod ser;
11
12pub use de::{from_str, Deserializer};
13use quick_xml::name::{LocalName as QuickLocalName, Prefix as QuickPrefix, QName as QuickName};
14pub use ser::{to_string, Serializer};
15
16#[derive(Debug, thiserror::Error)]
17pub enum Error {
18 #[error("Quick XML error: {0}")]
19 QuickXml(#[from] quick_xml::Error),
20 #[error("Attribute error: {0}")]
21 AttrError(#[from] quick_xml::events::attributes::AttrError),
22 #[error("IO error: {0}")]
23 Io(#[from] std::io::Error),
24 #[error("Unexpected: {0}")]
25 Unexpected(xmlity::de::Unexpected),
26 #[error("Custom: {0}")]
27 Custom(String),
28 #[error("Wrong name: expected {expected:?}, got {actual:?}")]
29 WrongName {
30 actual: Box<ExpandedName<'static>>,
31 expected: Box<ExpandedName<'static>>,
32 },
33 #[error("Unknown child")]
34 UnknownChild,
35 #[error("Invalid UTF-8: {0}")]
36 InvalidUtf8(#[from] std::string::FromUtf8Error),
37 #[error("Invalid string")]
38 InvalidString,
39 #[error("Missing field: {field}")]
40 MissingField { field: String },
41 #[error("No possible variant: {ident}")]
42 NoPossibleVariant { ident: String },
43 #[error("Missing data")]
44 MissingData,
45}
46
47impl xmlity::de::Error for Error {
48 fn custom<T: ToString>(msg: T) -> Self {
49 Error::Custom(msg.to_string())
50 }
51
52 fn wrong_name(actual: &ExpandedName<'_>, expected: &ExpandedName<'_>) -> Self {
53 Error::WrongName {
54 actual: Box::new(actual.clone().into_owned()),
55 expected: Box::new(expected.clone().into_owned()),
56 }
57 }
58
59 fn unexpected_visit<T>(unexpected: xmlity::de::Unexpected, _expected: &T) -> Self {
60 Error::Unexpected(unexpected)
61 }
62
63 fn missing_field(field: &str) -> Self {
64 Error::MissingField {
65 field: field.to_string(),
66 }
67 }
68
69 fn no_possible_variant(ident: &str) -> Self {
70 Error::NoPossibleVariant {
71 ident: ident.to_string(),
72 }
73 }
74
75 fn missing_data() -> Self {
76 Error::MissingData
77 }
78
79 fn unknown_child() -> Self {
80 Error::UnknownChild
81 }
82
83 fn invalid_string() -> Self {
84 Error::InvalidString
85 }
86}
87
88impl xmlity::ser::Error for Error {
89 fn custom<T: ToString>(msg: T) -> Self {
90 Error::Custom(msg.to_string())
91 }
92}
93
94pub trait HasQuickXmlAlternative {
95 type QuickXmlAlternative;
96
97 fn from_quick_xml(quick_xml: Self::QuickXmlAlternative) -> Self;
98}
99
100impl<'a> HasQuickXmlAlternative for QName<'a> {
101 type QuickXmlAlternative = QuickName<'a>;
102
103 fn from_quick_xml(quick_xml: Self::QuickXmlAlternative) -> Self {
104 QName::new(
105 quick_xml.prefix().map(Prefix::from_quick_xml),
106 LocalName::from_quick_xml(quick_xml.local_name()),
107 )
108 }
109}
110
111impl<'a> HasQuickXmlAlternative for Prefix<'a> {
112 type QuickXmlAlternative = QuickPrefix<'a>;
113 fn from_quick_xml(quick_xml: Self::QuickXmlAlternative) -> Self {
114 Self::new(str::from_utf8(quick_xml.into_inner()).expect("prefix should be valid utf8"))
115 .expect("A quick xml prefix should be valid")
116 }
117}
118
119impl<'a> HasQuickXmlAlternative for LocalName<'a> {
120 type QuickXmlAlternative = QuickLocalName<'a>;
121 fn from_quick_xml(quick_xml: Self::QuickXmlAlternative) -> Self {
122 Self::new(str::from_utf8(quick_xml.into_inner()).expect("local name should be valid utf8"))
123 .expect("A quick xml local name should be valid")
124 }
125}
126
127pub struct OwnedQuickName(Vec<u8>);
128
129impl OwnedQuickName {
130 pub fn new(name: &QName<'_>) -> Self {
131 Self(name.to_string().into_bytes())
132 }
133
134 pub fn as_ref(&self) -> QuickName<'_> {
135 QuickName(&self.0[..])
136 }
137}
138
139pub fn xml_namespace_from_resolve_result(value: ResolveResult<'_>) -> Option<XmlNamespace<'_>> {
140 match value {
141 ResolveResult::Bound(namespace) => Some(
142 XmlNamespace::new(str::from_utf8(namespace.0).expect("namespace should be valid utf8"))
143 .unwrap(),
144 ),
145 _ => None,
146 }
147}
148
149#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
150pub struct Attribute<'a> {
151 pub name: ExpandedName<'a>,
152 pub value: String,
153 pub enforce_prefix: IncludePrefix,
154 pub preferred_prefix: Option<Prefix<'a>>,
155}
156
157impl<'a> Attribute<'a> {
158 pub fn resolve(self, resolved_prefix: Option<Prefix<'a>>) -> ResolvedAttribute<'a> {
159 ResolvedAttribute {
160 name: self.name.to_q_name(resolved_prefix),
161 value: self.value,
162 }
163 }
164}
165
166#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
167pub struct ResolvedAttribute<'a> {
168 pub name: QName<'a>,
169 pub value: String,
170}
171
172fn declaration_into_attribute(xmlns: XmlnsDeclaration<'_>) -> ResolvedAttribute<'_> {
173 ResolvedAttribute {
174 name: XmlnsDeclaration::xmlns_qname(xmlns.prefix),
175 value: xmlns.namespace.as_str().to_owned(),
176 }
177}
178
179#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
181pub struct XmlnsDeclaration<'a> {
182 pub prefix: Prefix<'a>,
183 pub namespace: XmlNamespace<'a>,
184}
185
186impl<'a> XmlnsDeclaration<'a> {
187 pub fn new(prefix: Prefix<'a>, namespace: XmlNamespace<'a>) -> Self {
188 Self { prefix, namespace }
189 }
190
191 pub fn into_owned(self) -> XmlnsDeclaration<'static> {
192 XmlnsDeclaration {
193 prefix: self.prefix.into_owned(),
194 namespace: self.namespace.into_owned(),
195 }
196 }
197
198 pub fn prefix(&self) -> &Prefix<'a> {
199 &self.prefix
200 }
201
202 pub fn namespace(&self) -> &XmlNamespace<'a> {
203 &self.namespace
204 }
205
206 pub fn xmlns_qname(prefix: Prefix<'_>) -> QName<'_> {
208 if prefix.is_default() {
209 QName::new(
210 None,
211 LocalName::new("xmlns").expect("xmlns is a valid local name"),
212 )
213 } else {
214 QName::new(
215 Some(Prefix::new("xmlns").expect("xmlns is a valid prefix")),
216 LocalName::from(prefix),
217 )
218 }
219 }
220}