Skip to main content

xso/
fromxml.rs

1//! # Generic builder type implementations
2//!
3//! This module contains [`FromEventsBuilder`] implementations for types from
4//! foreign libraries (such as the standard library).
5//!
6//! In order to not clutter the `xso` crate's main namespace, they are
7//! stashed away in a separate module.
8
9// Copyright (c) 2024 Jonas Schäfer <jonas@zombofant.net>
10//
11// This Source Code Form is subject to the terms of the Mozilla Public
12// License, v. 2.0. If a copy of the MPL was not distributed with this
13// file, You can obtain one at http://mozilla.org/MPL/2.0/.
14
15use alloc::{
16    borrow::{Cow, ToOwned},
17    boxed::Box,
18};
19use core::marker::PhantomData;
20
21use crate::error::{Error, FromEventsError};
22use crate::{FromEventsBuilder, FromXml};
23
24/// Match an XML element qualified name.
25#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
26pub enum XmlNameMatcher<'x> {
27    /// Match any XML element
28    Any,
29
30    /// Match any XML element in the given namespace.
31    InNamespace(&'x str),
32
33    /// Match any XML element with the exact namespace/name combination.
34    Specific(&'x str, &'x str),
35}
36
37impl<'x> XmlNameMatcher<'x> {
38    /// Return the superset of two `XmlNameMatcher` instances.
39    pub const fn superset(self, other: Self) -> Self {
40        match self {
41            Self::Any => Self::Any,
42            Self::InNamespace(my_namespace) => match other {
43                Self::Any => Self::Any,
44                Self::InNamespace(other_namespace) | Self::Specific(other_namespace, _) => {
45                    if crate::util::const_str_eq(my_namespace, other_namespace) {
46                        Self::InNamespace(my_namespace)
47                    } else {
48                        Self::Any
49                    }
50                }
51            },
52            Self::Specific(my_namespace, my_name) => match other {
53                Self::Any => Self::Any,
54                Self::InNamespace(other_namespace) => {
55                    if crate::util::const_str_eq(my_namespace, other_namespace) {
56                        Self::InNamespace(my_namespace)
57                    } else {
58                        Self::Any
59                    }
60                }
61                Self::Specific(other_namespace, other_name) => {
62                    if crate::util::const_str_eq(my_namespace, other_namespace) {
63                        if crate::util::const_str_eq(my_name, other_name) {
64                            Self::Specific(my_name, other_name)
65                        } else {
66                            Self::InNamespace(my_namespace)
67                        }
68                    } else {
69                        Self::Any
70                    }
71                }
72            },
73        }
74    }
75
76    /// Return true if the given `qname` matches this matcher.
77    pub fn matches(&self, qname: &rxml::QName) -> bool {
78        match self {
79            Self::Any => true,
80            Self::InNamespace(ns) => qname.0.as_str() == *ns,
81            Self::Specific(ns, name) => qname.0.as_str() == *ns && qname.1.as_str() == *name,
82        }
83    }
84}
85
86/// # Parsing context for [`FromEventsBuilder`]
87///
88/// For the most part, [`FromEventsBuilder`] implementations can work with
89/// only the information inside the [`rxml::Event`] which is delivered to
90/// them (and any information they may have stored from previous events).
91///
92/// However, there is (currently) one special case: the `xml:lang` attribute.
93/// That attribute is inherited across the entire document tree hierarchy. If
94/// the parsed element is not the top-level element, there may be an implicit
95/// value for `xml:lang`.
96#[derive(Debug)]
97#[doc(hidden)]
98pub struct Context<'x> {
99    language: Option<&'x str>,
100}
101
102impl<'x> Context<'x> {
103    /// A context suitable for the beginning of the document.
104    ///
105    /// `xml:lang` is assumed to be unset.
106    pub fn empty() -> Self {
107        Self { language: None }
108    }
109
110    /// Set the effective `xml:lang` value on the context and return it.
111    pub fn with_language(mut self, language: Option<&'x str>) -> Self {
112        self.language = language;
113        self
114    }
115
116    /// Return the `xml:lang` value in effect at the end of the event which
117    /// is currently being processed.
118    pub fn language(&self) -> Option<&str> {
119        self.language
120    }
121}
122
123/// Helper struct to construct an `Option<T>` from XML events.
124pub struct OptionBuilder<T: FromEventsBuilder>(T);
125
126impl<T: FromEventsBuilder> FromEventsBuilder for OptionBuilder<T> {
127    type Output = Option<T::Output>;
128
129    fn feed(&mut self, ev: rxml::Event, ctx: &Context<'_>) -> Result<Option<Self::Output>, Error> {
130        self.0.feed(ev, ctx).map(|ok| ok.map(Some))
131    }
132}
133
134/// Parsers `T` into `Some(.)`.
135///
136/// Note that this never generates `None`: The main use case is to allow
137/// external (i.e. without calling `from_events`) defaulting to `None` and
138/// for optional serialisation (the [`AsXml`][`crate::AsXml`] implementation
139/// on `Option<T>` emits nothing for `None`).
140impl<T: FromXml> FromXml for Option<T> {
141    type Builder = OptionBuilder<T::Builder>;
142
143    fn from_events(
144        name: rxml::QName,
145        attrs: rxml::AttrMap,
146        ctx: &Context<'_>,
147    ) -> Result<Self::Builder, FromEventsError> {
148        Ok(OptionBuilder(T::from_events(name, attrs, ctx)?))
149    }
150}
151
152/// Helper struct to construct an `Box<T>` from XML events.
153pub struct BoxBuilder<T: FromEventsBuilder + ?Sized>(Box<T>);
154
155impl<T: FromEventsBuilder + ?Sized> FromEventsBuilder for BoxBuilder<T> {
156    type Output = Box<T::Output>;
157
158    fn feed(&mut self, ev: rxml::Event, ctx: &Context<'_>) -> Result<Option<Self::Output>, Error> {
159        self.0.feed(ev, ctx).map(|ok| ok.map(Box::new))
160    }
161}
162
163/// Parses `T` into a `Box`.
164impl<T: FromXml + ?Sized> FromXml for Box<T> {
165    type Builder = BoxBuilder<T::Builder>;
166
167    fn from_events(
168        name: rxml::QName,
169        attrs: rxml::AttrMap,
170        ctx: &Context<'_>,
171    ) -> Result<Self::Builder, FromEventsError> {
172        Ok(BoxBuilder(Box::new(T::from_events(name, attrs, ctx)?)))
173    }
174}
175
176impl<T: FromEventsBuilder + ?Sized> FromEventsBuilder for Box<T> {
177    type Output = T::Output;
178
179    fn feed(&mut self, ev: rxml::Event, ctx: &Context<'_>) -> Result<Option<Self::Output>, Error> {
180        (**self).feed(ev, ctx)
181    }
182}
183
184#[derive(Debug)]
185enum FallibleBuilderInner<T: FromEventsBuilder, E> {
186    Processing { depth: usize, builder: T },
187    Failed { depth: usize, err: Option<E> },
188    Done,
189}
190
191/// Build a `Result<T, E>` from XML.
192///
193/// This builder, invoked generally via the [`FromXml`] implementation on
194/// `Result<T, E> where T: FromXml, E: From<Error>`, allows to fallably parse
195/// an XSO from XML.
196///
197/// If an error occurs while parsing the XSO, the remaining events which
198/// belong to that XSO are discarded. Once all events have been seen, the
199/// error is returned as `Err(.)` value.
200///
201/// If parsing succeeds, the parsed XSO is returned as `Ok(.)` value.
202#[derive(Debug)]
203pub struct FallibleBuilder<T: FromEventsBuilder, E>(FallibleBuilderInner<T, E>);
204
205impl<T: FromEventsBuilder, E: From<Error>> FromEventsBuilder for FallibleBuilder<T, E> {
206    type Output = Result<T::Output, E>;
207
208    fn feed(&mut self, ev: rxml::Event, ctx: &Context<'_>) -> Result<Option<Self::Output>, Error> {
209        match self.0 {
210            FallibleBuilderInner::Processing {
211                ref mut depth,
212                ref mut builder,
213            } => {
214                let new_depth = match ev {
215                    rxml::Event::StartElement(..) => match depth.checked_add(1) {
216                        // I *think* it is OK to return an err here
217                        // instead of panicking. The reason is that anyone
218                        // who intends to resume processing at the level
219                        // of where we started to parse this thing in case
220                        // of an error either has to:
221                        // - Use this fallible implementation and rely on
222                        //   it capturing the error (which we don't in
223                        //   this case).
224                        // - Or count the depth themselves, which will
225                        //   either fail in the same way, or they use a
226                        //   wider type (in which case it's ok).
227                        None => {
228                            self.0 = FallibleBuilderInner::Done;
229                            return Err(Error::Other("maximum XML nesting depth exceeded"));
230                        }
231                        Some(v) => Some(v),
232                    },
233                    // In case of an element end, underflow means that we
234                    // have reached the end of the XSO we wanted to process.
235                    // We handle that case at the end of the outer match's
236                    // body: Either we have returned a value then (good), or,
237                    // if we reach the end there with a new_depth == None,
238                    // something went horribly wrong (and we panic).
239                    rxml::Event::EndElement(..) => depth.checked_sub(1),
240
241                    // Text and XML declarations have no influence on parsing
242                    // depth.
243                    rxml::Event::XmlDeclaration(..) | rxml::Event::Text(..) => Some(*depth),
244                };
245
246                match builder.feed(ev, ctx) {
247                    Ok(Some(v)) => {
248                        self.0 = FallibleBuilderInner::Done;
249                        return Ok(Some(Ok(v)));
250                    }
251                    Ok(None) => {
252                        // continue processing in the next round.
253                    }
254                    Err(e) => {
255                        // We are now officially failed ..
256                        match new_depth {
257                            // .. but we are not done yet, so enter the
258                            // failure backtracking state.
259                            Some(depth) => {
260                                self.0 = FallibleBuilderInner::Failed {
261                                    depth,
262                                    err: Some(e.into()),
263                                };
264                                return Ok(None);
265                            }
266                            // .. and we are done with parsing, so we return
267                            // the error as value.
268                            None => {
269                                self.0 = FallibleBuilderInner::Done;
270                                return Ok(Some(Err(e.into())));
271                            }
272                        }
273                    }
274                };
275
276                *depth = match new_depth {
277                    Some(v) => v,
278                    None => unreachable!("fallible parsing continued beyond end of element"),
279                };
280
281                // Need more events.
282                Ok(None)
283            }
284            FallibleBuilderInner::Failed {
285                ref mut depth,
286                ref mut err,
287            } => {
288                *depth = match ev {
289                    rxml::Event::StartElement(..) => match depth.checked_add(1) {
290                        // See above for error return rationale.
291                        None => {
292                            self.0 = FallibleBuilderInner::Done;
293                            return Err(Error::Other("maximum XML nesting depth exceeded"));
294                        }
295                        Some(v) => v,
296                    },
297                    rxml::Event::EndElement(..) => match depth.checked_sub(1) {
298                        Some(v) => v,
299                        None => {
300                            // We are officially done, return a value, switch
301                            // states, and be done with it.
302                            let err = err.take().expect("fallible parsing somehow lost its error");
303                            self.0 = FallibleBuilderInner::Done;
304                            return Ok(Some(Err(err)));
305                        }
306                    },
307
308                    // Text and XML declarations have no influence on parsing
309                    // depth.
310                    rxml::Event::XmlDeclaration(..) | rxml::Event::Text(..) => *depth,
311                };
312
313                // Need more events
314                Ok(None)
315            }
316            FallibleBuilderInner::Done => {
317                panic!("FromEventsBuilder called after it returned a value")
318            }
319        }
320    }
321}
322
323/// Parsers `T` fallibly. See [`FallibleBuilder`] for details.
324impl<T: FromXml, E: From<Error>> FromXml for Result<T, E> {
325    type Builder = FallibleBuilder<T::Builder, E>;
326
327    fn from_events(
328        name: rxml::QName,
329        attrs: rxml::AttrMap,
330        ctx: &Context<'_>,
331    ) -> Result<Self::Builder, FromEventsError> {
332        match T::from_events(name, attrs, ctx) {
333            Ok(builder) => Ok(FallibleBuilder(FallibleBuilderInner::Processing {
334                depth: 0,
335                builder,
336            })),
337            Err(FromEventsError::Mismatch { name, attrs }) => {
338                Err(FromEventsError::Mismatch { name, attrs })
339            }
340            Err(FromEventsError::Invalid(e)) => Ok(FallibleBuilder(FallibleBuilderInner::Failed {
341                depth: 0,
342                err: Some(e.into()),
343            })),
344        }
345    }
346}
347
348/// Builder which discards an entire child tree without inspecting the
349/// contents.
350#[derive(Debug, Default)]
351pub struct Discard {
352    depth: usize,
353}
354
355impl Discard {
356    /// Create a new discarding builder.
357    pub fn new() -> Self {
358        Self::default()
359    }
360}
361
362impl FromEventsBuilder for Discard {
363    type Output = ();
364
365    fn feed(&mut self, ev: rxml::Event, _ctx: &Context<'_>) -> Result<Option<Self::Output>, Error> {
366        match ev {
367            rxml::Event::StartElement(..) => {
368                self.depth = match self.depth.checked_add(1) {
369                    Some(v) => v,
370                    None => return Err(Error::Other("maximum XML nesting depth exceeded")),
371                };
372                Ok(None)
373            }
374            rxml::Event::EndElement(..) => match self.depth.checked_sub(1) {
375                None => Ok(Some(())),
376                Some(v) => {
377                    self.depth = v;
378                    Ok(None)
379                }
380            },
381            _ => Ok(None),
382        }
383    }
384}
385
386/// Builder which discards the contents (or raises on unexpected contents).
387///
388/// This builder is only to be used from within the proc macros and is not
389/// stable, public API.
390#[doc(hidden)]
391#[cfg(feature = "macros")]
392pub struct EmptyBuilder {
393    childerr: &'static str,
394    texterr: &'static str,
395}
396
397#[cfg(feature = "macros")]
398impl FromEventsBuilder for EmptyBuilder {
399    type Output = ();
400
401    fn feed(&mut self, ev: rxml::Event, _ctx: &Context<'_>) -> Result<Option<Self::Output>, Error> {
402        match ev {
403            rxml::Event::EndElement(..) => Ok(Some(())),
404            rxml::Event::StartElement(..) => Err(Error::Other(self.childerr)),
405            rxml::Event::Text(..) => Err(Error::Other(self.texterr)),
406            _ => Err(Error::Other(
407                "unexpected content in supposed-to-be-empty element",
408            )),
409        }
410    }
411}
412
413/// Precursor struct for [`EmptyBuilder`].
414///
415/// This struct is only to be used from within the proc macros and is not
416/// stable, public API.
417#[doc(hidden)]
418#[cfg(feature = "macros")]
419pub struct Empty {
420    pub attributeerr: &'static str,
421    pub childerr: &'static str,
422    pub texterr: &'static str,
423}
424
425#[cfg(feature = "macros")]
426impl Empty {
427    pub fn start(self, attr: rxml::AttrMap) -> Result<EmptyBuilder, Error> {
428        if !attr.is_empty() {
429            return Err(Error::Other(self.attributeerr));
430        }
431        Ok(EmptyBuilder {
432            childerr: self.childerr,
433            texterr: self.texterr,
434        })
435    }
436}
437
438/// Construct a `Cow<'a, B>` from XML events.'
439pub struct CowBuilder<'a, B: ToOwned + ?Sized + 'a>
440where
441    B::Owned: FromXml,
442{
443    builder: <B::Owned as FromXml>::Builder,
444    tie: PhantomData<fn() -> &'a B>,
445}
446
447impl<'a, T: FromXml, B: ToOwned<Owned = T> + ?Sized + 'a> FromEventsBuilder for CowBuilder<'a, B> {
448    type Output = Cow<'a, B>;
449
450    fn feed(&mut self, ev: rxml::Event, ctx: &Context<'_>) -> Result<Option<Self::Output>, Error> {
451        self.builder
452            .feed(ev, ctx)
453            .map(|opt| opt.map(|x| Cow::Owned(x)))
454    }
455}
456
457impl<'a, T: FromXml, B: ToOwned<Owned = T> + ?Sized + 'a> FromXml for Cow<'a, B> {
458    type Builder = CowBuilder<'a, B>;
459
460    fn from_events(
461        qname: rxml::QName,
462        attrs: rxml::AttrMap,
463        ctx: &Context<'_>,
464    ) -> Result<Self::Builder, FromEventsError> {
465        Ok(CowBuilder {
466            builder: T::from_events(qname, attrs, ctx)?,
467            tie: PhantomData,
468        })
469    }
470}
471
472#[cfg(test)]
473mod tests {
474    use super::*;
475
476    use alloc::borrow::ToOwned;
477    use rxml::{parser::EventMetrics, Event, Namespace, NcName};
478
479    macro_rules! null_builder {
480        ($name:ident for $output:ident) => {
481            #[derive(Debug)]
482            enum $name {}
483
484            impl FromEventsBuilder for $name {
485                type Output = $output;
486
487                fn feed(
488                    &mut self,
489                    _: Event,
490                    _: &Context<'_>,
491                ) -> Result<Option<Self::Output>, Error> {
492                    unreachable!();
493                }
494            }
495        };
496    }
497
498    null_builder!(AlwaysMismatchBuilder for AlwaysMismatch);
499    null_builder!(InitialErrorBuilder for InitialError);
500
501    #[derive(Debug)]
502    struct AlwaysMismatch;
503
504    impl FromXml for AlwaysMismatch {
505        type Builder = AlwaysMismatchBuilder;
506
507        fn from_events(
508            name: rxml::QName,
509            attrs: rxml::AttrMap,
510            _ctx: &Context<'_>,
511        ) -> Result<Self::Builder, FromEventsError> {
512            Err(FromEventsError::Mismatch { name, attrs })
513        }
514    }
515
516    #[derive(Debug)]
517    struct InitialError;
518
519    impl FromXml for InitialError {
520        type Builder = InitialErrorBuilder;
521
522        fn from_events(
523            _: rxml::QName,
524            _: rxml::AttrMap,
525            _: &Context<'_>,
526        ) -> Result<Self::Builder, FromEventsError> {
527            Err(FromEventsError::Invalid(Error::Other("some error")))
528        }
529    }
530
531    #[derive(Debug)]
532    struct FailOnContentBuilder;
533
534    impl FromEventsBuilder for FailOnContentBuilder {
535        type Output = FailOnContent;
536
537        fn feed(&mut self, _: Event, _: &Context<'_>) -> Result<Option<Self::Output>, Error> {
538            Err(Error::Other("content error"))
539        }
540    }
541
542    #[derive(Debug)]
543    struct FailOnContent;
544
545    impl FromXml for FailOnContent {
546        type Builder = FailOnContentBuilder;
547
548        fn from_events(
549            _: rxml::QName,
550            _: rxml::AttrMap,
551            _: &Context<'_>,
552        ) -> Result<Self::Builder, FromEventsError> {
553            Ok(FailOnContentBuilder)
554        }
555    }
556
557    fn qname() -> rxml::QName {
558        (Namespace::NONE, NcName::try_from("test").unwrap())
559    }
560
561    fn attrs() -> rxml::AttrMap {
562        rxml::AttrMap::new()
563    }
564
565    #[test]
566    fn fallible_builder_mismatch_passthrough() {
567        match Result::<AlwaysMismatch, Error>::from_events(qname(), attrs(), &Context::empty()) {
568            Err(FromEventsError::Mismatch { .. }) => (),
569            other => panic!("unexpected result: {:?}", other),
570        }
571    }
572
573    #[test]
574    fn fallible_builder_initial_error_capture() {
575        let ctx = Context::empty();
576        let mut builder = match Result::<InitialError, Error>::from_events(qname(), attrs(), &ctx) {
577            Ok(v) => v,
578            other => panic!("unexpected result: {:?}", other),
579        };
580        match builder.feed(
581            Event::Text(EventMetrics::zero(), "hello world!".to_owned()),
582            &ctx,
583        ) {
584            Ok(None) => (),
585            other => panic!("unexpected result: {:?}", other),
586        };
587        match builder.feed(Event::EndElement(EventMetrics::zero()), &ctx) {
588            Ok(Some(Err(Error::Other("some error")))) => (),
589            other => panic!("unexpected result: {:?}", other),
590        };
591    }
592
593    #[test]
594    fn fallible_builder_initial_error_capture_allows_nested_stuff() {
595        let ctx = Context::empty();
596        let mut builder = match Result::<InitialError, Error>::from_events(qname(), attrs(), &ctx) {
597            Ok(v) => v,
598            other => panic!("unexpected result: {:?}", other),
599        };
600        match builder.feed(
601            Event::StartElement(EventMetrics::zero(), qname(), attrs()),
602            &ctx,
603        ) {
604            Ok(None) => (),
605            other => panic!("unexpected result: {:?}", other),
606        };
607        match builder.feed(
608            Event::Text(EventMetrics::zero(), "hello world!".to_owned()),
609            &ctx,
610        ) {
611            Ok(None) => (),
612            other => panic!("unexpected result: {:?}", other),
613        };
614        match builder.feed(Event::EndElement(EventMetrics::zero()), &ctx) {
615            Ok(None) => (),
616            other => panic!("unexpected result: {:?}", other),
617        };
618        match builder.feed(
619            Event::Text(EventMetrics::zero(), "hello world!".to_owned()),
620            &ctx,
621        ) {
622            Ok(None) => (),
623            other => panic!("unexpected result: {:?}", other),
624        };
625        match builder.feed(
626            Event::StartElement(EventMetrics::zero(), qname(), attrs()),
627            &ctx,
628        ) {
629            Ok(None) => (),
630            other => panic!("unexpected result: {:?}", other),
631        };
632        match builder.feed(
633            Event::StartElement(EventMetrics::zero(), qname(), attrs()),
634            &ctx,
635        ) {
636            Ok(None) => (),
637            other => panic!("unexpected result: {:?}", other),
638        };
639        match builder.feed(
640            Event::Text(EventMetrics::zero(), "hello world!".to_owned()),
641            &ctx,
642        ) {
643            Ok(None) => (),
644            other => panic!("unexpected result: {:?}", other),
645        };
646        match builder.feed(Event::EndElement(EventMetrics::zero()), &ctx) {
647            Ok(None) => (),
648            other => panic!("unexpected result: {:?}", other),
649        };
650        match builder.feed(Event::EndElement(EventMetrics::zero()), &ctx) {
651            Ok(None) => (),
652            other => panic!("unexpected result: {:?}", other),
653        };
654        match builder.feed(Event::EndElement(EventMetrics::zero()), &ctx) {
655            Ok(Some(Err(Error::Other("some error")))) => (),
656            other => panic!("unexpected result: {:?}", other),
657        };
658    }
659
660    #[test]
661    fn fallible_builder_content_error_capture() {
662        let ctx = Context::empty();
663        let mut builder = match Result::<FailOnContent, Error>::from_events(qname(), attrs(), &ctx)
664        {
665            Ok(v) => v,
666            other => panic!("unexpected result: {:?}", other),
667        };
668        match builder.feed(Event::EndElement(EventMetrics::zero()), &ctx) {
669            Ok(Some(Err(Error::Other("content error")))) => (),
670            other => panic!("unexpected result: {:?}", other),
671        };
672    }
673
674    #[test]
675    fn fallible_builder_content_error_capture_with_more_content() {
676        let ctx = Context::empty();
677        let mut builder = match Result::<FailOnContent, Error>::from_events(qname(), attrs(), &ctx)
678        {
679            Ok(v) => v,
680            other => panic!("unexpected result: {:?}", other),
681        };
682        match builder.feed(
683            Event::Text(EventMetrics::zero(), "hello world!".to_owned()),
684            &ctx,
685        ) {
686            Ok(None) => (),
687            other => panic!("unexpected result: {:?}", other),
688        };
689        match builder.feed(Event::EndElement(EventMetrics::zero()), &ctx) {
690            Ok(Some(Err(Error::Other("content error")))) => (),
691            other => panic!("unexpected result: {:?}", other),
692        };
693    }
694
695    #[test]
696    fn fallible_builder_content_error_capture_with_nested_content() {
697        let ctx = Context::empty();
698        let mut builder = match Result::<FailOnContent, Error>::from_events(qname(), attrs(), &ctx)
699        {
700            Ok(v) => v,
701            other => panic!("unexpected result: {:?}", other),
702        };
703        match builder.feed(
704            Event::StartElement(EventMetrics::zero(), qname(), attrs()),
705            &ctx,
706        ) {
707            Ok(None) => (),
708            other => panic!("unexpected result: {:?}", other),
709        };
710        match builder.feed(
711            Event::Text(EventMetrics::zero(), "hello world!".to_owned()),
712            &ctx,
713        ) {
714            Ok(None) => (),
715            other => panic!("unexpected result: {:?}", other),
716        };
717        match builder.feed(Event::EndElement(EventMetrics::zero()), &ctx) {
718            Ok(None) => (),
719            other => panic!("unexpected result: {:?}", other),
720        };
721        match builder.feed(
722            Event::Text(EventMetrics::zero(), "hello world!".to_owned()),
723            &ctx,
724        ) {
725            Ok(None) => (),
726            other => panic!("unexpected result: {:?}", other),
727        };
728        match builder.feed(
729            Event::StartElement(EventMetrics::zero(), qname(), attrs()),
730            &ctx,
731        ) {
732            Ok(None) => (),
733            other => panic!("unexpected result: {:?}", other),
734        };
735        match builder.feed(
736            Event::StartElement(EventMetrics::zero(), qname(), attrs()),
737            &ctx,
738        ) {
739            Ok(None) => (),
740            other => panic!("unexpected result: {:?}", other),
741        };
742        match builder.feed(
743            Event::Text(EventMetrics::zero(), "hello world!".to_owned()),
744            &ctx,
745        ) {
746            Ok(None) => (),
747            other => panic!("unexpected result: {:?}", other),
748        };
749        match builder.feed(Event::EndElement(EventMetrics::zero()), &ctx) {
750            Ok(None) => (),
751            other => panic!("unexpected result: {:?}", other),
752        };
753        match builder.feed(Event::EndElement(EventMetrics::zero()), &ctx) {
754            Ok(None) => (),
755            other => panic!("unexpected result: {:?}", other),
756        };
757        match builder.feed(Event::EndElement(EventMetrics::zero()), &ctx) {
758            Ok(Some(Err(Error::Other("content error")))) => (),
759            other => panic!("unexpected result: {:?}", other),
760        };
761    }
762}