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