macros.rs

  1// Copyright (c) 2017-2018 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
  2//
  3// This Source Code Form is subject to the terms of the Mozilla Public
  4// License, v. 2.0. If a copy of the MPL was not distributed with this
  5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6
  7macro_rules! get_attr {
  8    ($elem:ident, $attr:tt, $type:tt) => (
  9        get_attr!($elem, $attr, $type, value, value.parse()?)
 10    );
 11    ($elem:ident, $attr:tt, optional_empty, $value:ident, $func:expr) => (
 12        match $elem.attr($attr) {
 13            Some("") => None,
 14            Some($value) => Some($func),
 15            None => None,
 16        }
 17    );
 18    ($elem:ident, $attr:tt, optional, $value:ident, $func:expr) => (
 19        match $elem.attr($attr) {
 20            Some($value) => Some($func),
 21            None => None,
 22        }
 23    );
 24    ($elem:ident, $attr:tt, required, $value:ident, $func:expr) => (
 25        match $elem.attr($attr) {
 26            Some($value) => $func,
 27            None => return Err(::error::Error::ParseError(concat!("Required attribute '", $attr, "' missing."))),
 28        }
 29    );
 30    ($elem:ident, $attr:tt, default, $value:ident, $func:expr) => (
 31        match $elem.attr($attr) {
 32            Some($value) => $func,
 33            None => ::std::default::Default::default(),
 34        }
 35    );
 36}
 37
 38macro_rules! generate_attribute {
 39    ($(#[$meta:meta])* $elem:ident, $name:tt, {$($(#[$a_meta:meta])* $a:ident => $b:tt),+,}) => (
 40        generate_attribute!($(#[$meta])* $elem, $name, {$($(#[$a_meta])* $a => $b),+});
 41    );
 42    ($(#[$meta:meta])* $elem:ident, $name:tt, {$($(#[$a_meta:meta])* $a:ident => $b:tt),+,}, Default = $default:ident) => (
 43        generate_attribute!($(#[$meta])* $elem, $name, {$($(#[$a_meta])* $a => $b),+}, Default = $default);
 44    );
 45    ($(#[$meta:meta])* $elem:ident, $name:tt, {$($(#[$a_meta:meta])* $a:ident => $b:tt),+}) => (
 46        $(#[$meta])*
 47        #[derive(Debug, Clone, PartialEq)]
 48        pub enum $elem {
 49            $(
 50                $(#[$a_meta])*
 51                $a
 52            ),+
 53        }
 54        impl ::std::str::FromStr for $elem {
 55            type Err = ::error::Error;
 56            fn from_str(s: &str) -> Result<$elem, ::error::Error> {
 57                Ok(match s {
 58                    $($b => $elem::$a),+,
 59                    _ => return Err(::error::Error::ParseError(concat!("Unknown value for '", $name, "' attribute."))),
 60                })
 61            }
 62        }
 63        impl ::minidom::IntoAttributeValue for $elem {
 64            fn into_attribute_value(self) -> Option<String> {
 65                Some(String::from(match self {
 66                    $($elem::$a => $b),+
 67                }))
 68            }
 69        }
 70    );
 71    ($(#[$meta:meta])* $elem:ident, $name:tt, {$($(#[$a_meta:meta])* $a:ident => $b:tt),+}, Default = $default:ident) => (
 72        $(#[$meta])*
 73        #[derive(Debug, Clone, PartialEq)]
 74        pub enum $elem {
 75            $(
 76                $(#[$a_meta])*
 77                $a
 78            ),+
 79        }
 80        impl ::std::str::FromStr for $elem {
 81            type Err = ::error::Error;
 82            fn from_str(s: &str) -> Result<$elem, ::error::Error> {
 83                Ok(match s {
 84                    $($b => $elem::$a),+,
 85                    _ => return Err(::error::Error::ParseError(concat!("Unknown value for '", $name, "' attribute."))),
 86                })
 87            }
 88        }
 89        impl ::minidom::IntoAttributeValue for $elem {
 90            #[allow(unreachable_patterns)]
 91            fn into_attribute_value(self) -> Option<String> {
 92                Some(String::from(match self {
 93                    $elem::$default => return None,
 94                    $($elem::$a => $b),+
 95                }))
 96            }
 97        }
 98        impl ::std::default::Default for $elem {
 99            fn default() -> $elem {
100                $elem::$default
101            }
102        }
103    );
104    ($(#[$meta:meta])* $elem:ident, $name:tt, bool) => (
105        $(#[$meta])*
106        #[derive(Debug, Clone, PartialEq)]
107        pub enum $elem {
108            /// True value, represented by either 'true' or '1'.
109            True,
110            /// False value, represented by either 'false' or '0'.
111            False,
112        }
113        impl ::std::str::FromStr for $elem {
114            type Err = ::error::Error;
115            fn from_str(s: &str) -> Result<Self, ::error::Error> {
116                Ok(match s {
117                    "true" | "1" => $elem::True,
118                    "false" | "0" => $elem::False,
119                    _ => return Err(::error::Error::ParseError(concat!("Unknown value for '", $name, "' attribute."))),
120                })
121            }
122        }
123        impl ::minidom::IntoAttributeValue for $elem {
124            fn into_attribute_value(self) -> Option<String> {
125                match self {
126                    $elem::True => Some(String::from("true")),
127                    $elem::False => None
128                }
129            }
130        }
131        impl ::std::default::Default for $elem {
132            fn default() -> $elem {
133                $elem::False
134            }
135        }
136    );
137}
138
139macro_rules! generate_element_enum {
140    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, {$($(#[$enum_meta:meta])* $enum:ident => $enum_name:tt),+,}) => (
141        generate_element_enum!($(#[$meta])* $elem, $name, $ns, {$($(#[$enum_meta])* $enum => $enum_name),+});
142    );
143    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, {$($(#[$enum_meta:meta])* $enum:ident => $enum_name:tt),+}) => (
144        $(#[$meta])*
145        #[derive(Debug, Clone, PartialEq)]
146        pub enum $elem {
147            $(
148            $(#[$enum_meta])*
149            $enum
150            ),+
151        }
152        impl ::try_from::TryFrom<::minidom::Element> for $elem {
153            type Err = ::error::Error;
154            fn try_from(elem: ::minidom::Element) -> Result<$elem, ::error::Error> {
155                check_ns_only!(elem, $name, $ns);
156                check_no_children!(elem, $name);
157                check_no_attributes!(elem, $name);
158                Ok(match elem.name() {
159                    $($enum_name => $elem::$enum,)+
160                    _ => return Err(::error::Error::ParseError(concat!("This is not a ", $name, " element."))),
161                })
162            }
163        }
164        impl From<$elem> for ::minidom::Element {
165            fn from(elem: $elem) -> ::minidom::Element {
166                ::minidom::Element::builder(match elem {
167                    $($elem::$enum => $enum_name,)+
168                }).ns(::ns::$ns)
169                  .build()
170            }
171        }
172    );
173}
174
175macro_rules! generate_attribute_enum {
176    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, $attr:tt, {$($(#[$enum_meta:meta])* $enum:ident => $enum_name:tt),+,}) => (
177        generate_attribute_enum!($(#[$meta])* $elem, $name, $ns, $attr, {$($(#[$enum_meta])* $enum => $enum_name),+});
178    );
179    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, $attr:tt, {$($(#[$enum_meta:meta])* $enum:ident => $enum_name:tt),+}) => (
180        $(#[$meta])*
181        #[derive(Debug, Clone, PartialEq)]
182        pub enum $elem {
183            $(
184            $(#[$enum_meta])*
185            $enum
186            ),+
187        }
188        impl ::try_from::TryFrom<::minidom::Element> for $elem {
189            type Err = ::error::Error;
190            fn try_from(elem: ::minidom::Element) -> Result<$elem, ::error::Error> {
191                check_ns_only!(elem, $name, $ns);
192                check_no_children!(elem, $name);
193                check_no_unknown_attributes!(elem, $name, [$attr]);
194                Ok(match get_attr!(elem, $attr, required) {
195                    $($enum_name => $elem::$enum,)+
196                    _ => return Err(::error::Error::ParseError(concat!("Invalid ", $name, " ", $attr, " value."))),
197                })
198            }
199        }
200        impl From<$elem> for ::minidom::Element {
201            fn from(elem: $elem) -> ::minidom::Element {
202                ::minidom::Element::builder($name)
203                        .ns(::ns::$ns)
204                        .attr($attr, match elem {
205                             $($elem::$enum => $enum_name,)+
206                         })
207                         .build()
208            }
209        }
210    );
211}
212
213macro_rules! check_self {
214    ($elem:ident, $name:tt, $ns:ident) => (
215        check_self!($elem, $name, $ns, $name);
216    );
217    ($elem:ident, $name:tt, $ns:ident, $pretty_name:tt) => (
218        if !$elem.is($name, ::ns::$ns) {
219            return Err(::error::Error::ParseError(concat!("This is not a ", $pretty_name, " element.")));
220        }
221    );
222}
223
224macro_rules! check_ns_only {
225    ($elem:ident, $name:tt, $ns:ident) => (
226        if !$elem.has_ns(::ns::$ns) {
227            return Err(::error::Error::ParseError(concat!("This is not a ", $name, " element.")));
228        }
229    );
230}
231
232macro_rules! check_no_children {
233    ($elem:ident, $name:tt) => (
234        for _ in $elem.children() {
235            return Err(::error::Error::ParseError(concat!("Unknown child in ", $name, " element.")));
236        }
237    );
238}
239
240macro_rules! check_no_attributes {
241    ($elem:ident, $name:tt) => (
242        for _ in $elem.attrs() {
243            return Err(::error::Error::ParseError(concat!("Unknown attribute in ", $name, " element.")));
244        }
245    );
246}
247
248macro_rules! check_no_unknown_attributes {
249    ($elem:ident, $name:tt, [$($attr:tt),*]) => (
250        for (_attr, _) in $elem.attrs() {
251            $(
252            if _attr == $attr {
253                continue;
254            }
255            )*
256            return Err(::error::Error::ParseError(concat!("Unknown attribute in ", $name, " element.")));
257        }
258    );
259}
260
261macro_rules! generate_empty_element {
262    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident) => (
263        $(#[$meta])*
264        #[derive(Debug, Clone)]
265        pub struct $elem;
266
267        impl ::try_from::TryFrom<::minidom::Element> for $elem {
268            type Err = ::error::Error;
269
270            fn try_from(elem: ::minidom::Element) -> Result<$elem, ::error::Error> {
271                check_self!(elem, $name, $ns);
272                check_no_children!(elem, $name);
273                check_no_attributes!(elem, $name);
274                Ok($elem)
275            }
276        }
277
278        impl From<$elem> for ::minidom::Element {
279            fn from(_: $elem) -> ::minidom::Element {
280                ::minidom::Element::builder($name)
281                        .ns(::ns::$ns)
282                        .build()
283            }
284        }
285    );
286}
287
288macro_rules! generate_element_with_only_attributes {
289    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),+,]) => (
290        generate_element_with_only_attributes!($(#[$meta])* $elem, $name, $ns, [$($(#[$attr_meta])* $attr: $attr_type = $attr_name => $attr_action),*]);
291    );
292    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),+]) => (
293        $(#[$meta])*
294        #[derive(Debug, Clone)]
295        pub struct $elem {
296            $(
297            $(#[$attr_meta])*
298            pub $attr: $attr_type,
299            )*
300        }
301
302        impl ::try_from::TryFrom<::minidom::Element> for $elem {
303            type Err = ::error::Error;
304
305            fn try_from(elem: ::minidom::Element) -> Result<$elem, ::error::Error> {
306                check_self!(elem, $name, $ns);
307                check_no_children!(elem, $name);
308                check_no_unknown_attributes!(elem, $name, [$($attr_name),*]);
309                Ok($elem {
310                    $(
311                    $attr: get_attr!(elem, $attr_name, $attr_action),
312                    )*
313                })
314            }
315        }
316
317        impl From<$elem> for ::minidom::Element {
318            fn from(elem: $elem) -> ::minidom::Element {
319                ::minidom::Element::builder($name)
320                        .ns(::ns::$ns)
321                        $(
322                        .attr($attr_name, elem.$attr)
323                        )*
324                        .build()
325            }
326        }
327    );
328}
329
330macro_rules! generate_id {
331    ($elem:ident) => (
332        #[derive(Debug, Clone, PartialEq, Eq, Hash)]
333        pub struct $elem(pub String);
334        impl ::std::str::FromStr for $elem {
335            type Err = ::error::Error;
336            fn from_str(s: &str) -> Result<$elem, ::error::Error> {
337                // TODO: add a way to parse that differently when needed.
338                Ok($elem(String::from(s)))
339            }
340        }
341        impl ::minidom::IntoAttributeValue for $elem {
342            fn into_attribute_value(self) -> Option<String> {
343                Some(self.0)
344            }
345        }
346    );
347}
348
349macro_rules! generate_elem_id {
350    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident) => (
351        $(#[$meta])*
352        #[derive(Debug, Clone, PartialEq, Eq, Hash)]
353        pub struct $elem(pub String);
354        impl ::std::str::FromStr for $elem {
355            type Err = ::error::Error;
356            fn from_str(s: &str) -> Result<$elem, ::error::Error> {
357                // TODO: add a way to parse that differently when needed.
358                Ok($elem(String::from(s)))
359            }
360        }
361        impl ::try_from::TryFrom<::minidom::Element> for $elem {
362            type Err = ::error::Error;
363            fn try_from(elem: ::minidom::Element) -> Result<$elem, ::error::Error> {
364                check_self!(elem, $name, $ns);
365                check_no_children!(elem, $name);
366                check_no_attributes!(elem, $name);
367                // TODO: add a way to parse that differently when needed.
368                Ok($elem(elem.text()))
369            }
370        }
371        impl From<$elem> for ::minidom::Element {
372            fn from(elem: $elem) -> ::minidom::Element {
373                ::minidom::Element::builder($name)
374                        .ns(::ns::$ns)
375                        .append(elem.0)
376                        .build()
377            }
378        }
379    );
380}
381
382macro_rules! generate_element_with_text {
383    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, $text_ident:ident: $codec:ident < $text_type:ty >) => (
384        generate_element_with_text!($(#[$meta])* $elem, $name, $ns, [], $text_ident: $codec<$text_type>);
385    );
386    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),*], $text_ident:ident: $codec:ident < $text_type:ty >) => (
387        $(#[$meta])*
388        #[derive(Debug, Clone)]
389        pub struct $elem {
390            $(
391            $(#[$attr_meta])*
392            pub $attr: $attr_type,
393            )*
394            pub $text_ident: $text_type,
395        }
396
397        impl ::try_from::TryFrom<::minidom::Element> for $elem {
398            type Err = ::error::Error;
399
400            fn try_from(elem: ::minidom::Element) -> Result<$elem, ::error::Error> {
401                check_self!(elem, $name, $ns);
402                check_no_children!(elem, $name);
403                check_no_unknown_attributes!(elem, $name, [$($attr_name),*]);
404                Ok($elem {
405                    $(
406                    $attr: get_attr!(elem, $attr_name, $attr_action),
407                    )*
408                    $text_ident: $codec::decode(&elem.text())?,
409                })
410            }
411        }
412
413        impl From<$elem> for ::minidom::Element {
414            fn from(elem: $elem) -> ::minidom::Element {
415                ::minidom::Element::builder($name)
416                        .ns(::ns::$ns)
417                        $(
418                        .attr($attr_name, elem.$attr)
419                        )*
420                        .append($codec::encode(&elem.$text_ident))
421                        .build()
422            }
423        }
424    );
425}
426
427macro_rules! generate_element_with_children {
428    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, children: [$($(#[$child_meta:meta])* $child_ident:ident: Vec<$child_type:ty> = ($child_name:tt, $child_ns:ident) => $child_constructor:ident),+]) => (
429        generate_element_with_children!($(#[$meta])* $elem, $name, $ns, attributes: [], children: [$($(#[$child_meta])* $child_ident: Vec<$child_type> = ($child_name, $child_ns) => $child_constructor),+]);
430    );
431    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),*,], children: [$($(#[$child_meta:meta])* $child_ident:ident: Vec<$child_type:ty> = ($child_name:tt, $child_ns:ident) => $child_constructor:ident),+]) => (
432        generate_element_with_children!($(#[$meta])* $elem, $name, $ns, attributes: [$($(#[$attr_meta])* $attr: $attr_type = $attr_name => $attr_action),*], children: [$($(#[$child_meta])* $child_ident: Vec<$child_type> = ($child_name, $child_ns) => $child_constructor),+]);
433    );
434    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),*], children: [$($(#[$child_meta:meta])* $child_ident:ident: Vec<$child_type:ty> = ($child_name:tt, $child_ns:ident) => $child_constructor:ident),+]) => (
435        $(#[$meta])*
436        #[derive(Debug, Clone)]
437        pub struct $elem {
438            $(
439            $(#[$attr_meta])*
440            pub $attr: $attr_type,
441            )*
442            $(
443            $(#[$child_meta])*
444            pub $child_ident: Vec<$child_type>,
445            )*
446        }
447
448        impl ::try_from::TryFrom<::minidom::Element> for $elem {
449            type Err = ::error::Error;
450
451            fn try_from(elem: ::minidom::Element) -> Result<$elem, ::error::Error> {
452                check_self!(elem, $name, $ns);
453                check_no_unknown_attributes!(elem, $name, [$($attr_name),*]);
454                let mut parsed_children = vec!();
455                for child in elem.children() {
456                    $(
457                    if child.is($child_name, ::ns::$child_ns) {
458                        let parsed_child = $child_constructor::try_from(child.clone())?;
459                        parsed_children.push(parsed_child);
460                        continue;
461                    }
462                    )*
463                    return Err(::error::Error::ParseError(concat!("Unknown child in ", $name, " element.")));
464                }
465                Ok($elem {
466                    $(
467                    $attr: get_attr!(elem, $attr_name, $attr_action),
468                    )*
469                    $(
470                    $child_ident: parsed_children,
471                    )*
472                })
473            }
474        }
475
476        impl From<$elem> for ::minidom::Element {
477            fn from(elem: $elem) -> ::minidom::Element {
478                ::minidom::Element::builder($name)
479                        .ns(::ns::$ns)
480                        $(
481                        .attr($attr_name, elem.$attr)
482                        )*
483                        $(
484                        .append(elem.$child_ident)
485                        )*
486                        .build()
487            }
488        }
489    );
490    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, child: ($(#[$child_meta:meta])* $child_ident:ident: Option<$child_type:ty> = ($child_name:tt, $child_ns:ident) => $child_constructor:ident)) => (
491        generate_element_with_children!($(#[$meta])* $elem, $name, $ns, attributes: [], child: ($(#[$child_meta])* $child_ident: Option<$child_type> = ($child_name, $child_ns) => $child_constructor));
492    );
493    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),*,], child: ($(#[$child_meta:meta])* $child_ident:ident: Option<$child_type:ty> = ($child_name:tt, $child_ns:ident) => $child_constructor:ident)) => (
494        generate_element_with_children!($(#[$meta])* $elem, $name, $ns, attributes: [$($(#[$attr_meta])* $attr: $attr_type = $attr_name => $attr_action),*], child: ($(#[$child_meta])* $child_ident: Option<$child_type> = ($child_name, $child_ns) => $child_constructor));
495    );
496    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),*], child: ($(#[$child_meta:meta])* $child_ident:ident: Option<$child_type:ty> = ($child_name:tt, $child_ns:ident) => $child_constructor:ident)) => (
497        $(#[$meta])*
498        #[derive(Debug, Clone)]
499        pub struct $elem {
500            $(
501            $(#[$attr_meta])*
502            pub $attr: $attr_type,
503            )*
504            $(#[$child_meta])*
505            pub $child_ident: Option<$child_type>,
506        }
507
508        impl ::try_from::TryFrom<::minidom::Element> for $elem {
509            type Err = ::error::Error;
510
511            fn try_from(elem: ::minidom::Element) -> Result<$elem, ::error::Error> {
512                check_self!(elem, $name, $ns);
513                check_no_unknown_attributes!(elem, $name, [$($attr_name),*]);
514                let mut parsed_child = None;
515                for child in elem.children() {
516                    if child.is($child_name, ::ns::$child_ns) {
517                        parsed_child = Some($child_constructor::try_from(child.clone())?);
518                        continue;
519                    }
520                    return Err(::error::Error::ParseError(concat!("Unknown child in ", $name, " element.")));
521                }
522                Ok($elem {
523                    $(
524                    $attr: get_attr!(elem, $attr_name, $attr_action),
525                    )*
526                    $child_ident: parsed_child,
527                })
528            }
529        }
530
531        impl From<$elem> for ::minidom::Element {
532            fn from(elem: $elem) -> ::minidom::Element {
533                ::minidom::Element::builder($name)
534                        .ns(::ns::$ns)
535                        $(
536                        .attr($attr_name, elem.$attr)
537                        )*
538                        .append(elem.$child_ident)
539                        .build()
540            }
541        }
542    );
543    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, child: ($(#[$child_meta:meta])* $child_ident:ident: $child_type:ty = ($child_name:tt, $child_ns:ident) => $child_constructor:ident)) => (
544        generate_element_with_children!($(#[$meta])* $elem, $name, $ns, attributes: [], child: ($(#[$child_meta])* $child_ident: $child_type = ($child_name, $child_ns) => $child_constructor));
545    );
546    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),*,], child: ($(#[$child_meta:meta])* $child_ident:ident: $child_type:ty = ($child_name:tt, $child_ns:ident) => $child_constructor:ident)) => (
547        generate_element_with_children!($(#[$meta])* $elem, $name, $ns, attributes: [$($(#[$attr_meta])* $attr: $attr_type = $attr_name => $attr_action),*], child: ($(#[$child_meta])* $child_ident: $child_type = ($child_name, $child_ns) => $child_constructor));
548    );
549    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),*], child: ($(#[$child_meta:meta])* $child_ident:ident: $child_type:ty = ($child_name:tt, $child_ns:ident) => $child_constructor:ident)) => (
550        $(#[$meta])*
551        #[derive(Debug, Clone)]
552        pub struct $elem {
553            $(
554            $(#[$attr_meta])*
555            pub $attr: $attr_type,
556            )*
557            $(#[$child_meta])*
558            pub $child_ident: $child_type,
559        }
560
561        impl ::try_from::TryFrom<::minidom::Element> for $elem {
562            type Err = ::error::Error;
563
564            fn try_from(elem: ::minidom::Element) -> Result<$elem, ::error::Error> {
565                check_self!(elem, $name, $ns);
566                check_no_unknown_attributes!(elem, $name, [$($attr_name),*]);
567                let mut parsed_child = None;
568                for child in elem.children() {
569                    if child.is($child_name, ::ns::$child_ns) {
570                        parsed_child = Some($child_constructor::try_from(child.clone())?);
571                        continue;
572                    }
573                    return Err(::error::Error::ParseError(concat!("Unknown child in ", $name, " element.")));
574                }
575                Ok($elem {
576                    $(
577                    $attr: get_attr!(elem, $attr_name, $attr_action),
578                    )*
579                    $child_ident: parsed_child.ok_or(::error::Error::ParseError(concat!("Missing child ", $child_name, " in ", $name, " element.")))?,
580                })
581            }
582        }
583
584        impl From<$elem> for ::minidom::Element {
585            fn from(elem: $elem) -> ::minidom::Element {
586                ::minidom::Element::builder($name)
587                        .ns(::ns::$ns)
588                        $(
589                        .attr($attr_name, elem.$attr)
590                        )*
591                        .append(elem.$child_ident)
592                        .build()
593            }
594        }
595    );
596}