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, OptionEmpty, $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, Option, $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 => {
 28                return Err(crate::util::error::Error::ParseError(concat!(
 29                    "Required attribute '",
 30                    $attr,
 31                    "' missing."
 32                )));
 33            }
 34        }
 35    };
 36    ($elem:ident, $attr:tt, Default, $value:ident, $func:expr) => {
 37        match $elem.attr($attr) {
 38            Some($value) => $func,
 39            None => ::std::default::Default::default(),
 40        }
 41    };
 42}
 43
 44macro_rules! generate_attribute {
 45    ($(#[$meta:meta])* $elem:ident, $name:tt, {$($(#[$a_meta:meta])* $a:ident => $b:tt),+,}) => (
 46        generate_attribute!($(#[$meta])* $elem, $name, {$($(#[$a_meta])* $a => $b),+});
 47    );
 48    ($(#[$meta:meta])* $elem:ident, $name:tt, {$($(#[$a_meta:meta])* $a:ident => $b:tt),+,}, Default = $default:ident) => (
 49        generate_attribute!($(#[$meta])* $elem, $name, {$($(#[$a_meta])* $a => $b),+}, Default = $default);
 50    );
 51    ($(#[$meta:meta])* $elem:ident, $name:tt, {$($(#[$a_meta:meta])* $a:ident => $b:tt),+}) => (
 52        $(#[$meta])*
 53        #[derive(Debug, Clone, PartialEq)]
 54        pub enum $elem {
 55            $(
 56                $(#[$a_meta])*
 57                $a
 58            ),+
 59        }
 60        impl ::std::str::FromStr for $elem {
 61            type Err = crate::util::error::Error;
 62            fn from_str(s: &str) -> Result<$elem, crate::util::error::Error> {
 63                Ok(match s {
 64                    $($b => $elem::$a),+,
 65                    _ => return Err(crate::util::error::Error::ParseError(concat!("Unknown value for '", $name, "' attribute."))),
 66                })
 67            }
 68        }
 69        impl ::minidom::IntoAttributeValue for $elem {
 70            fn into_attribute_value(self) -> Option<String> {
 71                Some(String::from(match self {
 72                    $($elem::$a => $b),+
 73                }))
 74            }
 75        }
 76    );
 77    ($(#[$meta:meta])* $elem:ident, $name:tt, {$($(#[$a_meta:meta])* $a:ident => $b:tt),+}, Default = $default:ident) => (
 78        $(#[$meta])*
 79        #[derive(Debug, Clone, PartialEq)]
 80        pub enum $elem {
 81            $(
 82                $(#[$a_meta])*
 83                $a
 84            ),+
 85        }
 86        impl ::std::str::FromStr for $elem {
 87            type Err = crate::util::error::Error;
 88            fn from_str(s: &str) -> Result<$elem, crate::util::error::Error> {
 89                Ok(match s {
 90                    $($b => $elem::$a),+,
 91                    _ => return Err(crate::util::error::Error::ParseError(concat!("Unknown value for '", $name, "' attribute."))),
 92                })
 93            }
 94        }
 95        impl ::minidom::IntoAttributeValue for $elem {
 96            #[allow(unreachable_patterns)]
 97            fn into_attribute_value(self) -> Option<String> {
 98                Some(String::from(match self {
 99                    $elem::$default => return None,
100                    $($elem::$a => $b),+
101                }))
102            }
103        }
104        impl ::std::default::Default for $elem {
105            fn default() -> $elem {
106                $elem::$default
107            }
108        }
109    );
110    ($(#[$meta:meta])* $elem:ident, $name:tt, ($(#[$meta_symbol:meta])* $symbol:ident => $value:tt)) => (
111        $(#[$meta])*
112        #[derive(Debug, Clone, PartialEq)]
113        pub enum $elem {
114            $(#[$meta_symbol])*
115            $symbol,
116            /// Value when absent.
117            None,
118        }
119        impl ::std::str::FromStr for $elem {
120            type Err = crate::util::error::Error;
121            fn from_str(s: &str) -> Result<Self, crate::util::error::Error> {
122                Ok(match s {
123                    $value => $elem::$symbol,
124                    _ => return Err(crate::util::error::Error::ParseError(concat!("Unknown value for '", $name, "' attribute."))),
125                })
126            }
127        }
128        impl ::minidom::IntoAttributeValue for $elem {
129            fn into_attribute_value(self) -> Option<String> {
130                match self {
131                    $elem::$symbol => Some(String::from($value)),
132                    $elem::None => None
133                }
134            }
135        }
136        impl ::std::default::Default for $elem {
137            fn default() -> $elem {
138                $elem::None
139            }
140        }
141    );
142    ($(#[$meta:meta])* $elem:ident, $name:tt, bool) => (
143        $(#[$meta])*
144        #[derive(Debug, Clone, PartialEq)]
145        pub enum $elem {
146            /// True value, represented by either 'true' or '1'.
147            True,
148            /// False value, represented by either 'false' or '0'.
149            False,
150        }
151        impl ::std::str::FromStr for $elem {
152            type Err = crate::util::error::Error;
153            fn from_str(s: &str) -> Result<Self, crate::util::error::Error> {
154                Ok(match s {
155                    "true" | "1" => $elem::True,
156                    "false" | "0" => $elem::False,
157                    _ => return Err(crate::util::error::Error::ParseError(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::True => Some(String::from("true")),
165                    $elem::False => None
166                }
167            }
168        }
169        impl ::std::default::Default for $elem {
170            fn default() -> $elem {
171                $elem::False
172            }
173        }
174    );
175}
176
177macro_rules! generate_element_enum {
178    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, {$($(#[$enum_meta:meta])* $enum:ident => $enum_name:tt),+,}) => (
179        generate_element_enum!($(#[$meta])* $elem, $name, $ns, {$($(#[$enum_meta])* $enum => $enum_name),+});
180    );
181    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, {$($(#[$enum_meta:meta])* $enum:ident => $enum_name:tt),+}) => (
182        $(#[$meta])*
183        #[derive(Debug, Clone, PartialEq)]
184        pub enum $elem {
185            $(
186                $(#[$enum_meta])*
187                $enum
188            ),+
189        }
190        impl ::try_from::TryFrom<::minidom::Element> for $elem {
191            type Err = crate::util::error::Error;
192            fn try_from(elem: ::minidom::Element) -> Result<$elem, crate::util::error::Error> {
193                check_ns_only!(elem, $name, $ns);
194                check_no_children!(elem, $name);
195                check_no_attributes!(elem, $name);
196                Ok(match elem.name() {
197                    $($enum_name => $elem::$enum,)+
198                    _ => return Err(crate::util::error::Error::ParseError(concat!("This is not a ", $name, " element."))),
199                })
200            }
201        }
202        impl From<$elem> for ::minidom::Element {
203            fn from(elem: $elem) -> ::minidom::Element {
204                ::minidom::Element::builder(
205                    match elem {
206                        $($elem::$enum => $enum_name,)+
207                    }
208                )
209                    .ns(crate::ns::$ns)
210                    .build()
211            }
212        }
213    );
214}
215
216macro_rules! generate_attribute_enum {
217    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, $attr:tt, {$($(#[$enum_meta:meta])* $enum:ident => $enum_name:tt),+,}) => (
218        generate_attribute_enum!($(#[$meta])* $elem, $name, $ns, $attr, {$($(#[$enum_meta])* $enum => $enum_name),+});
219    );
220    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, $attr:tt, {$($(#[$enum_meta:meta])* $enum:ident => $enum_name:tt),+}) => (
221        $(#[$meta])*
222        #[derive(Debug, Clone, PartialEq)]
223        pub enum $elem {
224            $(
225                $(#[$enum_meta])*
226                $enum
227            ),+
228        }
229        impl ::try_from::TryFrom<::minidom::Element> for $elem {
230            type Err = crate::util::error::Error;
231            fn try_from(elem: ::minidom::Element) -> Result<$elem, crate::util::error::Error> {
232                check_ns_only!(elem, $name, $ns);
233                check_no_children!(elem, $name);
234                check_no_unknown_attributes!(elem, $name, [$attr]);
235                Ok(match get_attr!(elem, $attr, Required) {
236                    $($enum_name => $elem::$enum,)+
237                    _ => return Err(crate::util::error::Error::ParseError(concat!("Invalid ", $name, " ", $attr, " value."))),
238                })
239            }
240        }
241        impl From<$elem> for ::minidom::Element {
242            fn from(elem: $elem) -> ::minidom::Element {
243                ::minidom::Element::builder($name)
244                    .ns(crate::ns::$ns)
245                    .attr($attr, match elem {
246                         $($elem::$enum => $enum_name,)+
247                     })
248                     .build()
249            }
250        }
251    );
252}
253
254macro_rules! check_self {
255    ($elem:ident, $name:tt, $ns:ident) => {
256        check_self!($elem, $name, $ns, $name);
257    };
258    ($elem:ident, $name:tt, $ns:ident, $pretty_name:tt) => {
259        if !$elem.is($name, crate::ns::$ns) {
260            return Err(crate::util::error::Error::ParseError(concat!(
261                "This is not a ",
262                $pretty_name,
263                " element."
264            )));
265        }
266    };
267}
268
269macro_rules! check_ns_only {
270    ($elem:ident, $name:tt, $ns:ident) => {
271        if !$elem.has_ns(crate::ns::$ns) {
272            return Err(crate::util::error::Error::ParseError(concat!(
273                "This is not a ",
274                $name,
275                " element."
276            )));
277        }
278    };
279}
280
281macro_rules! check_no_children {
282    ($elem:ident, $name:tt) => {
283        #[cfg(not(feature = "disable-validation"))]
284        for _ in $elem.children() {
285            return Err(crate::util::error::Error::ParseError(concat!(
286                "Unknown child in ",
287                $name,
288                " element."
289            )));
290        }
291    };
292}
293
294macro_rules! check_no_attributes {
295    ($elem:ident, $name:tt) => {
296        #[cfg(not(feature = "disable-validation"))]
297        for _ in $elem.attrs() {
298            return Err(crate::util::error::Error::ParseError(concat!(
299                "Unknown attribute in ",
300                $name,
301                " element."
302            )));
303        }
304    };
305}
306
307macro_rules! check_no_unknown_attributes {
308    ($elem:ident, $name:tt, [$($attr:tt),*]) => (
309        #[cfg(not(feature = "disable-validation"))]
310        for (_attr, _) in $elem.attrs() {
311            $(
312                if _attr == $attr {
313                    continue;
314                }
315            )*
316            return Err(crate::util::error::Error::ParseError(concat!("Unknown attribute in ", $name, " element.")));
317        }
318    );
319}
320
321macro_rules! generate_empty_element {
322    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident) => (
323        $(#[$meta])*
324        #[derive(Debug, Clone)]
325        pub struct $elem;
326
327        impl ::try_from::TryFrom<::minidom::Element> for $elem {
328            type Err = crate::util::error::Error;
329
330            fn try_from(elem: ::minidom::Element) -> Result<$elem, crate::util::error::Error> {
331                check_self!(elem, $name, $ns);
332                check_no_children!(elem, $name);
333                check_no_attributes!(elem, $name);
334                Ok($elem)
335            }
336        }
337
338        impl From<$elem> for ::minidom::Element {
339            fn from(_: $elem) -> ::minidom::Element {
340                ::minidom::Element::builder($name)
341                    .ns(crate::ns::$ns)
342                    .build()
343            }
344        }
345    );
346}
347
348macro_rules! generate_id {
349    ($(#[$meta:meta])* $elem:ident) => (
350        $(#[$meta])*
351        #[derive(Debug, Clone, PartialEq, Eq, Hash)]
352        pub struct $elem(pub String);
353        impl ::std::str::FromStr for $elem {
354            type Err = crate::util::error::Error;
355            fn from_str(s: &str) -> Result<$elem, crate::util::error::Error> {
356                // TODO: add a way to parse that differently when needed.
357                Ok($elem(String::from(s)))
358            }
359        }
360        impl ::minidom::IntoAttributeValue for $elem {
361            fn into_attribute_value(self) -> Option<String> {
362                Some(self.0)
363            }
364        }
365    );
366}
367
368macro_rules! generate_elem_id {
369    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident) => (
370        $(#[$meta])*
371        #[derive(Debug, Clone, PartialEq, Eq, Hash)]
372        pub struct $elem(pub String);
373        impl ::std::str::FromStr for $elem {
374            type Err = crate::util::error::Error;
375            fn from_str(s: &str) -> Result<$elem, crate::util::error::Error> {
376                // TODO: add a way to parse that differently when needed.
377                Ok($elem(String::from(s)))
378            }
379        }
380        impl ::try_from::TryFrom<::minidom::Element> for $elem {
381            type Err = crate::util::error::Error;
382            fn try_from(elem: ::minidom::Element) -> Result<$elem, crate::util::error::Error> {
383                check_self!(elem, $name, $ns);
384                check_no_children!(elem, $name);
385                check_no_attributes!(elem, $name);
386                // TODO: add a way to parse that differently when needed.
387                Ok($elem(elem.text()))
388            }
389        }
390        impl From<$elem> for ::minidom::Element {
391            fn from(elem: $elem) -> ::minidom::Element {
392                ::minidom::Element::builder($name)
393                    .ns(crate::ns::$ns)
394                    .append(elem.0)
395                    .build()
396            }
397        }
398    );
399}
400
401macro_rules! decl_attr {
402    (OptionEmpty, $type:ty) => (
403        Option<$type>
404    );
405    (Option, $type:ty) => (
406        Option<$type>
407    );
408    (Required, $type:ty) => (
409        $type
410    );
411    (Default, $type:ty) => (
412        $type
413    );
414}
415
416macro_rules! start_decl {
417    (Vec, $type:ty) => (
418        Vec<$type>
419    );
420    (Option, $type:ty) => (
421        Option<$type>
422    );
423    (Required, $type:ty) => (
424        $type
425    );
426}
427
428macro_rules! start_parse_elem {
429    ($temp:ident: Vec) => {
430        let mut $temp = Vec::new();
431    };
432    ($temp:ident: Option) => {
433        let mut $temp = None;
434    };
435    ($temp:ident: Required) => {
436        let mut $temp = None;
437    };
438}
439
440macro_rules! do_parse {
441    ($elem:ident, Element) => {
442        $elem.clone()
443    };
444    ($elem:ident, String) => {
445        $elem.text()
446    };
447    ($elem:ident, $constructor:ident) => {
448        $constructor::try_from($elem.clone())?
449    };
450}
451
452macro_rules! do_parse_elem {
453    ($temp:ident: Vec = $constructor:ident => $elem:ident, $name:tt, $parent_name:tt) => {
454        $temp.push(do_parse!($elem, $constructor));
455    };
456    ($temp:ident: Option = $constructor:ident => $elem:ident, $name:tt, $parent_name:tt) => {
457        if $temp.is_some() {
458            return Err(crate::util::error::Error::ParseError(concat!(
459                "Element ",
460                $parent_name,
461                " must not have more than one ",
462                $name,
463                " child."
464            )));
465        }
466        $temp = Some(do_parse!($elem, $constructor));
467    };
468    ($temp:ident: Required = $constructor:ident => $elem:ident, $name:tt, $parent_name:tt) => {
469        if $temp.is_some() {
470            return Err(crate::util::error::Error::ParseError(concat!(
471                "Element ",
472                $parent_name,
473                " must not have more than one ",
474                $name,
475                " child."
476            )));
477        }
478        $temp = Some(do_parse!($elem, $constructor));
479    };
480}
481
482macro_rules! finish_parse_elem {
483    ($temp:ident: Vec = $name:tt, $parent_name:tt) => {
484        $temp
485    };
486    ($temp:ident: Option = $name:tt, $parent_name:tt) => {
487        $temp
488    };
489    ($temp:ident: Required = $name:tt, $parent_name:tt) => {
490        $temp.ok_or(crate::util::error::Error::ParseError(concat!(
491            "Missing child ",
492            $name,
493            " in ",
494            $parent_name,
495            " element."
496        )))?
497    };
498}
499
500macro_rules! generate_serialiser {
501    ($parent:ident, $elem:ident, Required, String, ($name:tt, $ns:ident)) => {
502        ::minidom::Element::builder($name)
503            .ns(crate::ns::$ns)
504            .append($parent.$elem)
505            .build()
506    };
507    ($parent:ident, $elem:ident, Option, String, ($name:tt, $ns:ident)) => {
508        $parent.$elem.map(|elem| {
509            ::minidom::Element::builder($name)
510                .ns(crate::ns::$ns)
511                .append(elem)
512                .build()
513        })
514    };
515    ($parent:ident, $elem:ident, $_:ident, $constructor:ident, ($name:tt, $ns:ident)) => {
516        $parent.$elem
517    };
518}
519
520macro_rules! generate_element {
521    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_action:tt<$attr_type:ty> = $attr_name:tt),+,]) => (
522        generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [$($(#[$attr_meta])* $attr: $attr_action<$attr_type> = $attr_name),*], children: []);
523    );
524    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_action:tt<$attr_type:ty> = $attr_name:tt),+]) => (
525        generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [$($(#[$attr_meta])* $attr: $attr_action<$attr_type> = $attr_name),*], children: []);
526    );
527    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, children: [$($(#[$child_meta:meta])* $child_ident:ident: $coucou:tt<$child_type:ty> = ($child_name:tt, $child_ns:ident) => $child_constructor:ident),*]) => (
528        generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [], children: [$($(#[$child_meta])* $child_ident: $coucou<$child_type> = ($child_name, $child_ns) => $child_constructor),*]);
529    );
530    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_action:tt<$attr_type:ty> = $attr_name:tt),*,], children: [$($(#[$child_meta:meta])* $child_ident:ident: $coucou:tt<$child_type:ty> = ($child_name:tt, $child_ns:ident) => $child_constructor:ident),*]) => (
531        generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [$($(#[$attr_meta])* $attr: $attr_action<$attr_type> = $attr_name),*], children: [$($(#[$child_meta])* $child_ident: $coucou<$child_type> = ($child_name, $child_ns) => $child_constructor),*]);
532    );
533    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, text: ($(#[$text_meta:meta])* $text_ident:ident: $codec:ident < $text_type:ty >)) => (
534        generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [], children: [], text: ($(#[$text_meta])* $text_ident: $codec<$text_type>));
535    );
536    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_action:tt<$attr_type:ty> = $attr_name:tt),+], text: ($(#[$text_meta:meta])* $text_ident:ident: $codec:ident < $text_type:ty >)) => (
537        generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [$($(#[$attr_meta])* $attr: $attr_action<$attr_type> = $attr_name),*], children: [], text: ($(#[$text_meta])* $text_ident: $codec<$text_type>));
538    );
539    ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_action:tt<$attr_type:ty> = $attr_name:tt),*], children: [$($(#[$child_meta:meta])* $child_ident:ident: $coucou:tt<$child_type:ty> = ($child_name:tt, $child_ns:ident) => $child_constructor:ident),*] $(, text: ($(#[$text_meta:meta])* $text_ident:ident: $codec:ident < $text_type:ty >))*) => (
540        $(#[$meta])*
541        #[derive(Debug, Clone)]
542        pub struct $elem {
543            $(
544                $(#[$attr_meta])*
545                pub $attr: decl_attr!($attr_action, $attr_type),
546            )*
547            $(
548                $(#[$child_meta])*
549                pub $child_ident: start_decl!($coucou, $child_type),
550            )*
551            $(
552                $(#[$text_meta])*
553                pub $text_ident: $text_type,
554            )*
555        }
556
557        impl ::try_from::TryFrom<::minidom::Element> for $elem {
558            type Err = crate::util::error::Error;
559
560            fn try_from(elem: ::minidom::Element) -> Result<$elem, crate::util::error::Error> {
561                check_self!(elem, $name, $ns);
562                check_no_unknown_attributes!(elem, $name, [$($attr_name),*]);
563                $(
564                    start_parse_elem!($child_ident: $coucou);
565                )*
566                for _child in elem.children() {
567                    $(
568                    if _child.is($child_name, crate::ns::$child_ns) {
569                        do_parse_elem!($child_ident: $coucou = $child_constructor => _child, $child_name, $name);
570                        continue;
571                    }
572                    )*
573                    return Err(crate::util::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                    $(
580                        $child_ident: finish_parse_elem!($child_ident: $coucou = $child_name, $name),
581                    )*
582                    $(
583                        $text_ident: $codec::decode(&elem.text())?,
584                    )*
585                })
586            }
587        }
588
589        impl From<$elem> for ::minidom::Element {
590            fn from(elem: $elem) -> ::minidom::Element {
591                ::minidom::Element::builder($name)
592                    .ns(crate::ns::$ns)
593                    $(
594                        .attr($attr_name, elem.$attr)
595                    )*
596                    $(
597                        .append(generate_serialiser!(elem, $child_ident, $coucou, $child_constructor, ($child_name, $child_ns)))
598                    )*
599                    $(
600                        .append($codec::encode(&elem.$text_ident))
601                    )*
602                    .build()
603            }
604        }
605    );
606}
607
608#[cfg(test)]
609macro_rules! assert_size (
610    ($t:ty, $sz:expr) => (
611        assert_eq!(::std::mem::size_of::<$t>(), $sz);
612    );
613);
614
615// TODO: move that to src/pubsub/mod.rs, once we figure out how to use macros from there.
616macro_rules! impl_pubsub_item {
617    ($item:ident, $ns:ident) => {
618        impl crate::TryFrom<crate::Element> for $item {
619            type Err = Error;
620
621            fn try_from(elem: crate::Element) -> Result<$item, Error> {
622                check_self!(elem, "item", $ns);
623                check_no_unknown_attributes!(elem, "item", ["id", "publisher"]);
624                let mut payloads = elem.children().cloned().collect::<Vec<_>>();
625                let payload = payloads.pop();
626                if !payloads.is_empty() {
627                    return Err(Error::ParseError(
628                        "More than a single payload in item element.",
629                    ));
630                }
631                Ok($item(crate::pubsub::Item {
632                    id: get_attr!(elem, "id", Option),
633                    publisher: get_attr!(elem, "publisher", Option),
634                    payload,
635                }))
636            }
637        }
638
639        impl From<$item> for crate::Element {
640            fn from(item: $item) -> crate::Element {
641                crate::Element::builder("item")
642                    .ns(ns::$ns)
643                    .attr("id", item.0.id)
644                    .attr("publisher", item.0.publisher)
645                    .append(item.0.payload)
646                    .build()
647            }
648        }
649
650        impl ::std::ops::Deref for $item {
651            type Target = crate::pubsub::Item;
652
653            fn deref(&self) -> &Self::Target {
654                &self.0
655            }
656        }
657
658        impl ::std::ops::DerefMut for $item {
659            fn deref_mut(&mut self) -> &mut Self::Target {
660                &mut self.0
661            }
662        }
663    }
664}