rapid_xml/
tree.rs

1//! Contains XML tree serde Deserializer build on top of `Parser` from `parse` and `Deserializer`
2//! from `de`.
3
4use std::fmt;
5use std::io::Read;
6use std::marker::PhantomData;
7
8#[doc(hidden)]
9pub use paste::item as paste_item;
10use serde::de::DeserializeOwned;
11use tuple_utils::Prepend;
12
13use crate::de::{DeserializeError, Deserializer};
14use crate::parser::{EventCode, Parser};
15
16// Re-exported so we can use it in our macro. Is there better way?
17
18/// Utility that turns single-element tuple into that element and keeps multi-element tuples as
19/// they are
20pub trait DeTuple {
21    /// The output type - a single element or >=2 element tuple
22    type Output;
23
24    /// Perform the transformation
25    fn detuple(self) -> Self::Output;
26}
27
28impl<A> DeTuple for (A,) {
29    type Output = A;
30    fn detuple(self) -> Self::Output { self.0 }
31}
32
33macro_rules! detuple_impls {
34    ($i:ident, $j:ident) => {
35        detuple_impls!(impl $i, $j);
36    };
37
38    ($i:ident, $j:ident, $($r_i:ident),+) => {
39        detuple_impls!(impl $i, $j, $($r_i),+);
40        detuple_impls!($j, $($r_i),+);
41    };
42
43    (impl $($i:ident),+) => {
44        impl<$($i),+> DeTuple for ($($i),+) {
45            type Output = ($($i),+);
46            fn detuple(self) -> Self::Output { self }
47        }
48    };
49}
50
51detuple_impls!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
52
53
54/// Like the try! macro (i.e. ? operator), but wraps the error in Some before returning.
55macro_rules! try_some {
56    ($e:expr) => {
57        match $e {
58            Ok(v) => v,
59            Err(err) => return Some(Err(core::convert::From::from(err)))
60        }
61    }
62}
63
64/// Trait that determines whether given tag name matches some condition
65pub trait TagMatcher {
66    /// Does given `tag_name` match this matcher's condition?
67    fn matches(&self, tag_name: &str) -> bool;
68}
69
70/// Matches tags against needle provided as `'static str`
71#[derive(Debug, PartialEq)]
72pub struct ExactTagMatch {
73    needle: &'static str,
74}
75
76impl TagMatcher for ExactTagMatch {
77    #[inline(always)]
78    fn matches(&self, tag_name: &str) -> bool {
79        self.needle == tag_name
80    }
81}
82
83/// Matches all tags
84#[derive(Debug, Default, PartialEq)]
85pub struct AnyTagMatch {}
86
87impl TagMatcher for AnyTagMatch {
88    #[inline(always)]
89    fn matches(&self, _tag_name: &str) -> bool {
90        true
91    }
92}
93
94/// Part of path for `TreeDeserializer`.
95///
96/// Enters matched element in a tree, nothing is deserialized.
97///
98/// You may want to use the `xml_path!` macro rather than constructing path manually.
99#[derive(Debug)]
100pub struct ElementEnter<M, N> {
101    tag_matcher: M,
102
103    /// Next part of the path.
104    pub next: N,
105
106    entered: bool,
107}
108
109impl<M: Default, N: Default> Default for ElementEnter<M, N> {
110    fn default() -> Self {
111        Self {
112            tag_matcher: M::default(),
113            next: N::default(),
114            entered: false,
115        }
116    }
117}
118
119impl<M, N> ElementEnter<M, N> {
120    /// Create `ElementEnter` matching tag using given matcher
121    pub fn new(tag_matcher: M, next: N) -> Self {
122        Self { tag_matcher, next, entered: false }
123    }
124}
125
126impl<N> ElementEnter<ExactTagMatch, N> {
127    /// Create `ElementEnter` matching given tag
128    pub fn tag(tag: &'static str, next: N) -> Self {
129        Self::new(ExactTagMatch { needle: tag }, next)
130    }
131}
132
133impl<N> ElementEnter<AnyTagMatch, N> {
134    /// Create `ElementEnter` matching any tag
135    pub fn any(next: N) -> Self {
136        Self::new(AnyTagMatch {}, next)
137    }
138}
139
140/// Part of path for `TreeDeserializer`.
141///
142/// Enters matched element in a tree. It's attributes are deserialized into given Deserializable
143/// type and the deserializer proceeds with contained elements. The type must be `Clone` because it
144/// may be returned multiple times if there are multiple contained elements.
145///
146/// You may want to use the `xml_path!` macro rather than constructing path manually.
147pub struct ElementEnterDeserialize<T, M, N> {
148    tag_matcher: M,
149
150    /// Next part of the path.
151    pub next: N,
152
153    trace: Option<Box<dyn FnMut(&T)>>,
154
155    entered: Option<T>,
156}
157
158impl<T, M, N> fmt::Debug for ElementEnterDeserialize<T, M, N>
159    where T: fmt::Debug,
160          M: fmt::Debug,
161          N: fmt::Debug,
162{
163    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
164        f.debug_struct("ElementEnterDeserialize")
165            .field("tag_matcher", &self.tag_matcher)
166            .field("next", &self.next)
167            .field("entered", &self.entered)
168            .finish_non_exhaustive()
169    }
170}
171
172impl<T, M: Default, N: Default> Default for ElementEnterDeserialize<T, M, N> {
173    fn default() -> Self {
174        Self {
175            tag_matcher: M::default(),
176            next: N::default(),
177            trace: None,
178            entered: None,
179        }
180    }
181}
182
183impl<T, M, N> ElementEnterDeserialize<T, M, N> {
184    /// Create `ElementEnterDeserialize` matching tag using given matcher
185    pub fn new(tag_matcher: M, next: N) -> Self {
186        Self { tag_matcher, next, trace: None, entered: None }
187    }
188
189    /// Set the trace callback to be called each time the start tag is successfully parsed.
190    pub fn set_trace(&mut self, f: impl FnMut(&T) + 'static) {
191        self.trace = Some(Box::new(f) as Box<_>);
192    }
193}
194
195impl<T, N> ElementEnterDeserialize<T, ExactTagMatch, N> {
196    /// Create `ElementEnterDeserialize` matching given tag
197    pub fn tag(tag: &'static str, next: N) -> Self {
198        Self::new(ExactTagMatch { needle: tag }, next)
199    }
200}
201
202impl<T, N> ElementEnterDeserialize<T, AnyTagMatch, N> {
203    /// Create `ElementEnterDeserialize` matching any tag
204    pub fn any(next: N) -> Self {
205        Self::new(AnyTagMatch {}, next)
206    }
207}
208
209/// Part of path for `TreeDeserializer`.
210///
211/// Deserializes matched element. This is the final component of every path. The matched element and
212/// all nested elements are deserialized into given type.
213///
214/// You may want to use the `xml_path!` macro rather than constructing path manually.
215#[derive(Debug, PartialEq)]
216pub struct ElementDeserialize<T: DeserializeOwned, M> {
217    tag_matcher: M,
218    _phantom: PhantomData<T>,
219}
220
221impl<T: DeserializeOwned, M: Default> Default for ElementDeserialize<T, M> {
222    fn default() -> Self {
223        Self {
224            tag_matcher: M::default(),
225            _phantom: PhantomData,
226        }
227    }
228}
229
230impl<T: DeserializeOwned, M> ElementDeserialize<T, M> {
231    /// Create `ElementDeserialize` matching tag using given matcher
232    pub fn new(tag_matcher: M) -> Self {
233        Self { tag_matcher, _phantom: PhantomData }
234    }
235}
236
237impl<T: DeserializeOwned> ElementDeserialize<T, ExactTagMatch> {
238    /// Create `ElementDeserialize` matching given tag
239    pub fn tag(tag: &'static str) -> Self {
240        Self::new(ExactTagMatch { needle: tag })
241    }
242}
243
244impl<T: DeserializeOwned> ElementDeserialize<T, AnyTagMatch> {
245    /// Create `ElementDeserialize` matching any tag
246    pub fn any() -> Self {
247        Self::new(AnyTagMatch {})
248    }
249}
250
251mod private {
252    use serde::de::DeserializeOwned;
253
254    pub trait Sealed {}
255
256    impl<N, M> Sealed for super::ElementEnter<N, M> {}
257    impl<T: DeserializeOwned, N, M> Sealed for super::ElementEnterDeserialize<T, N, M> {}
258    impl<T: DeserializeOwned, M> Sealed for super::ElementDeserialize<T, M> {}
259}
260
261#[doc(hidden)]
262pub trait XmlPath: private::Sealed {
263    type Output: DeTuple;
264
265    fn go<R: Read>(&mut self, parser: &mut Parser<R>) -> Option<Result<Self::Output, DeserializeError>>;
266}
267
268impl<M: TagMatcher, N: XmlPath> XmlPath for ElementEnter<M, N> {
269    type Output = N::Output;
270
271    fn go<R: Read>(&mut self, parser: &mut Parser<R>) -> Option<Result<Self::Output, DeserializeError>> {
272        loop {
273            if self.entered {
274                if let Some(out) = self.next.go(parser) {
275                    return Some(out);
276                }
277            }
278            self.entered = false;
279
280            let mut event = try_some!(parser.next());
281            match event.code() {
282                EventCode::StartTag => {
283                    let tag_name = try_some!(event.get_str());
284                    if self.tag_matcher.matches(tag_name.as_ref()) {
285                        self.entered = true;
286                    } else {
287                        try_some!(parser.finish_tag(1));
288                    }
289                },
290                EventCode::EndTagImmediate | EventCode::EndTag | EventCode::Eof => {
291                    return None;
292                },
293                EventCode::AttributeName | EventCode::AttributeValue | EventCode::Text => {}
294            }
295        }
296    }
297}
298
299impl<T: DeserializeOwned + Clone, M: TagMatcher, N: XmlPath> XmlPath for ElementEnterDeserialize<T, M, N>
300    where N::Output: Prepend<T>, <N::Output as Prepend<T>>::Output: DeTuple
301{
302    type Output = <N::Output as Prepend<T>>::Output;
303
304    fn go<R: Read>(&mut self, parser: &mut Parser<R>) -> Option<Result<Self::Output, DeserializeError>> {
305        loop {
306            if let Some(entered) = &self.entered {
307                if let Some(out) = self.next.go(parser) {
308                    return match out {
309                        Ok(out) => {
310                            // We clone one more times than necessary (the last remaining one will get dropped once
311                            // the `next` returns `None`. It would be nice if we could avoid the last clone, but
312                            // we would have to know that the underlying `next` really returned the last one.
313                            Some(Ok(out.prepend((*entered).clone())))
314                        }
315                        Err(err) => Some(Err(err))
316                    };
317                }
318            }
319            self.entered = None;
320
321            let mut event = try_some!(parser.next());
322            match event.code() {
323                EventCode::StartTag => {
324                    let tag_name = try_some!(event.get_str());
325                    if self.tag_matcher.matches(&tag_name) {
326                        let opening_tag = tag_name.into();
327                        let mut des = Deserializer::new_inside_tag(parser, opening_tag, true);
328                        self.entered = Some(try_some!(T::deserialize(&mut des)));
329                        if let Some(f) = self.trace.as_mut() {
330                            f(self.entered.as_ref().unwrap());
331                        }
332                        if let EventCode::EndTag | EventCode::EndTagImmediate = try_some!(parser.peek()).code() {
333                            // This is fine, we deserialized the `T` successfully but then there
334                            // are no child tags to enter, so we continue to next sibling tag or
335                            // end of this container.
336                            let _ = parser.next().unwrap();
337                            self.entered = None;
338                        }
339                    } else {
340                        try_some!(parser.finish_tag(1));
341                    }
342                },
343                EventCode::EndTagImmediate | EventCode::EndTag | EventCode::Eof => {
344                    return None;
345                },
346                EventCode::AttributeName | EventCode::AttributeValue | EventCode::Text => {}
347            }
348        }
349    }
350}
351
352impl<T: DeserializeOwned, M: TagMatcher> XmlPath for ElementDeserialize<T, M> {
353    type Output = (T,);
354
355    fn go<R: Read>(&mut self, parser: &mut Parser<R>) -> Option<Result<Self::Output, DeserializeError>> {
356        loop {
357            let mut event = try_some!(parser.next());
358            match event.code() {
359                EventCode::StartTag => {
360                    let tag_name = try_some!(event.get_str());
361                    if self.tag_matcher.matches(tag_name.as_ref()) {
362                        let opening_tag = tag_name.into();
363                        let mut des = Deserializer::new_inside_tag(parser, opening_tag, false);
364                        return Some(Ok((try_some!(T::deserialize(&mut des)), )))
365                    }
366                },
367                EventCode::EndTagImmediate | EventCode::EndTag => {
368                    return None;
369                },
370                EventCode::Eof => {
371                    return Some(Err(DeserializeError::UnexpectedEof));
372                },
373                EventCode::AttributeName | EventCode::AttributeValue | EventCode::Text => {}
374            }
375        }
376    }
377}
378
379/// Deserializer for a sequence of elements in a tree.
380///
381/// See `xml_path` macro for easy way of constructing the path.
382///
383/// TreeDeserializer is an `Iterator` over the deserialized elements. If the xml path deserializes
384/// exactly one type, the iterator will yield that type. If the xml path deserializes multiple
385/// types (nested in a XML tree), the iterator will yield tuple of those types.
386///
387/// TODO: Example
388pub struct TreeDeserializer<R: Read, N> {
389    parser: Parser<R>,
390    path: N,
391}
392
393/// Type alias that helps to get the output type of TreeDeserializer
394pub type TreeDeserializerOutput<N> = <<N as XmlPath>::Output as DeTuple>::Output;
395
396impl<R: Read, N: XmlPath> TreeDeserializer<R, N> {
397    /// Create new `TreeDeserializer` from given `Parser`.
398    pub fn from_path(path: N, parser: Parser<R>) -> Self {
399        Self {
400            parser,
401            path,
402        }
403    }
404
405    /// Create new `TreeDeserializer` from given IO `Read`.
406    pub fn from_path_and_reader(path: N, reader: R) -> Self {
407        Self::from_path(path, Parser::new(reader))
408    }
409}
410
411impl<R: Read, N: XmlPath + Default> TreeDeserializer<R, N> {
412    /// Create new `TreeDeserializer` from given `Parser`.
413    pub fn new(parser: Parser<R>) -> Self {
414        Self {
415            parser,
416            path: N::default(),
417        }
418    }
419
420    /// Create new `TreeDeserializer` from given IO `Read`.
421    pub fn from_reader(reader: R) -> Self {
422        Self::new(Parser::new(reader))
423    }
424}
425
426impl<R: Read, N: XmlPath> Iterator for TreeDeserializer<R, N> where N::Output: DeTuple {
427    type Item = Result<<N::Output as DeTuple>::Output, DeserializeError>;
428
429    fn next(&mut self) -> Option<Self::Item> {
430        match self.path.go(&mut self.parser) {
431            Some(Ok(tuple)) => Some(Ok(tuple.detuple())),
432            Some(Err(err)) => Some(Err(err)),
433            None => None,
434        }
435    }
436}
437
438/// Macro for easier construction of XML path.
439///
440/// This macro is alternative to building path by manually creating and nesting `ElementEnter`,
441/// `ElementDeserialize` and `ElementEnterDeserialize`.
442///
443/// You can use `*` (not `"*"`!) to match any tag. Partial matching is currently not supported!
444///
445/// The last element must deserialize into a type!
446///
447/// # Example
448///
449/// ```no_run
450/// # use serde_derive::Deserialize;
451/// # #[derive(Clone, Deserialize)]
452/// # struct Ccc {}
453/// # #[derive(Deserialize)]
454/// # struct Eee {}
455/// # use rapid_xml::xml_path;
456/// let path = xml_path!("aaa", *, "ccc" => Ccc, "ddd", * => Eee);
457/// ```
458///
459/// This will enter tags `<aaa ...>`, inside enter any tag, inside enter and deserialize `<ccc ...>`
460/// tag into `Ccc` type, enter `<ddd ...> tag tag and finaly deserialize any tag into `Eee` type.
461///
462/// The `TreeDeserializer` with this path will be `Iterator` over `Result<(Ccc, Eee), _>` type.
463#[macro_export]
464macro_rules! xml_path {
465    // Tail rule - turns `"ccc" => Ccc` or `* => Ccc` expression into `ElementDeserialize`
466    ($tag_name:literal => $t:ty) => {
467        $crate::tree::ElementDeserialize::<$t, _>::tag($tag_name)
468    };
469    (* => $t:ty) => {
470        $crate::tree::ElementDeserialize::<$t, _>::any()
471    };
472
473    // Tail rule - to inform user that the last expression must be `"ccc" => Ccc`, can't be just
474    // `"ccc"`.
475    ($tag_name:literal) => { $crate::xml_path!(*) };
476    (*) => { compile_error!("Paths must end with `\"tag_name\" => Type` expression.") };
477
478    // Recursive rule - turn `"ccc" => Ccc` or `* => Ccc` expression at beginning into `ElementEnterDeserialize`
479    // and call ourselves recursively on the rest.
480    ($tag_name:literal => $t:ty, $($r_tag_name:tt $(=> $r_t:ty)?),+) => {
481        $crate::tree::ElementEnterDeserialize::<$t, _, _>::tag($tag_name,
482            $crate::xml_path!($($r_tag_name $(=> $r_t)?),+)
483        )
484    };
485    (* => $t:ty, $($r_tag_name:tt $(=> $r_t:ty)?),+) => {
486        $crate::tree::ElementEnterDeserialize::<$t, _, _>::any(
487            $crate::xml_path!($($r_tag_name $(=> $r_t)?),+)
488        )
489    };
490
491    // Recursive rule - turn `"ccc"` or `*` expression at beginning into `ElementEnter` and call ourselves
492    // recursively on the rest.
493    ($tag_name:literal, $($r_tag_name:tt $(=> $r_t:ty)?),+) => {
494        $crate::tree::ElementEnter::tag($tag_name,
495            $crate::xml_path!($($r_tag_name $(=> $r_t)?),+)
496        )
497    };
498    (*, $($r_tag_name:tt $(=> $r_t:ty)?),+) => {
499        $crate::tree::ElementEnter::any(
500            $crate::xml_path!($($r_tag_name $(=> $r_t)?),+)
501        )
502    };
503}
504
505/// Macro that expands to `type ... = ...` alias of XML path.
506///
507/// The XML path if fully encoded in the type, including the names of the tags to be matched.
508///
509/// The resulting type is `Default`-constructible. This allows you to create the `TreeDeserializer`
510/// using the `new` and `from_reader` functions. This is useful if for example you need to store
511/// the deserializer in an associated type.
512///
513/// # Example
514///
515/// ```no_run
516/// # use serde_derive::Deserialize;
517/// # #[derive(Clone, Deserialize)]
518/// # struct Ccc {}
519/// # #[derive(Deserialize)]
520/// # struct Eee {}
521/// # use rapid_xml::xml_path_type;
522/// xml_path_type!(MyPath: "aaa", *, "ccc" => Ccc, "ddd", * => Eee);
523/// # fn main() {}
524/// ```
525#[macro_export]
526macro_rules! xml_path_type {
527    // If we had const generics, implementing this would be quite easy - we would just have
528    // something like the `ExactTagMatch` that takes the string as const generic parameter and here
529    // we would just generate the type with it. But we don't have that in stable rust yet, so we use
530    // more complicated technique: For every string in the input we generate a struct implementing
531    // `TagMatcher` where the string ends up hardcoded inside the `matches` function. It is marked
532    // as `#[inline(always)]`, so the final result should be the same as it would be after
533    // monomorphization of the const generics struct.
534    //
535    // The generated structs are hidden inside a generated module to reduce chance of name
536    // collisions. We use the `paste` crate to create names for the module and the structs
537    // by concatenating the given type name with extra suffix.
538    // The module ends up named "<type_name>__rapid_xml_generated_matchers", the structs inside end
539    // up named "<Struct>Matcher<Suffix>", where `Struct` is the structure that the tag will be
540    // deserialized into (if any, otherwise empty) and `Suffix` is string containing multiple
541    // repeated 'A' characters. (Easiest form of a "counter".)
542
543    // This is the entry point - this is what the user should call.
544    // We create the basic structure - a module and type alias and call ourselves with @structs and
545    // @types prefix to generate the structs and the type respectively.
546    ($type_name:ident : $($r_tag_name:tt $(=> $r_t:ty)?),+) => {
547        $crate::tree::paste_item! {
548            #[allow(non_snake_case)]
549            #[doc(hidden)]
550            mod [<$type_name __rapid_xml_generated_matchers>] {
551                $crate::xml_path_type!(@structs A $($r_tag_name $(=> $r_t)?),+);
552            }
553        }
554
555        type $type_name = $crate::xml_path_type!(@types $type_name A $($r_tag_name $(=> $r_t)?),+);
556    };
557
558    // == @structs ==
559    // This part generates multiple structs implementing `TagMatcher` inside the module. One is
560    // generated for each tag matches by string (none for tags matched by wildcard). It goes thru
561    // the list recursively.
562
563    // Tail of the recursion for string match, we generate the struct and the impl of TagMatcher.
564    (@structs $suffix:ident $tag_name:literal $(=> $t:ty)?) => {
565        $crate::tree::paste_item! {
566            #[derive(Debug, Default, PartialEq)]
567            pub struct [<$($t)? Matcher $suffix>] {}
568
569            impl $crate::tree::TagMatcher for [<$($t)? Matcher $suffix>] {
570                #[inline(always)]
571                fn matches(&self, tag_name: &str) -> bool {
572                    tag_name == $tag_name
573                }
574            }
575        }
576    };
577    // Tail of the recursion for wildcard match, we generate nothing
578    (@structs $suffix:ident * $(=> $t:ty)?) => {
579        // nothing
580    };
581
582    // The next item in list is a string match, we generate the struct and impl (by calling
583    // ourselves with the item alone - invoking the tail pattern) and then we call ourselves
584    // recursively on the rest of the list.
585    (@structs $suffix:ident $tag_name:literal $(=> $t:ty)?, $($r_tag_name:tt $(=> $r_t:ty)?),+) => {
586        $crate::tree::paste_item! {
587            $crate::xml_path_type!(@structs $suffix $tag_name $(=> $t)?);
588            $crate::xml_path_type!(@structs [<$suffix A>] $($r_tag_name $(=> $r_t)?),*);
589        }
590    };
591
592    // The next item in list is a wildcard match - we do nothing and call ourselves recursively on
593    // the rest of the list.
594    (@structs $suffix:ident * $(=> $t:ty)?, $($r_tag_name:tt $(=> $r_t:ty)?),+) => {
595        $crate::tree::paste_item! {
596            $crate::xml_path_type!(@structs [<$suffix A>] $($r_tag_name $(=> $r_t)?),+);
597        }
598    };
599
600    // == @types ==
601    // This part generates the type by nesting `ElementEnter`, `ElementEnterDeserialize` and
602    // `ElementDeserialize`. They are build with matchers generated by the @structs part of with
603    // `AnyTagMatch` matcher.
604
605    // Tail rule - turns `"ccc" => Ccc` or `* => Ccc` expression into `ElementDeserialize`
606    (@types $type_name:ident $suffix:ident $tag_name:literal => $t:ty) => {
607        $crate::tree::paste_item! {
608            $crate::tree::ElementDeserialize<$t, [<$type_name __rapid_xml_generated_matchers>]::[<$t Matcher $suffix>]>
609        }
610    };
611    (@types $type_name:ident $suffix:ident * => $t:ty) => {
612        $crate::tree::ElementDeserialize::<$t, $crate::tree::AnyTagMatch>
613    };
614
615    // Tail rule - to inform user that the last expression must be `"ccc" => Ccc`, can't be just
616    // `"ccc"`.
617    (@types $type_name:ident $suffix:ident $tag_name:literal) => { $crate::xml_path_type!(*) };
618    (@types $type_name:ident $suffix:ident *) => { compile_error!("Paths must end with `\"tag_name\" => Type` expression.") };
619
620    // Recursive rule - turn `"ccc" => Ccc` or `* => Ccc` expression at beginning into `ElementEnterDeserialize`
621    // and call ourselves recursively on the rest.
622    (@types $type_name:ident $suffix:ident $tag_name:literal => $t:ty, $($r_tag_name:tt $(=> $r_t:ty)?),+) => {
623        $crate::tree::paste_item! {
624            $crate::tree::ElementEnterDeserialize<$t, [<$type_name __rapid_xml_generated_matchers>]::[<$t Matcher $suffix>],
625                $crate::xml_path_type!(@types $type_name [<$suffix A>] $($r_tag_name $(=> $r_t)?),+)
626            >
627        }
628    };
629    (@types $type_name:ident $suffix:ident * => $t:ty, $($r_tag_name:tt $(=> $r_t:ty)?),+) => {
630        $crate::tree::paste_item! {
631            $crate::tree::ElementEnterDeserialize::<$t, $crate::tree::AnyTagMatch,
632                $crate::xml_path_type!(@types $type_name [<$suffix A>] $($r_tag_name $(=> $r_t)?),+)
633            >
634        }
635    };
636
637    // Recursive rule - turn `"ccc"` or `*` expression at beginning into `ElementEnter` and call ourselves
638    // recursively on the rest.
639    (@types $type_name:ident $suffix:ident $tag_name:literal, $($r_tag_name:tt $(=> $r_t:ty)?),+) => {
640        $crate::tree::paste_item! {
641            $crate::tree::ElementEnter<[<$type_name __rapid_xml_generated_matchers>]::[<Matcher $suffix>],
642                $crate::xml_path_type!(@types $type_name [<$suffix A>] $($r_tag_name $(=> $r_t)?),+)
643            >
644        }
645    };
646    (@types $type_name:ident $suffix:ident *, $($r_tag_name:tt $(=> $r_t:ty)?),+) => {
647        $crate::tree::paste_item! {
648            $crate::tree::ElementEnter::<$crate::tree::AnyTagMatch,
649                $crate::xml_path_type!(@types $type_name [<$suffix A>] $($r_tag_name $(=> $r_t)?),+)
650            >
651        }
652    };
653}
654
655#[cfg(test)]
656mod tests {
657    use std::io::Cursor;
658
659    use serde_derive::Deserialize;
660
661    use super::*;
662
663    #[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
664    struct Root {
665        xyz: u32,
666    }
667
668    #[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
669    struct Bbb {
670        n: u32,
671    }
672
673    #[derive(Debug, Deserialize, PartialEq, Eq)]
674    struct Ccc {
675        m: u32,
676    }
677
678    const SAMPLE_XML: &[u8] = br#"
679            <root xyz="42">
680                <aaa>
681                    <bbb n="1">
682                        <ccc m="100"/>
683                        <ccc m="200"/>
684                    </bbb>
685                    <xxx>Unknown tag</xxx>
686                </aaa>
687                <xxx>Unknown tag</xxx>
688                <aaa>
689                    <bbb n="99"/>
690                </aaa>
691                <aaa/>
692                <aaa>
693                    <bbb n="99">Matched tag without anything nested</bbb>
694                    <bbb n="2">
695                        <ccc><m>300</m></ccc>
696                        <ccc><m>400</m></ccc>
697                    </bbb>
698                </aaa>
699                <aaa2>
700                    <bbb n="3">
701                        <ccc m="500"/>
702                    </bbb>
703                </aaa2>
704            </root>
705        "#;
706
707    const SAMPLE_XML_ERRORS: &[u8] = br#"
708            <root xyz="42">
709                <aaa>
710                    <bbb n="1">
711                        <ccc m="100"/>
712                        <ccc/>
713                        <ccc m="200"/>
714                        <ccc m=250/>
715                    </bbb>
716                    <xxx>Unknown tag</xxx>
717                </aaa>
718                <xxx>Unknown tag</xxx>
719                <aaa>
720                    <bbb n="99">Matched tag without anything nested</bbb>
721                    <bbb n="2">
722                        <ccc><m>300</m></ccc>
723                        <ccc><m>asdf</m></ccc>
724                    </bbb>
725                </aaa>
726            </root>
727        "#;
728
729    #[test]
730    fn basic() {
731        let path = xml_path!("root", "aaa", "bbb", "ccc" => Ccc);
732
733        let mut des = TreeDeserializer::from_path_and_reader(path, Cursor::new(&SAMPLE_XML[..]));
734
735        assert_eq!(des.next().unwrap().unwrap(), Ccc { m: 100 });
736        assert_eq!(des.next().unwrap().unwrap(), Ccc { m: 200 });
737        assert_eq!(des.next().unwrap().unwrap(), Ccc { m: 300 });
738        assert_eq!(des.next().unwrap().unwrap(), Ccc { m: 400 });
739        assert!(des.next().is_none());
740    }
741
742    #[test]
743    fn basic_100_times() {
744        let path = xml_path!("root", "aaa", "bbb", "ccc" => Ccc);
745
746        let xml = SAMPLE_XML.repeat(100);
747        let mut des = TreeDeserializer::from_path_and_reader(path, Cursor::new(&xml));
748
749        for _ in 0..100 {
750            assert_eq!(des.next().unwrap().unwrap(), Ccc { m: 100 });
751            assert_eq!(des.next().unwrap().unwrap(), Ccc { m: 200 });
752            assert_eq!(des.next().unwrap().unwrap(), Ccc { m: 300 });
753            assert_eq!(des.next().unwrap().unwrap(), Ccc { m: 400 });
754        }
755        assert!(des.next().is_none());
756    }
757
758    #[test]
759    fn wildcard() {
760        let path = xml_path!("root", *, "bbb", "ccc" => Ccc);
761
762        let mut des = TreeDeserializer::from_path_and_reader(path, Cursor::new(&SAMPLE_XML[..]));
763
764        assert_eq!(des.next().unwrap().unwrap(), Ccc { m: 100 });
765        assert_eq!(des.next().unwrap().unwrap(), Ccc { m: 200 });
766        assert_eq!(des.next().unwrap().unwrap(), Ccc { m: 300 });
767        assert_eq!(des.next().unwrap().unwrap(), Ccc { m: 400 });
768        assert_eq!(des.next().unwrap().unwrap(), Ccc { m: 500 });
769        assert!(des.next().is_none());
770    }
771
772    #[test]
773    fn multiple_elements() {
774        let path = xml_path!("root", "aaa", "bbb" => Bbb, "ccc" => Ccc);
775
776        let mut des = TreeDeserializer::from_path_and_reader(path, Cursor::new(&SAMPLE_XML[..]));
777
778        assert_eq!(des.next().unwrap().unwrap(), (Bbb { n: 1 }, Ccc { m: 100 }));
779        assert_eq!(des.next().unwrap().unwrap(), (Bbb { n: 1 }, Ccc { m: 200 }));
780        assert_eq!(des.next().unwrap().unwrap(), (Bbb { n: 2 }, Ccc { m: 300 }));
781        assert_eq!(des.next().unwrap().unwrap(), (Bbb { n: 2 }, Ccc { m: 400 }));
782        assert!(des.next().is_none());
783    }
784
785    xml_path_type!(MyPath: "root", "aaa", "bbb" => Bbb, "ccc" => Ccc);
786
787    #[test]
788    fn multiple_elements_with_type() {
789        let mut des = TreeDeserializer::<_, MyPath>::from_reader(Cursor::new(&SAMPLE_XML[..]));
790
791        assert_eq!(des.next().unwrap().unwrap(), (Bbb { n: 1 }, Ccc { m: 100 }));
792        assert_eq!(des.next().unwrap().unwrap(), (Bbb { n: 1 }, Ccc { m: 200 }));
793        assert_eq!(des.next().unwrap().unwrap(), (Bbb { n: 2 }, Ccc { m: 300 }));
794        assert_eq!(des.next().unwrap().unwrap(), (Bbb { n: 2 }, Ccc { m: 400 }));
795        assert!(des.next().is_none());
796    }
797
798    #[test]
799    fn with_errors() {
800        let path = xml_path!("root", "aaa", "bbb" => Bbb, "ccc" => Ccc);
801
802        let mut des = TreeDeserializer::from_path_and_reader(path, Cursor::new(&SAMPLE_XML_ERRORS[..]));
803
804        // TODO: The actual output may still change if we learn to recover from some errors better.
805
806        assert_eq!(des.next().unwrap().unwrap(), (Bbb { n: 1 }, Ccc { m: 100 }));
807        assert!(des.next().unwrap().is_err());
808        assert_eq!(des.next().unwrap().unwrap(), (Bbb { n: 1 }, Ccc { m: 200 }));
809        assert!(des.next().unwrap().is_err()); // Bad attribute value
810        assert_eq!(des.next().unwrap().unwrap(), (Bbb { n: 2 }, Ccc { m: 300 }));
811        assert!(des.next().unwrap().is_err());
812        assert!(des.next().is_none());
813    }
814
815    #[test]
816    fn parse_root() {
817        let path = xml_path!("root" => Root, "aaa", "bbb", "ccc" => Ccc);
818
819        let mut des = TreeDeserializer::from_path_and_reader(path, Cursor::new(&SAMPLE_XML[..]));
820
821        assert_eq!(des.next().unwrap().unwrap(), (Root { xyz: 42, }, Ccc { m: 100 }));
822        assert_eq!(des.next().unwrap().unwrap(), (Root { xyz: 42, }, Ccc { m: 200 }));
823        assert_eq!(des.next().unwrap().unwrap(), (Root { xyz: 42, }, Ccc { m: 300 }));
824        assert_eq!(des.next().unwrap().unwrap(), (Root { xyz: 42, }, Ccc { m: 400 }));
825        assert!(des.next().is_none());
826    }
827}
828
829#[cfg(test)]
830#[cfg(feature = "bencher")]
831mod bench {
832    use std::io::Cursor;
833    use test::{Bencher, black_box};
834
835    use serde_derive::Deserialize;
836
837    use super::*;
838
839    #[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
840    pub enum Thing {
841        VariantA {
842            some_field: String,
843        },
844
845        VariantB {
846            some_field: String,
847            another_field: Option<u32>,
848            abcd_efgh: Option<u32>,
849            mumble_rumble: i16,
850            short: Option<String>,
851            field_with_long_name: Option<u32>,
852            xyz_qwerty: Option<u32>,
853        },
854
855        VariantC {
856            some_field: String,
857            field_1: u32,
858            field_2: i16,
859            field_3: u32,
860        },
861    }
862
863    const BENCH_XML: &[u8] = br#"<root><group>
864<VariantA some_field="TextAbcd"/>
865<VariantB some_field="TextAbcd"><another_field>80</another_field><abcd_efgh>4587</abcd_efgh><mumble_rumble>-8</mumble_rumble><short>AnotherText</short><field_with_long_name>79452</field_with_long_name></VariantB>
866<VariantC some_field="TextAbcd"><field_1>123</field_1><field_2>-3</field_2><field_3>567</field_3></VariantC>
867</group></root>"#;
868
869    #[bench]
870    fn bench_tree_deserializer(b: &mut Bencher) {
871        let xml = BENCH_XML.repeat(10000);
872
873        b.iter(move || {
874            let path = xml_path!("root", "group", * => Thing);
875            let mut des = TreeDeserializer::from_path_and_reader(path, Cursor::new(&xml));
876            while let Some(item) = des.next() {
877                black_box(item.unwrap());
878            }
879        });
880    }
881}