1// Copyright (c) 2017 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, optional_empty, $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, optional, $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 => return Err(Error::ParseError(concat!("Required attribute '", $attr, "' missing."))),
28 }
29 );
30 ($elem:ident, $attr:tt, default, $value:ident, $func:expr) => (
31 match $elem.attr($attr) {
32 Some($value) => $func,
33 None => Default::default(),
34 }
35 );
36}
37
38macro_rules! generate_attribute {
39 ($elem:ident, $name:tt, {$($a:ident => $b:tt),+,}) => (
40 generate_attribute!($elem, $name, {$($a => $b),+});
41 );
42 ($elem:ident, $name:tt, {$($a:ident => $b:tt),+,}, Default = $default:ident) => (
43 generate_attribute!($elem, $name, {$($a => $b),+}, Default = $default);
44 );
45 ($elem:ident, $name:tt, {$($a:ident => $b:tt),+}) => (
46 #[derive(Debug, Clone, PartialEq)]
47 pub enum $elem {
48 $(
49 #[doc=$b]
50 #[doc="value for this attribute."]
51 $a
52 ),+
53 }
54 impl FromStr for $elem {
55 type Err = Error;
56 fn from_str(s: &str) -> Result<$elem, Error> {
57 Ok(match s {
58 $($b => $elem::$a),+,
59 _ => return Err(Error::ParseError(concat!("Unknown value for '", $name, "' attribute."))),
60 })
61 }
62 }
63 impl IntoAttributeValue for $elem {
64 fn into_attribute_value(self) -> Option<String> {
65 Some(String::from(match self {
66 $($elem::$a => $b),+
67 }))
68 }
69 }
70 );
71 ($elem:ident, $name:tt, {$($a:ident => $b:tt),+}, Default = $default:ident) => (
72 #[derive(Debug, Clone, PartialEq)]
73 pub enum $elem {
74 $(
75 #[doc=$b]
76 #[doc="value for this attribute."]
77 $a
78 ),+
79 }
80 impl FromStr for $elem {
81 type Err = Error;
82 fn from_str(s: &str) -> Result<$elem, Error> {
83 Ok(match s {
84 $($b => $elem::$a),+,
85 _ => return Err(Error::ParseError(concat!("Unknown value for '", $name, "' attribute."))),
86 })
87 }
88 }
89 impl IntoAttributeValue for $elem {
90 #[allow(unreachable_patterns)]
91 fn into_attribute_value(self) -> Option<String> {
92 Some(String::from(match self {
93 $elem::$default => return None,
94 $($elem::$a => $b),+
95 }))
96 }
97 }
98 impl Default for $elem {
99 fn default() -> $elem {
100 $elem::$default
101 }
102 }
103 );
104}
105
106macro_rules! generate_element_enum {
107 ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:expr, {$($(#[$enum_meta:meta])* $enum:ident => $enum_name:tt),+,}) => (
108 generate_element_enum!($(#[$meta])* $elem, $name, $ns, {$($(#[$enum_meta])* $enum => $enum_name),+});
109 );
110 ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:expr, {$($(#[$enum_meta:meta])* $enum:ident => $enum_name:tt),+}) => (
111 $(#[$meta])*
112 #[derive(Debug, Clone, PartialEq)]
113 pub enum $elem {
114 $(
115 $(#[$enum_meta])*
116 $enum
117 ),+
118 }
119 impl TryFrom<Element> for $elem {
120 type Err = Error;
121 fn try_from(elem: Element) -> Result<$elem, Error> {
122 check_ns_only!(elem, $name, $ns);
123 check_no_children!(elem, $name);
124 check_no_attributes!(elem, $name);
125 Ok(match elem.name() {
126 $($enum_name => $elem::$enum,)+
127 _ => return Err(Error::ParseError(concat!("This is not a ", $name, " element."))),
128 })
129 }
130 }
131 impl From<$elem> for Element {
132 fn from(elem: $elem) -> Element {
133 Element::builder(match elem {
134 $($elem::$enum => $enum_name,)+
135 }).ns($ns)
136 .build()
137 }
138 }
139 );
140}
141
142macro_rules! check_self {
143 ($elem:ident, $name:tt, $ns:expr) => (
144 check_self!($elem, $name, $ns, $name);
145 );
146 ($elem:ident, $name:tt, $ns:expr, $pretty_name:tt) => (
147 if !$elem.is($name, $ns) {
148 return Err(Error::ParseError(concat!("This is not a ", $pretty_name, " element.")));
149 }
150 );
151}
152
153macro_rules! check_ns_only {
154 ($elem:ident, $name:tt, $ns:expr) => (
155 if !$elem.has_ns($ns) {
156 return Err(Error::ParseError(concat!("This is not a ", $name, " element.")));
157 }
158 );
159}
160
161macro_rules! check_no_children {
162 ($elem:ident, $name:tt) => (
163 for _ in $elem.children() {
164 return Err(Error::ParseError(concat!("Unknown child in ", $name, " element.")));
165 }
166 );
167}
168
169macro_rules! check_no_attributes {
170 ($elem:ident, $name:tt) => (
171 check_no_unknown_attributes!($elem, $name, []);
172 );
173}
174
175macro_rules! check_no_unknown_attributes {
176 ($elem:ident, $name:tt, [$($attr:tt),*]) => (
177 for (_attr, _) in $elem.attrs() {
178 $(
179 if _attr == $attr {
180 continue;
181 }
182 )*
183 return Err(Error::ParseError(concat!("Unknown attribute in ", $name, " element.")));
184 }
185 );
186}
187
188macro_rules! generate_empty_element {
189 ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:expr) => (
190 $(#[$meta])*
191 #[derive(Debug, Clone)]
192 pub struct $elem;
193
194 impl TryFrom<Element> for $elem {
195 type Err = Error;
196
197 fn try_from(elem: Element) -> Result<$elem, Error> {
198 check_self!(elem, $name, $ns);
199 check_no_children!(elem, $name);
200 check_no_attributes!(elem, $name);
201 Ok($elem)
202 }
203 }
204
205 impl From<$elem> for Element {
206 fn from(_: $elem) -> Element {
207 Element::builder($name)
208 .ns($ns)
209 .build()
210 }
211 }
212 );
213}
214
215macro_rules! generate_element_with_only_attributes {
216 ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:expr, [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),+,]) => (
217 generate_element_with_only_attributes!($(#[$meta])* $elem, $name, $ns, [$($(#[$attr_meta])* $attr: $attr_type = $attr_name => $attr_action),*]);
218 );
219 ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:expr, [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),+]) => (
220 $(#[$meta])*
221 #[derive(Debug, Clone)]
222 pub struct $elem {
223 $(
224 $(#[$attr_meta])*
225 pub $attr: $attr_type,
226 )*
227 }
228
229 impl TryFrom<Element> for $elem {
230 type Err = Error;
231
232 fn try_from(elem: Element) -> Result<$elem, Error> {
233 check_self!(elem, $name, $ns);
234 check_no_children!(elem, $name);
235 check_no_unknown_attributes!(elem, $name, [$($attr_name),*]);
236 Ok($elem {
237 $(
238 $attr: get_attr!(elem, $attr_name, $attr_action),
239 )*
240 })
241 }
242 }
243
244 impl From<$elem> for Element {
245 fn from(elem: $elem) -> Element {
246 Element::builder($name)
247 .ns($ns)
248 $(
249 .attr($attr_name, elem.$attr)
250 )*
251 .build()
252 }
253 }
254 );
255}
256
257macro_rules! generate_id {
258 ($elem:ident) => (
259 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
260 pub struct $elem(pub String);
261 impl FromStr for $elem {
262 type Err = Error;
263 fn from_str(s: &str) -> Result<$elem, Error> {
264 // TODO: add a way to parse that differently when needed.
265 Ok($elem(String::from(s)))
266 }
267 }
268 impl IntoAttributeValue for $elem {
269 fn into_attribute_value(self) -> Option<String> {
270 Some(self.0)
271 }
272 }
273 );
274}
275
276macro_rules! generate_elem_id {
277 ($elem:ident, $name:tt, $ns:expr) => (
278 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
279 pub struct $elem(pub String);
280 impl FromStr for $elem {
281 type Err = Error;
282 fn from_str(s: &str) -> Result<$elem, Error> {
283 // TODO: add a way to parse that differently when needed.
284 Ok($elem(String::from(s)))
285 }
286 }
287 impl TryFrom<Element> for $elem {
288 type Err = Error;
289 fn try_from(elem: Element) -> Result<$elem, Error> {
290 check_self!(elem, $name, $ns);
291 check_no_children!(elem, $name);
292 check_no_attributes!(elem, $name);
293 // TODO: add a way to parse that differently when needed.
294 Ok($elem(elem.text()))
295 }
296 }
297 impl From<$elem> for Element {
298 fn from(elem: $elem) -> Element {
299 Element::builder($name)
300 .ns($ns)
301 .append(elem.0)
302 .build()
303 }
304 }
305 );
306}
307
308macro_rules! generate_element_with_text {
309 ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:expr, [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),+], $text_ident:ident: $codec:ident < $text_type:ty >) => (
310 $(#[$meta])*
311 #[derive(Debug, Clone)]
312 pub struct $elem {
313 $(
314 $(#[$attr_meta])*
315 pub $attr: $attr_type,
316 )*
317 pub $text_ident: $text_type,
318 }
319
320 impl TryFrom<Element> for $elem {
321 type Err = Error;
322
323 fn try_from(elem: Element) -> Result<$elem, Error> {
324 check_self!(elem, $name, $ns);
325 check_no_children!(elem, $name);
326 check_no_unknown_attributes!(elem, $name, [$($attr_name),*]);
327 Ok($elem {
328 $(
329 $attr: get_attr!(elem, $attr_name, $attr_action),
330 )*
331 $text_ident: $codec::decode(&elem.text())?,
332 })
333 }
334 }
335
336 impl From<$elem> for Element {
337 fn from(elem: $elem) -> Element {
338 Element::builder($name)
339 .ns($ns)
340 $(
341 .attr($attr_name, elem.$attr)
342 )*
343 .append($codec::encode(&elem.$text_ident))
344 .build()
345 }
346 }
347 );
348}
349
350macro_rules! generate_element_with_children {
351 ($(#[$meta:meta])* $elem:ident, $name:tt, $ns:expr, attributes: [$($(#[$attr_meta:meta])* $attr:ident: $attr_type:ty = $attr_name:tt => $attr_action:tt),+], children: [$($(#[$child_meta:meta])* $child_ident:ident: Vec<$child_type:ty> = ($child_name:tt, $child_ns:expr) => $child_constructor:ident),+]) => (
352 $(#[$meta])*
353 #[derive(Debug, Clone)]
354 pub struct $elem {
355 $(
356 $(#[$attr_meta])*
357 pub $attr: $attr_type,
358 )*
359 $(
360 $(#[$child_meta])*
361 pub $child_ident: Vec<$child_type>,
362 )*
363 }
364
365 impl TryFrom<Element> for $elem {
366 type Err = Error;
367
368 fn try_from(elem: Element) -> Result<$elem, Error> {
369 check_self!(elem, $name, $ns);
370 check_no_unknown_attributes!(elem, $name, [$($attr_name),*]);
371 let mut parsed_children = vec!();
372 for child in elem.children() {
373 $(
374 if child.is($child_name, $child_ns) {
375 let parsed_child = $child_constructor::try_from(child.clone())?;
376 parsed_children.push(parsed_child);
377 continue;
378 }
379 )*
380 return Err(Error::ParseError(concat!("Unknown child in ", $name, " element.")));
381 }
382 Ok($elem {
383 $(
384 $attr: get_attr!(elem, $attr_name, $attr_action),
385 )*
386 $(
387 $child_ident: parsed_children,
388 )*
389 })
390 }
391 }
392
393 impl From<$elem> for Element {
394 fn from(elem: $elem) -> Element {
395 Element::builder($name)
396 .ns($ns)
397 $(
398 .attr($attr_name, elem.$attr)
399 )*
400 $(
401 .append(elem.$child_ident)
402 )*
403 .build()
404 }
405 }
406 );
407}