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