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<crate::Element> for $elem {
234 type Error = crate::util::error::Error;
235 fn try_from(elem: crate::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 crate::Element {
246 fn from(elem: $elem) -> crate::Element {
247 crate::Element::builder(
248 match elem {
249 $($elem::$enum => $enum_name,)+
250 }
251 )
252 .ns(crate::ns::$ns)
253 .build()
254 }
255 }
256 impl From<$elem> for ::minidom::Node {
257 fn from(elem: $elem) -> ::minidom::Node {
258 ::minidom::Node::Element(elem.into())
259 }
260 }
261 );
262}
263
264macro_rules! generate_attribute_enum {
265 ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, $attr:tt, {$($(#[$enum_meta:meta])* $enum:ident => $enum_name:tt),+,}) => (
266 generate_attribute_enum!($(#[$meta])* $elem, $name, $ns, $attr, {$($(#[$enum_meta])* $enum => $enum_name),+});
267 );
268 ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, $attr:tt, {$($(#[$enum_meta:meta])* $enum:ident => $enum_name:tt),+}) => (
269 $(#[$meta])*
270 #[derive(Debug, Clone, PartialEq)]
271 pub enum $elem {
272 $(
273 $(#[$enum_meta])*
274 $enum
275 ),+
276 }
277 impl ::std::convert::TryFrom<crate::Element> for $elem {
278 type Error = crate::util::error::Error;
279 fn try_from(elem: crate::Element) -> Result<$elem, crate::util::error::Error> {
280 check_ns_only!(elem, $name, $ns);
281 check_no_children!(elem, $name);
282 check_no_unknown_attributes!(elem, $name, [$attr]);
283 Ok(match get_attr!(elem, $attr, Required) {
284 $($enum_name => $elem::$enum,)+
285 _ => return Err(crate::util::error::Error::ParseError(concat!("Invalid ", $name, " ", $attr, " value."))),
286 })
287 }
288 }
289 impl From<$elem> for crate::Element {
290 fn from(elem: $elem) -> crate::Element {
291 crate::Element::builder($name)
292 .ns(crate::ns::$ns)
293 .attr($attr, match elem {
294 $($elem::$enum => $enum_name,)+
295 })
296 .build()
297 }
298 }
299 impl From<$elem> for ::minidom::Node {
300 fn from(elem: $elem) -> ::minidom::Node {
301 ::minidom::Node::Element(elem.into())
302 }
303 }
304 );
305}
306
307macro_rules! check_self {
308 ($elem:ident, $name:tt, $ns:ident) => {
309 check_self!($elem, $name, $ns, $name);
310 };
311 ($elem:ident, $name:tt, $ns:ident, $pretty_name:tt) => {
312 if !$elem.is($name, crate::ns::$ns) {
313 return Err(crate::util::error::Error::ParseError(concat!(
314 "This is not a ",
315 $pretty_name,
316 " element."
317 )));
318 }
319 };
320}
321
322macro_rules! check_ns_only {
323 ($elem:ident, $name:tt, $ns:ident) => {
324 if !$elem.has_ns(crate::ns::$ns) {
325 return Err(crate::util::error::Error::ParseError(concat!(
326 "This is not a ",
327 $name,
328 " element."
329 )));
330 }
331 };
332}
333
334macro_rules! check_no_children {
335 ($elem:ident, $name:tt) => {
336 #[cfg(not(feature = "disable-validation"))]
337 for _ in $elem.children() {
338 return Err(crate::util::error::Error::ParseError(concat!(
339 "Unknown child in ",
340 $name,
341 " element."
342 )));
343 }
344 };
345}
346
347macro_rules! check_no_attributes {
348 ($elem:ident, $name:tt) => {
349 #[cfg(not(feature = "disable-validation"))]
350 for _ in $elem.attrs() {
351 return Err(crate::util::error::Error::ParseError(concat!(
352 "Unknown attribute in ",
353 $name,
354 " element."
355 )));
356 }
357 };
358}
359
360macro_rules! check_no_unknown_attributes {
361 ($elem:ident, $name:tt, [$($attr:tt),*]) => (
362 #[cfg(not(feature = "disable-validation"))]
363 for (_attr, _) in $elem.attrs() {
364 $(
365 if _attr == $attr {
366 continue;
367 }
368 )*
369 return Err(crate::util::error::Error::ParseError(concat!("Unknown attribute in ", $name, " element.")));
370 }
371 );
372}
373
374macro_rules! generate_empty_element {
375 ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident) => (
376 $(#[$meta])*
377 #[derive(Debug, Clone)]
378 pub struct $elem;
379
380 impl ::std::convert::TryFrom<crate::Element> for $elem {
381 type Error = crate::util::error::Error;
382
383 fn try_from(elem: crate::Element) -> Result<$elem, crate::util::error::Error> {
384 check_self!(elem, $name, $ns);
385 check_no_children!(elem, $name);
386 check_no_attributes!(elem, $name);
387 Ok($elem)
388 }
389 }
390
391 impl From<$elem> for crate::Element {
392 fn from(_: $elem) -> crate::Element {
393 crate::Element::builder($name)
394 .ns(crate::ns::$ns)
395 .build()
396 }
397 }
398
399 impl From<$elem> for ::minidom::Node {
400 fn from(elem: $elem) -> ::minidom::Node {
401 ::minidom::Node::Element(elem.into())
402 }
403 }
404 );
405}
406
407macro_rules! generate_id {
408 ($(#[$meta:meta])* $elem:ident) => (
409 $(#[$meta])*
410 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
411 pub struct $elem(pub String);
412 impl ::std::str::FromStr for $elem {
413 type Err = crate::util::error::Error;
414 fn from_str(s: &str) -> Result<$elem, crate::util::error::Error> {
415 // TODO: add a way to parse that differently when needed.
416 Ok($elem(String::from(s)))
417 }
418 }
419 impl ::minidom::IntoAttributeValue for $elem {
420 fn into_attribute_value(self) -> Option<String> {
421 Some(self.0)
422 }
423 }
424 );
425}
426
427macro_rules! generate_elem_id {
428 ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident) => (
429 generate_elem_id!($(#[$meta])* $elem, $name, $ns, String);
430 impl ::std::str::FromStr for $elem {
431 type Err = crate::util::error::Error;
432 fn from_str(s: &str) -> Result<$elem, crate::util::error::Error> {
433 // TODO: add a way to parse that differently when needed.
434 Ok($elem(String::from(s)))
435 }
436 }
437 );
438 ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, $type:ty) => (
439 $(#[$meta])*
440 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
441 pub struct $elem(pub $type);
442 impl ::std::convert::TryFrom<crate::Element> for $elem {
443 type Error = crate::util::error::Error;
444 fn try_from(elem: crate::Element) -> Result<$elem, crate::util::error::Error> {
445 check_self!(elem, $name, $ns);
446 check_no_children!(elem, $name);
447 check_no_attributes!(elem, $name);
448 // TODO: add a way to parse that differently when needed.
449 Ok($elem(elem.text().parse()?))
450 }
451 }
452 impl From<$elem> for crate::Element {
453 fn from(elem: $elem) -> crate::Element {
454 crate::Element::builder($name)
455 .ns(crate::ns::$ns)
456 .append(elem.0.to_string())
457 .build()
458 }
459 }
460
461 impl From<$elem> for ::minidom::Node {
462 fn from(elem: $elem) -> ::minidom::Node {
463 ::minidom::Node::Element(elem.into())
464 }
465 }
466 );
467}
468
469macro_rules! decl_attr {
470 (OptionEmpty, $type:ty) => (
471 Option<$type>
472 );
473 (Option, $type:ty) => (
474 Option<$type>
475 );
476 (Required, $type:ty) => (
477 $type
478 );
479 (RequiredNonEmpty, $type:ty) => (
480 $type
481 );
482 (Default, $type:ty) => (
483 $type
484 );
485}
486
487macro_rules! start_decl {
488 (Vec, $type:ty) => (
489 Vec<$type>
490 );
491 (Option, $type:ty) => (
492 Option<$type>
493 );
494 (Required, $type:ty) => (
495 $type
496 );
497 (Present, $type:ty) => (
498 bool
499 );
500}
501
502macro_rules! start_parse_elem {
503 ($temp:ident: Vec) => {
504 let mut $temp = Vec::new();
505 };
506 ($temp:ident: Option) => {
507 let mut $temp = None;
508 };
509 ($temp:ident: Required) => {
510 let mut $temp = None;
511 };
512 ($temp:ident: Present) => {
513 let mut $temp = false;
514 };
515}
516
517macro_rules! do_parse {
518 ($elem:ident, Element) => {
519 $elem.clone()
520 };
521 ($elem:ident, String) => {
522 $elem.text()
523 };
524 ($elem:ident, $constructor:ident) => {
525 $constructor::try_from($elem.clone())?
526 };
527}
528
529macro_rules! do_parse_elem {
530 ($temp:ident: Vec = $constructor:ident => $elem:ident, $name:tt, $parent_name:tt) => {
531 $temp.push(do_parse!($elem, $constructor));
532 };
533 ($temp:ident: Option = $constructor:ident => $elem:ident, $name:tt, $parent_name:tt) => {
534 if $temp.is_some() {
535 return Err(crate::util::error::Error::ParseError(concat!(
536 "Element ",
537 $parent_name,
538 " must not have more than one ",
539 $name,
540 " child."
541 )));
542 }
543 $temp = Some(do_parse!($elem, $constructor));
544 };
545 ($temp:ident: Required = $constructor:ident => $elem:ident, $name:tt, $parent_name:tt) => {
546 if $temp.is_some() {
547 return Err(crate::util::error::Error::ParseError(concat!(
548 "Element ",
549 $parent_name,
550 " must not have more than one ",
551 $name,
552 " child."
553 )));
554 }
555 $temp = Some(do_parse!($elem, $constructor));
556 };
557 ($temp:ident: Present = $constructor:ident => $elem:ident, $name:tt, $parent_name:tt) => {
558 if $temp {
559 return Err(crate::util::error::Error::ParseError(concat!(
560 "Element ",
561 $parent_name,
562 " must not have more than one ",
563 $name,
564 " child."
565 )));
566 }
567 $temp = true;
568 };
569}
570
571macro_rules! finish_parse_elem {
572 ($temp:ident: Vec = $name:tt, $parent_name:tt) => {
573 $temp
574 };
575 ($temp:ident: Option = $name:tt, $parent_name:tt) => {
576 $temp
577 };
578 ($temp:ident: Required = $name:tt, $parent_name:tt) => {
579 $temp.ok_or(crate::util::error::Error::ParseError(concat!(
580 "Missing child ",
581 $name,
582 " in ",
583 $parent_name,
584 " element."
585 )))?
586 };
587 ($temp:ident: Present = $name:tt, $parent_name:tt) => {
588 $temp
589 };
590}
591
592macro_rules! generate_serialiser {
593 ($builder:ident, $parent:ident, $elem:ident, Required, String, ($name:tt, $ns:ident)) => {
594 $builder.append(
595 crate::Element::builder($name)
596 .ns(crate::ns::$ns)
597 .append(::minidom::Node::Text($parent.$elem))
598 )
599 };
600 ($builder:ident, $parent:ident, $elem:ident, Option, String, ($name:tt, $ns:ident)) => {
601 $builder.append_all($parent.$elem.map(|elem| {
602 crate::Element::builder($name)
603 .ns(crate::ns::$ns)
604 .append(::minidom::Node::Text(elem))
605 })
606 )
607 };
608 ($builder:ident, $parent:ident, $elem:ident, Option, $constructor:ident, ($name:tt, *)) => {
609 $builder.append_all($parent.$elem.map(|elem| {
610 crate::Element::builder($name)
611 .ns(elem.get_ns())
612 .append(::minidom::Node::Element(crate::Element::from(elem)))
613 })
614 )
615 };
616 ($builder:ident, $parent:ident, $elem:ident, Option, $constructor:ident, ($name:tt, $ns:ident)) => {
617 $builder.append_all($parent.$elem.map(|elem| {
618 crate::Element::builder($name)
619 .ns(crate::ns::$ns)
620 .append(::minidom::Node::Element(crate::Element::from(elem)))
621 })
622 )
623 };
624 ($builder:ident, $parent:ident, $elem:ident, Vec, $constructor:ident, ($name:tt, $ns:ident)) => {
625 $builder.append_all($parent.$elem.into_iter())
626 };
627 ($builder:ident, $parent:ident, $elem:ident, Present, $constructor:ident, ($name:tt, $ns:ident)) => {
628 $builder.append(::minidom::Node::Element(crate::Element::builder($name).ns(crate::ns::$ns).build()))
629 };
630 ($builder:ident, $parent:ident, $elem:ident, $_:ident, $constructor:ident, ($name:tt, $ns:ident)) => {
631 $builder.append(::minidom::Node::Element(crate::Element::from($parent.$elem)))
632 };
633}
634
635macro_rules! generate_child_test {
636 ($child:ident, $name:tt, *) => {
637 true
638 };
639 ($child:ident, $name:tt, $ns:tt) => {
640 $child.is($name, crate::ns::$ns)
641 };
642}
643
644macro_rules! generate_element {
645 ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_action:tt<$attr_type:ty> = $attr_name:tt),+,]) => (
646 generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [$($(#[$attr_meta])* $attr: $attr_action<$attr_type> = $attr_name),*], children: []);
647 );
648 ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_action:tt<$attr_type:ty> = $attr_name:tt),+]) => (
649 generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [$($(#[$attr_meta])* $attr: $attr_action<$attr_type> = $attr_name),*], children: []);
650 );
651 ($(#[$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),*]) => (
652 generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [], children: [$($(#[$child_meta])* $child_ident: $coucou<$child_type> = ($child_name, $child_ns) => $child_constructor),*]);
653 );
654 ($(#[$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),*]) => (
655 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),*]);
656 );
657 ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, text: ($(#[$text_meta:meta])* $text_ident:ident: $codec:ident < $text_type:ty >)) => (
658 generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [], children: [], text: ($(#[$text_meta])* $text_ident: $codec<$text_type>));
659 );
660 ($(#[$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 >)) => (
661 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>));
662 );
663 ($(#[$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 >))*) => (
664 $(#[$meta])*
665 #[derive(Debug, Clone)]
666 pub struct $elem {
667 $(
668 $(#[$attr_meta])*
669 pub $attr: decl_attr!($attr_action, $attr_type),
670 )*
671 $(
672 $(#[$child_meta])*
673 pub $child_ident: start_decl!($coucou, $child_type),
674 )*
675 $(
676 $(#[$text_meta])*
677 pub $text_ident: $text_type,
678 )*
679 }
680
681 impl ::std::convert::TryFrom<crate::Element> for $elem {
682 type Error = crate::util::error::Error;
683
684 fn try_from(elem: crate::Element) -> Result<$elem, crate::util::error::Error> {
685 check_self!(elem, $name, $ns);
686 check_no_unknown_attributes!(elem, $name, [$($attr_name),*]);
687 $(
688 start_parse_elem!($child_ident: $coucou);
689 )*
690 for _child in elem.children() {
691 $(
692 if generate_child_test!(_child, $child_name, $child_ns) {
693 do_parse_elem!($child_ident: $coucou = $child_constructor => _child, $child_name, $name);
694 continue;
695 }
696 )*
697 return Err(crate::util::error::Error::ParseError(concat!("Unknown child in ", $name, " element.")));
698 }
699 Ok($elem {
700 $(
701 $attr: get_attr!(elem, $attr_name, $attr_action),
702 )*
703 $(
704 $child_ident: finish_parse_elem!($child_ident: $coucou = $child_name, $name),
705 )*
706 $(
707 $text_ident: $codec::decode(&elem.text())?,
708 )*
709 })
710 }
711 }
712
713 impl From<$elem> for crate::Element {
714 fn from(elem: $elem) -> crate::Element {
715 let mut builder = crate::Element::builder($name)
716 .ns(crate::ns::$ns);
717 $(
718 builder = builder.attr($attr_name, elem.$attr);
719 )*
720 $(
721 builder = generate_serialiser!(builder, elem, $child_ident, $coucou, $child_constructor, ($child_name, $child_ns));
722 )*
723 $(
724 builder = builder.append_all($codec::encode(&elem.$text_ident).map(::minidom::Node::Text).into_iter());
725 )*
726
727 builder.build()
728 }
729 }
730
731 impl From<$elem> for ::minidom::Node {
732 fn from(elem: $elem) -> ::minidom::Node {
733 ::minidom::Node::Element(elem.into())
734 }
735 }
736 );
737}
738
739#[cfg(test)]
740macro_rules! assert_size (
741 ($t:ty, $sz:expr) => (
742 assert_eq!(::std::mem::size_of::<$t>(), $sz);
743 );
744);
745
746// TODO: move that to src/pubsub/mod.rs, once we figure out how to use macros from there.
747macro_rules! impl_pubsub_item {
748 ($item:ident, $ns:ident) => {
749 impl ::std::convert::TryFrom<crate::Element> for $item {
750 type Error = Error;
751
752 fn try_from(elem: crate::Element) -> Result<$item, Error> {
753 check_self!(elem, "item", $ns);
754 check_no_unknown_attributes!(elem, "item", ["id", "publisher"]);
755 let mut payloads = elem.children().cloned().collect::<Vec<_>>();
756 let payload = payloads.pop();
757 if !payloads.is_empty() {
758 return Err(Error::ParseError(
759 "More than a single payload in item element.",
760 ));
761 }
762 Ok($item(crate::pubsub::Item {
763 id: get_attr!(elem, "id", Option),
764 publisher: get_attr!(elem, "publisher", Option),
765 payload,
766 }))
767 }
768 }
769
770 impl From<$item> for crate::Element {
771 fn from(item: $item) -> crate::Element {
772 crate::Element::builder("item")
773 .ns(ns::$ns)
774 .attr("id", item.0.id)
775 .attr("publisher", item.0.publisher)
776 .append_all(item.0.payload)
777 .build()
778 }
779 }
780
781 impl From<$item> for ::minidom::Node {
782 fn from(item: $item) -> ::minidom::Node {
783 ::minidom::Node::Element(item.into())
784 }
785 }
786
787 impl ::std::ops::Deref for $item {
788 type Target = crate::pubsub::Item;
789
790 fn deref(&self) -> &Self::Target {
791 &self.0
792 }
793 }
794
795 impl ::std::ops::DerefMut for $item {
796 fn deref_mut(&mut self) -> &mut Self::Target {
797 &mut self.0
798 }
799 }
800 }
801}