1macro_rules! get_attr {
8 ($elem:ident, $attr:tt, $type:tt) => {
9 get_attr!(
10 $elem,
11 $attr,
12 $type,
13 value,
14 value.parse().map_err(xso::error::Error::text_parse_error)?
15 )
16 };
17 ($elem:ident, $attr:tt, Option, $value:ident, $func:expr) => {
18 match $elem.attr($attr) {
19 Some($value) => Some($func),
20 None => None,
21 }
22 };
23 ($elem:ident, $attr:tt, Required, $value:ident, $func:expr) => {
24 match $elem.attr($attr) {
25 Some($value) => $func,
26 None => {
27 return Err(xso::error::Error::Other(
28 concat!("Required attribute '", $attr, "' missing.").into(),
29 )
30 .into());
31 }
32 }
33 };
34 ($elem:ident, $attr:tt, Default, $value:ident, $func:expr) => {
35 match $elem.attr($attr) {
36 Some($value) => $func,
37 None => ::core::default::Default::default(),
38 }
39 };
40}
41
42macro_rules! generate_attribute {
43 ($(#[$meta:meta])* $elem:ident, $name:tt, {$($(#[$a_meta:meta])* $a:ident => $b:tt),+$(,)?}) => (
44 $(#[$meta])*
45 #[derive(Debug, Clone, PartialEq)]
46 pub enum $elem {
47 $(
48 $(#[$a_meta])*
49 $a
50 ),+
51 }
52 impl ::core::str::FromStr for $elem {
53 type Err = xso::error::Error;
54 fn from_str(s: &str) -> Result<$elem, xso::error::Error> {
55 Ok(match s {
56 $($b => $elem::$a),+,
57 _ => return Err(xso::error::Error::Other(concat!("Unknown value for '", $name, "' attribute.")).into()),
58 })
59 }
60 }
61 impl ::xso::FromXmlText for $elem {
62 fn from_xml_text(s: String) -> Result<$elem, xso::error::Error> {
63 s.parse().map_err(xso::error::Error::text_parse_error)
64 }
65 }
66 impl core::fmt::Display for $elem {
67 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
68 write!(fmt, "{}", match self {
69 $($elem::$a => $b),+
70 })
71 }
72 }
73 impl ::xso::AsXmlText for $elem {
74 fn as_xml_text(&self) -> Result<::alloc::borrow::Cow<'_, str>, xso::error::Error> {
75 match self {
76 $(
77 $elem::$a => Ok(::alloc::borrow::Cow::Borrowed($b))
78 ),+
79 }
80 }
81 }
82 impl ::minidom::IntoAttributeValue for $elem {
83 fn into_attribute_value(self) -> Option<String> {
84 Some(String::from(match self {
85 $($elem::$a => $b),+
86 }))
87 }
88 }
89 );
90 ($(#[$meta:meta])* $elem:ident, $name:tt, {$($(#[$a_meta:meta])* $a:ident => $b:tt),+$(,)?}, Default = $default:ident) => (
91 $(#[$meta])*
92 #[derive(Debug, Clone, PartialEq)]
93 pub enum $elem {
94 $(
95 $(#[$a_meta])*
96 $a
97 ),+
98 }
99 impl ::core::str::FromStr for $elem {
100 type Err = xso::error::Error;
101 fn from_str(s: &str) -> Result<$elem, xso::error::Error> {
102 Ok(match s {
103 $($b => $elem::$a),+,
104 _ => return Err(xso::error::Error::Other(concat!("Unknown value for '", $name, "' attribute.")).into()),
105 })
106 }
107 }
108 impl ::xso::FromXmlText for $elem {
109 fn from_xml_text(s: String) -> Result<$elem, xso::error::Error> {
110 s.parse().map_err(xso::error::Error::text_parse_error)
111 }
112 }
113 impl ::xso::AsXmlText for $elem {
114 fn as_xml_text(&self) -> Result<alloc::borrow::Cow<'_, str>, xso::error::Error> {
115 Ok(alloc::borrow::Cow::Borrowed(match self {
116 $($elem::$a => $b),+
117 }))
118 }
119
120 #[allow(unreachable_patterns)]
121 fn as_optional_xml_text(&self) -> Result<Option<alloc::borrow::Cow<'_, str>>, xso::error::Error> {
122 Ok(Some(alloc::borrow::Cow::Borrowed(match self {
123 $elem::$default => return Ok(None),
124 $($elem::$a => $b),+
125 })))
126 }
127 }
128 impl ::minidom::IntoAttributeValue for $elem {
129 #[allow(unreachable_patterns)]
130 fn into_attribute_value(self) -> Option<String> {
131 Some(String::from(match self {
132 $elem::$default => return None,
133 $($elem::$a => $b),+
134 }))
135 }
136 }
137 impl ::core::default::Default for $elem {
138 fn default() -> $elem {
139 $elem::$default
140 }
141 }
142 );
143 ($(#[$meta:meta])* $elem:ident, $name:tt, ($(#[$meta_symbol:meta])* $symbol:ident => $value:tt)) => (
144 $(#[$meta])*
145 #[derive(Debug, Clone, PartialEq)]
146 pub enum $elem {
147 $(#[$meta_symbol])*
148 $symbol,
149 None,
151 }
152 impl ::core::str::FromStr for $elem {
153 type Err = xso::error::Error;
154 fn from_str(s: &str) -> Result<Self, xso::error::Error> {
155 Ok(match s {
156 $value => $elem::$symbol,
157 _ => return Err(xso::error::Error::Other(concat!("Unknown value for '", $name, "' attribute."))),
158 })
159 }
160 }
161 impl ::minidom::IntoAttributeValue for $elem {
162 fn into_attribute_value(self) -> Option<String> {
163 match self {
164 $elem::$symbol => Some(String::from($value)),
165 $elem::None => None
166 }
167 }
168 }
169 impl ::core::default::Default for $elem {
170 fn default() -> $elem {
171 $elem::None
172 }
173 }
174 impl ::xso::FromXmlText for $elem {
175 fn from_xml_text(s: String) -> Result<$elem, xso::error::Error> {
176 s.parse().map_err(xso::error::Error::text_parse_error)
177 }
178 }
179 impl ::xso::AsXmlText for $elem {
180 fn as_xml_text(&self) -> Result<::alloc::borrow::Cow<'_, str>, xso::error::Error> {
181 Ok(::alloc::borrow::Cow::Borrowed($value))
182 }
183
184 #[allow(unreachable_patterns)]
185 fn as_optional_xml_text(&self) -> Result<Option<alloc::borrow::Cow<'_, str>>, xso::error::Error> {
186 Ok(Some(alloc::borrow::Cow::Borrowed(match self {
187 $elem::$symbol => $value,
188 $elem::None => return Ok(None),
189 })))
190 }
191 }
192 );
193 ($(#[$meta:meta])* $elem:ident, $name:tt, $type:tt, Default = $default:expr) => (
194 $(#[$meta])*
195 #[derive(Debug, Clone, PartialEq)]
196 pub struct $elem(pub $type);
197 impl ::core::str::FromStr for $elem {
198 type Err = xso::error::Error;
199 fn from_str(s: &str) -> Result<Self, xso::error::Error> {
200 Ok($elem($type::from_str(s).map_err(xso::error::Error::text_parse_error)?))
201 }
202 }
203 impl ::minidom::IntoAttributeValue for $elem {
204 fn into_attribute_value(self) -> Option<String> {
205 match self {
206 $elem($default) => None,
207 $elem(value) => Some(format!("{}", value)),
208 }
209 }
210 }
211 impl ::core::default::Default for $elem {
212 fn default() -> $elem {
213 $elem($default)
214 }
215 }
216 impl ::xso::FromXmlText for $elem {
217 fn from_xml_text(s: String) -> Result<$elem, xso::error::Error> {
218 s.parse().map_err(xso::error::Error::text_parse_error)
219 }
220 }
221 impl ::xso::AsXmlText for $elem {
222 fn as_xml_text(&self) -> Result<::alloc::borrow::Cow<'_, str>, xso::error::Error> {
223 Ok(::alloc::borrow::Cow::Owned(format!("{}", self.0)))
224 }
225
226 fn as_optional_xml_text(&self) -> Result<Option<::alloc::borrow::Cow<'_, str>>, xso::error::Error> {
227 match self.0 {
228 $default => Ok(None),
229 _ => Ok(Some(::alloc::borrow::Cow::Owned(format!("{}", self.0)))),
230 }
231 }
232 }
233 );
234}
235
236macro_rules! generate_attribute_enum {
237 ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, $attr:tt, {$($(#[$enum_meta:meta])* $enum:ident => $enum_name:tt),+$(,)?}) => (
238 $(#[$meta])*
239 #[derive(Debug, Clone, PartialEq)]
240 pub enum $elem {
241 $(
242 $(#[$enum_meta])*
243 $enum
244 ),+
245 }
246 impl ::core::convert::TryFrom<minidom::Element> for $elem {
247 type Error = xso::error::FromElementError;
248 fn try_from(elem: minidom::Element) -> Result<$elem, xso::error::FromElementError> {
249 check_ns_only!(elem, $name, $ns);
250 check_no_children!(elem, $name);
251 check_no_unknown_attributes!(elem, $name, [$attr]);
252 Ok(match get_attr!(elem, $attr, Required) {
253 $($enum_name => $elem::$enum,)+
254 _ => return Err(xso::error::Error::Other(concat!("Invalid ", $name, " ", $attr, " value.")).into()),
255 })
256 }
257 }
258
259 impl ::xso::FromXml for $elem {
260 type Builder = ::xso::minidom_compat::FromEventsViaElement<$elem>;
261
262 fn from_events(
263 qname: ::xso::exports::rxml::QName,
264 attrs: ::xso::exports::rxml::AttrMap,
265 _ctx: &::xso::Context<'_>,
266 ) -> Result<Self::Builder, ::xso::error::FromEventsError> {
267 if qname.0 != crate::ns::$ns || qname.1 != $name {
268 return Err(::xso::error::FromEventsError::Mismatch {
269 name: qname,
270 attrs,
271 })
272 }
273 Self::Builder::new(qname, attrs)
274 }
275 }
276
277 impl From<$elem> for minidom::Element {
278 fn from(elem: $elem) -> minidom::Element {
279 minidom::Element::builder($name, crate::ns::$ns)
280 .attr($attr, match elem {
281 $($elem::$enum => $enum_name,)+
282 })
283 .build()
284 }
285 }
286
287 impl ::xso::AsXml for $elem {
288 type ItemIter<'x> = ::xso::minidom_compat::AsItemsViaElement<'x>;
289
290 fn as_xml_iter(&self) -> Result<Self::ItemIter<'_>, ::xso::error::Error> {
291 ::xso::minidom_compat::AsItemsViaElement::new(self.clone())
292 }
293 }
294 );
295}
296
297macro_rules! check_self {
298 ($elem:ident, $name:tt, $ns:ident) => {
299 check_self!($elem, $name, $ns, $name);
300 };
301 ($elem:ident, $name:tt, $ns:ident, $pretty_name:tt) => {
302 if !$elem.is($name, crate::ns::$ns) {
303 return Err(xso::error::FromElementError::Mismatch($elem));
304 }
305 };
306}
307
308macro_rules! check_ns_only {
309 ($elem:ident, $name:tt, $ns:ident) => {
310 if !$elem.has_ns(crate::ns::$ns) {
311 return Err(xso::error::Error::Other(
312 concat!("This is not a ", $name, " element.").into(),
313 )
314 .into());
315 }
316 };
317}
318
319macro_rules! check_no_children {
320 ($elem:ident, $name:tt) => {
321 #[cfg(not(feature = "disable-validation"))]
322 for _ in $elem.children() {
323 return Err(xso::error::Error::Other(
324 concat!("Unknown child in ", $name, " element.").into(),
325 )
326 .into());
327 }
328 };
329}
330
331macro_rules! check_no_attributes {
332 ($elem:ident, $name:tt) => {
333 #[cfg(not(feature = "disable-validation"))]
334 for _ in $elem.attrs() {
335 return Err(xso::error::Error::Other(
336 concat!("Unknown attribute in ", $name, " element.").into(),
337 )
338 .into());
339 }
340 };
341}
342
343macro_rules! check_no_unknown_attributes {
344 ($elem:ident, $name:tt, [$($attr:tt),*]) => (
345 #[cfg(not(feature = "disable-validation"))]
346 for (_attr, _) in $elem.attrs() {
347 $(
348 if _attr == $attr {
349 continue;
350 }
351 )*
352 return Err(xso::error::Error::Other(concat!("Unknown attribute in ", $name, " element.")).into());
353 }
354 );
355}
356
357macro_rules! generate_id {
358 ($(#[$meta:meta])* $elem:ident) => (
359 $(#[$meta])*
360 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
361 pub struct $elem(pub String);
362 impl ::core::str::FromStr for $elem {
363 type Err = xso::error::Error;
364 fn from_str(s: &str) -> Result<$elem, xso::error::Error> {
365 Ok($elem(String::from(s)))
367 }
368 }
369 impl ::xso::FromXmlText for $elem {
370 fn from_xml_text(s: String) -> Result<$elem, xso::error::Error> {
371 Ok(Self(s))
372 }
373 }
374 impl ::xso::AsXmlText for $elem {
375 fn as_xml_text(&self) ->Result<::alloc::borrow::Cow<'_, str>, xso::error::Error> {
376 Ok(::alloc::borrow::Cow::Borrowed(self.0.as_str()))
377 }
378 }
379 impl ::minidom::IntoAttributeValue for $elem {
380 fn into_attribute_value(self) -> Option<String> {
381 Some(self.0)
382 }
383 }
384 );
385}
386
387macro_rules! generate_elem_id {
388 ($(#[$meta:meta])* $elem:ident, $name:literal, $ns:ident) => (
389 generate_elem_id!($(#[$meta])* $elem, $name, $ns, String);
390 impl ::core::str::FromStr for $elem {
391 type Err = xso::error::Error;
392 fn from_str(s: &str) -> Result<$elem, xso::error::Error> {
393 Ok($elem(String::from(s)))
395 }
396 }
397 );
398 ($(#[$meta:meta])* $elem:ident, $name:literal, $ns:ident, $type:ty) => (
399 $(#[$meta])*
400 #[derive(xso::FromXml, xso::AsXml, Debug, Clone, PartialEq, Eq, Hash)]
401 #[xml(namespace = crate::ns::$ns, name = $name)]
402 pub struct $elem(#[xml(text)] pub $type);
403 );
404}
405
406#[cfg(test)]
407macro_rules! assert_size (
408 ($t:ty, $sz:expr) => (
409 assert_eq!(::core::mem::size_of::<$t>(), $sz);
410 );
411);