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 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<::minidom::Element> for $elem {
278 type Error = crate::util::error::Error;
279 fn try_from(elem: ::minidom::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 ::minidom::Element {
290 fn from(elem: $elem) -> ::minidom::Element {
291 ::minidom::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<::minidom::Element> for $elem {
381 type Error = crate::util::error::Error;
382
383 fn try_from(elem: ::minidom::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 ::minidom::Element {
392 fn from(_: $elem) -> ::minidom::Element {
393 ::minidom::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<::minidom::Element> for $elem {
443 type Error = crate::util::error::Error;
444 fn try_from(elem: ::minidom::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 ::minidom::Element {
453 fn from(elem: $elem) -> ::minidom::Element {
454 ::minidom::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}
498
499macro_rules! start_parse_elem {
500 ($temp:ident: Vec) => {
501 let mut $temp = Vec::new();
502 };
503 ($temp:ident: Option) => {
504 let mut $temp = None;
505 };
506 ($temp:ident: Required) => {
507 let mut $temp = None;
508 };
509}
510
511macro_rules! do_parse {
512 ($elem:ident, Element) => {
513 $elem.clone()
514 };
515 ($elem:ident, String) => {
516 $elem.text()
517 };
518 ($elem:ident, $constructor:ident) => {
519 $constructor::try_from($elem.clone())?
520 };
521}
522
523macro_rules! do_parse_elem {
524 ($temp:ident: Vec = $constructor:ident => $elem:ident, $name:tt, $parent_name:tt) => {
525 $temp.push(do_parse!($elem, $constructor));
526 };
527 ($temp:ident: Option = $constructor:ident => $elem:ident, $name:tt, $parent_name:tt) => {
528 if $temp.is_some() {
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 = Some(do_parse!($elem, $constructor));
538 };
539 ($temp:ident: Required = $constructor:ident => $elem:ident, $name:tt, $parent_name:tt) => {
540 if $temp.is_some() {
541 return Err(crate::util::error::Error::ParseError(concat!(
542 "Element ",
543 $parent_name,
544 " must not have more than one ",
545 $name,
546 " child."
547 )));
548 }
549 $temp = Some(do_parse!($elem, $constructor));
550 };
551}
552
553macro_rules! finish_parse_elem {
554 ($temp:ident: Vec = $name:tt, $parent_name:tt) => {
555 $temp
556 };
557 ($temp:ident: Option = $name:tt, $parent_name:tt) => {
558 $temp
559 };
560 ($temp:ident: Required = $name:tt, $parent_name:tt) => {
561 $temp.ok_or(crate::util::error::Error::ParseError(concat!(
562 "Missing child ",
563 $name,
564 " in ",
565 $parent_name,
566 " element."
567 )))?
568 };
569}
570
571macro_rules! generate_serialiser {
572 ($builder:ident, $parent:ident, $elem:ident, Required, String, ($name:tt, $ns:ident)) => {
573 $builder.append(
574 ::minidom::Element::builder($name)
575 .ns(crate::ns::$ns)
576 .append(::minidom::Node::Text($parent.$elem))
577 )
578 };
579 ($builder:ident, $parent:ident, $elem:ident, Option, String, ($name:tt, $ns:ident)) => {
580 $builder.append_all($parent.$elem.map(|elem| {
581 ::minidom::Element::builder($name)
582 .ns(crate::ns::$ns)
583 .append(::minidom::Node::Text(elem))
584 })
585 )
586 };
587 ($builder:ident, $parent:ident, $elem:ident, Option, $constructor:ident, ($name:tt, $ns:ident)) => {
588 $builder.append_all($parent.$elem.map(|elem| {
589 ::minidom::Element::builder($name)
590 .ns(crate::ns::$ns)
591 .append(::minidom::Node::Element(::minidom::Element::from(elem)))
592 })
593 )
594 };
595 ($builder:ident, $parent:ident, $elem:ident, Vec, $constructor:ident, ($name:tt, $ns:ident)) => {
596 $builder.append_all($parent.$elem.into_iter())
597 };
598 ($builder:ident, $parent:ident, $elem:ident, $_:ident, $constructor:ident, ($name:tt, $ns:ident)) => {
599 $builder.append(::minidom::Node::Element(::minidom::Element::from($parent.$elem)))
600 };
601}
602
603macro_rules! generate_element {
604 ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_action:tt<$attr_type:ty> = $attr_name:tt),+,]) => (
605 generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [$($(#[$attr_meta])* $attr: $attr_action<$attr_type> = $attr_name),*], children: []);
606 );
607 ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_action:tt<$attr_type:ty> = $attr_name:tt),+]) => (
608 generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [$($(#[$attr_meta])* $attr: $attr_action<$attr_type> = $attr_name),*], children: []);
609 );
610 ($(#[$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),*]) => (
611 generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [], children: [$($(#[$child_meta])* $child_ident: $coucou<$child_type> = ($child_name, $child_ns) => $child_constructor),*]);
612 );
613 ($(#[$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),*]) => (
614 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),*]);
615 );
616 ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:ident, text: ($(#[$text_meta:meta])* $text_ident:ident: $codec:ident < $text_type:ty >)) => (
617 generate_element!($(#[$meta])* $elem, $name, $ns, attributes: [], children: [], text: ($(#[$text_meta])* $text_ident: $codec<$text_type>));
618 );
619 ($(#[$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 >)) => (
620 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>));
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),*], 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 >))*) => (
623 $(#[$meta])*
624 #[derive(Debug, Clone)]
625 pub struct $elem {
626 $(
627 $(#[$attr_meta])*
628 pub $attr: decl_attr!($attr_action, $attr_type),
629 )*
630 $(
631 $(#[$child_meta])*
632 pub $child_ident: start_decl!($coucou, $child_type),
633 )*
634 $(
635 $(#[$text_meta])*
636 pub $text_ident: $text_type,
637 )*
638 }
639
640 impl ::std::convert::TryFrom<::minidom::Element> for $elem {
641 type Error = crate::util::error::Error;
642
643 fn try_from(elem: ::minidom::Element) -> Result<$elem, crate::util::error::Error> {
644 check_self!(elem, $name, $ns);
645 check_no_unknown_attributes!(elem, $name, [$($attr_name),*]);
646 $(
647 start_parse_elem!($child_ident: $coucou);
648 )*
649 for _child in elem.children() {
650 $(
651 if _child.is($child_name, crate::ns::$child_ns) {
652 do_parse_elem!($child_ident: $coucou = $child_constructor => _child, $child_name, $name);
653 continue;
654 }
655 )*
656 return Err(crate::util::error::Error::ParseError(concat!("Unknown child in ", $name, " element.")));
657 }
658 Ok($elem {
659 $(
660 $attr: get_attr!(elem, $attr_name, $attr_action),
661 )*
662 $(
663 $child_ident: finish_parse_elem!($child_ident: $coucou = $child_name, $name),
664 )*
665 $(
666 $text_ident: $codec::decode(&elem.text())?,
667 )*
668 })
669 }
670 }
671
672 impl From<$elem> for ::minidom::Element {
673 fn from(elem: $elem) -> ::minidom::Element {
674 let mut builder = ::minidom::Element::builder($name)
675 .ns(crate::ns::$ns);
676 $(
677 builder = builder.attr($attr_name, elem.$attr);
678 )*
679 $(
680 builder = generate_serialiser!(builder, elem, $child_ident, $coucou, $child_constructor, ($child_name, $child_ns));
681 )*
682 $(
683 builder = builder.append_all($codec::encode(&elem.$text_ident).map(::minidom::Node::Text).into_iter());
684 )*
685
686 builder.build()
687 }
688 }
689
690 impl From<$elem> for ::minidom::Node {
691 fn from(elem: $elem) -> ::minidom::Node {
692 ::minidom::Node::Element(elem.into())
693 }
694 }
695 );
696}
697
698#[cfg(test)]
699macro_rules! assert_size (
700 ($t:ty, $sz:expr) => (
701 assert_eq!(::std::mem::size_of::<$t>(), $sz);
702 );
703);
704
705// TODO: move that to src/pubsub/mod.rs, once we figure out how to use macros from there.
706macro_rules! impl_pubsub_item {
707 ($item:ident, $ns:ident) => {
708 impl ::std::convert::TryFrom<crate::Element> for $item {
709 type Error = Error;
710
711 fn try_from(elem: crate::Element) -> Result<$item, Error> {
712 check_self!(elem, "item", $ns);
713 check_no_unknown_attributes!(elem, "item", ["id", "publisher"]);
714 let mut payloads = elem.children().cloned().collect::<Vec<_>>();
715 let payload = payloads.pop();
716 if !payloads.is_empty() {
717 return Err(Error::ParseError(
718 "More than a single payload in item element.",
719 ));
720 }
721 Ok($item(crate::pubsub::Item {
722 id: get_attr!(elem, "id", Option),
723 publisher: get_attr!(elem, "publisher", Option),
724 payload,
725 }))
726 }
727 }
728
729 impl From<$item> for crate::Element {
730 fn from(item: $item) -> crate::Element {
731 crate::Element::builder("item")
732 .ns(ns::$ns)
733 .attr("id", item.0.id)
734 .attr("publisher", item.0.publisher)
735 .append_all(item.0.payload)
736 .build()
737 }
738 }
739
740 impl From<$item> for ::minidom::Node {
741 fn from(item: $item) -> ::minidom::Node {
742 ::minidom::Node::Element(item.into())
743 }
744 }
745
746 impl ::std::ops::Deref for $item {
747 type Target = crate::pubsub::Item;
748
749 fn deref(&self) -> &Self::Target {
750 &self.0
751 }
752 }
753
754 impl ::std::ops::DerefMut for $item {
755 fn deref_mut(&mut self) -> &mut Self::Target {
756 &mut self.0
757 }
758 }
759 }
760}