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