1use 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#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
26pub enum XmlNameMatcher<'x> {
27 Any,
29
30 InNamespace(&'x str),
32
33 Specific(&'x str, &'x str),
35}
36
37impl<'x> XmlNameMatcher<'x> {
38 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 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#[derive(Debug)]
97#[doc(hidden)]
98pub struct Context<'x> {
99 language: Option<&'x str>,
100}
101
102impl<'x> Context<'x> {
103 pub fn empty() -> Self {
107 Self { language: None }
108 }
109
110 pub fn with_language(mut self, language: Option<&'x str>) -> Self {
112 self.language = language;
113 self
114 }
115
116 pub fn language(&self) -> Option<&str> {
119 self.language
120 }
121}
122
123pub 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
134impl<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
152pub 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
163impl<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#[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 None => {
228 self.0 = FallibleBuilderInner::Done;
229 return Err(Error::Other("maximum XML nesting depth exceeded"));
230 }
231 Some(v) => Some(v),
232 },
233 rxml::Event::EndElement(..) => depth.checked_sub(1),
240
241 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 }
254 Err(e) => {
255 match new_depth {
257 Some(depth) => {
260 self.0 = FallibleBuilderInner::Failed {
261 depth,
262 err: Some(e.into()),
263 };
264 return Ok(None);
265 }
266 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 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 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 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 rxml::Event::XmlDeclaration(..) | rxml::Event::Text(..) => *depth,
311 };
312
313 Ok(None)
315 }
316 FallibleBuilderInner::Done => {
317 panic!("FromEventsBuilder called after it returned a value")
318 }
319 }
320 }
321}
322
323impl<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#[derive(Debug, Default)]
351pub struct Discard {
352 depth: usize,
353}
354
355impl Discard {
356 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#[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#[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
438pub 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}