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