1use alloc::boxed::Box;
16
17use crate::error::{Error, FromEventsError};
18use crate::{Context, FromEventsBuilder, FromXml};
19
20pub struct OptionBuilder<T: FromEventsBuilder>(T);
22
23impl<T: FromEventsBuilder> FromEventsBuilder for OptionBuilder<T> {
24 type Output = Option<T::Output>;
25
26 fn feed(&mut self, ev: rxml::Event, ctx: &Context<'_>) -> Result<Option<Self::Output>, Error> {
27 self.0.feed(ev, ctx).map(|ok| ok.map(Some))
28 }
29}
30
31impl<T: FromXml> FromXml for Option<T> {
38 type Builder = OptionBuilder<T::Builder>;
39
40 fn from_events(
41 name: rxml::QName,
42 attrs: rxml::AttrMap,
43 ctx: &Context<'_>,
44 ) -> Result<Self::Builder, FromEventsError> {
45 Ok(OptionBuilder(T::from_events(name, attrs, ctx)?))
46 }
47}
48
49pub struct BoxBuilder<T: FromEventsBuilder>(Box<T>);
51
52impl<T: FromEventsBuilder> FromEventsBuilder for BoxBuilder<T> {
53 type Output = Box<T::Output>;
54
55 fn feed(&mut self, ev: rxml::Event, ctx: &Context<'_>) -> Result<Option<Self::Output>, Error> {
56 self.0.feed(ev, ctx).map(|ok| ok.map(Box::new))
57 }
58}
59
60impl<T: FromXml> FromXml for Box<T> {
62 type Builder = BoxBuilder<T::Builder>;
63
64 fn from_events(
65 name: rxml::QName,
66 attrs: rxml::AttrMap,
67 ctx: &Context<'_>,
68 ) -> Result<Self::Builder, FromEventsError> {
69 Ok(BoxBuilder(Box::new(T::from_events(name, attrs, ctx)?)))
70 }
71}
72
73#[derive(Debug)]
74enum FallibleBuilderInner<T: FromEventsBuilder, E> {
75 Processing { depth: usize, builder: T },
76 Failed { depth: usize, err: Option<E> },
77 Done,
78}
79
80#[derive(Debug)]
92pub struct FallibleBuilder<T: FromEventsBuilder, E>(FallibleBuilderInner<T, E>);
93
94impl<T: FromEventsBuilder, E: From<Error>> FromEventsBuilder for FallibleBuilder<T, E> {
95 type Output = Result<T::Output, E>;
96
97 fn feed(&mut self, ev: rxml::Event, ctx: &Context<'_>) -> Result<Option<Self::Output>, Error> {
98 match self.0 {
99 FallibleBuilderInner::Processing {
100 ref mut depth,
101 ref mut builder,
102 } => {
103 let new_depth = match ev {
104 rxml::Event::StartElement(..) => match depth.checked_add(1) {
105 None => {
117 self.0 = FallibleBuilderInner::Done;
118 return Err(Error::Other("maximum XML nesting depth exceeded"));
119 }
120 Some(v) => Some(v),
121 },
122 rxml::Event::EndElement(..) => depth.checked_sub(1),
129
130 rxml::Event::XmlDeclaration(..) | rxml::Event::Text(..) => Some(*depth),
133 };
134
135 match builder.feed(ev, ctx) {
136 Ok(Some(v)) => {
137 self.0 = FallibleBuilderInner::Done;
138 return Ok(Some(Ok(v)));
139 }
140 Ok(None) => {
141 }
143 Err(e) => {
144 match new_depth {
146 Some(depth) => {
149 self.0 = FallibleBuilderInner::Failed {
150 depth,
151 err: Some(e.into()),
152 };
153 return Ok(None);
154 }
155 None => {
158 self.0 = FallibleBuilderInner::Done;
159 return Ok(Some(Err(e.into())));
160 }
161 }
162 }
163 };
164
165 *depth = match new_depth {
166 Some(v) => v,
167 None => unreachable!("fallible parsing continued beyond end of element"),
168 };
169
170 Ok(None)
172 }
173 FallibleBuilderInner::Failed {
174 ref mut depth,
175 ref mut err,
176 } => {
177 *depth = match ev {
178 rxml::Event::StartElement(..) => match depth.checked_add(1) {
179 None => {
181 self.0 = FallibleBuilderInner::Done;
182 return Err(Error::Other("maximum XML nesting depth exceeded"));
183 }
184 Some(v) => v,
185 },
186 rxml::Event::EndElement(..) => match depth.checked_sub(1) {
187 Some(v) => v,
188 None => {
189 let err = err.take().expect("fallible parsing somehow lost its error");
192 self.0 = FallibleBuilderInner::Done;
193 return Ok(Some(Err(err)));
194 }
195 },
196
197 rxml::Event::XmlDeclaration(..) | rxml::Event::Text(..) => *depth,
200 };
201
202 Ok(None)
204 }
205 FallibleBuilderInner::Done => {
206 panic!("FromEventsBuilder called after it returned a value")
207 }
208 }
209 }
210}
211
212impl<T: FromXml, E: From<Error>> FromXml for Result<T, E> {
214 type Builder = FallibleBuilder<T::Builder, E>;
215
216 fn from_events(
217 name: rxml::QName,
218 attrs: rxml::AttrMap,
219 ctx: &Context<'_>,
220 ) -> Result<Self::Builder, FromEventsError> {
221 match T::from_events(name, attrs, ctx) {
222 Ok(builder) => Ok(FallibleBuilder(FallibleBuilderInner::Processing {
223 depth: 0,
224 builder,
225 })),
226 Err(FromEventsError::Mismatch { name, attrs }) => {
227 Err(FromEventsError::Mismatch { name, attrs })
228 }
229 Err(FromEventsError::Invalid(e)) => Ok(FallibleBuilder(FallibleBuilderInner::Failed {
230 depth: 0,
231 err: Some(e.into()),
232 })),
233 }
234 }
235}
236
237#[derive(Debug, Default)]
240pub struct Discard {
241 depth: usize,
242}
243
244impl Discard {
245 pub fn new() -> Self {
247 Self::default()
248 }
249}
250
251impl FromEventsBuilder for Discard {
252 type Output = ();
253
254 fn feed(&mut self, ev: rxml::Event, _ctx: &Context<'_>) -> Result<Option<Self::Output>, Error> {
255 match ev {
256 rxml::Event::StartElement(..) => {
257 self.depth = match self.depth.checked_add(1) {
258 Some(v) => v,
259 None => return Err(Error::Other("maximum XML nesting depth exceeded")),
260 };
261 Ok(None)
262 }
263 rxml::Event::EndElement(..) => match self.depth.checked_sub(1) {
264 None => Ok(Some(())),
265 Some(v) => {
266 self.depth = v;
267 Ok(None)
268 }
269 },
270 _ => Ok(None),
271 }
272 }
273}
274
275#[doc(hidden)]
280#[cfg(feature = "macros")]
281pub struct EmptyBuilder {
282 childerr: &'static str,
283 texterr: &'static str,
284}
285
286#[cfg(feature = "macros")]
287impl FromEventsBuilder for EmptyBuilder {
288 type Output = ();
289
290 fn feed(&mut self, ev: rxml::Event, _ctx: &Context<'_>) -> Result<Option<Self::Output>, Error> {
291 match ev {
292 rxml::Event::EndElement(..) => Ok(Some(())),
293 rxml::Event::StartElement(..) => Err(Error::Other(self.childerr)),
294 rxml::Event::Text(..) => Err(Error::Other(self.texterr)),
295 _ => Err(Error::Other(
296 "unexpected content in supposed-to-be-empty element",
297 )),
298 }
299 }
300}
301
302#[doc(hidden)]
307#[cfg(feature = "macros")]
308pub struct Empty {
309 pub attributeerr: &'static str,
310 pub childerr: &'static str,
311 pub texterr: &'static str,
312}
313
314#[cfg(feature = "macros")]
315impl Empty {
316 pub fn start(self, attr: rxml::AttrMap) -> Result<EmptyBuilder, Error> {
317 if !attr.is_empty() {
318 return Err(Error::Other(self.attributeerr));
319 }
320 Ok(EmptyBuilder {
321 childerr: self.childerr,
322 texterr: self.texterr,
323 })
324 }
325}
326
327#[cfg(test)]
328mod tests {
329 use super::*;
330
331 use alloc::borrow::ToOwned;
332 use rxml::{parser::EventMetrics, Event, Namespace, NcName};
333
334 macro_rules! null_builder {
335 ($name:ident for $output:ident) => {
336 #[derive(Debug)]
337 enum $name {}
338
339 impl FromEventsBuilder for $name {
340 type Output = $output;
341
342 fn feed(
343 &mut self,
344 _: Event,
345 _: &Context<'_>,
346 ) -> Result<Option<Self::Output>, Error> {
347 unreachable!();
348 }
349 }
350 };
351 }
352
353 null_builder!(AlwaysMismatchBuilder for AlwaysMismatch);
354 null_builder!(InitialErrorBuilder for InitialError);
355
356 #[derive(Debug)]
357 struct AlwaysMismatch;
358
359 impl FromXml for AlwaysMismatch {
360 type Builder = AlwaysMismatchBuilder;
361
362 fn from_events(
363 name: rxml::QName,
364 attrs: rxml::AttrMap,
365 _ctx: &Context<'_>,
366 ) -> Result<Self::Builder, FromEventsError> {
367 Err(FromEventsError::Mismatch { name, attrs })
368 }
369 }
370
371 #[derive(Debug)]
372 struct InitialError;
373
374 impl FromXml for InitialError {
375 type Builder = InitialErrorBuilder;
376
377 fn from_events(
378 _: rxml::QName,
379 _: rxml::AttrMap,
380 _: &Context<'_>,
381 ) -> Result<Self::Builder, FromEventsError> {
382 Err(FromEventsError::Invalid(Error::Other("some error")))
383 }
384 }
385
386 #[derive(Debug)]
387 struct FailOnContentBuilder;
388
389 impl FromEventsBuilder for FailOnContentBuilder {
390 type Output = FailOnContent;
391
392 fn feed(&mut self, _: Event, _: &Context<'_>) -> Result<Option<Self::Output>, Error> {
393 Err(Error::Other("content error"))
394 }
395 }
396
397 #[derive(Debug)]
398 struct FailOnContent;
399
400 impl FromXml for FailOnContent {
401 type Builder = FailOnContentBuilder;
402
403 fn from_events(
404 _: rxml::QName,
405 _: rxml::AttrMap,
406 _: &Context<'_>,
407 ) -> Result<Self::Builder, FromEventsError> {
408 Ok(FailOnContentBuilder)
409 }
410 }
411
412 fn qname() -> rxml::QName {
413 (Namespace::NONE, NcName::try_from("test").unwrap())
414 }
415
416 fn attrs() -> rxml::AttrMap {
417 rxml::AttrMap::new()
418 }
419
420 #[test]
421 fn fallible_builder_mismatch_passthrough() {
422 match Result::<AlwaysMismatch, Error>::from_events(qname(), attrs(), &Context::empty()) {
423 Err(FromEventsError::Mismatch { .. }) => (),
424 other => panic!("unexpected result: {:?}", other),
425 }
426 }
427
428 #[test]
429 fn fallible_builder_initial_error_capture() {
430 let ctx = Context::empty();
431 let mut builder = match Result::<InitialError, Error>::from_events(qname(), attrs(), &ctx) {
432 Ok(v) => v,
433 other => panic!("unexpected result: {:?}", other),
434 };
435 match builder.feed(
436 Event::Text(EventMetrics::zero(), "hello world!".to_owned()),
437 &ctx,
438 ) {
439 Ok(None) => (),
440 other => panic!("unexpected result: {:?}", other),
441 };
442 match builder.feed(Event::EndElement(EventMetrics::zero()), &ctx) {
443 Ok(Some(Err(Error::Other("some error")))) => (),
444 other => panic!("unexpected result: {:?}", other),
445 };
446 }
447
448 #[test]
449 fn fallible_builder_initial_error_capture_allows_nested_stuff() {
450 let ctx = Context::empty();
451 let mut builder = match Result::<InitialError, Error>::from_events(qname(), attrs(), &ctx) {
452 Ok(v) => v,
453 other => panic!("unexpected result: {:?}", other),
454 };
455 match builder.feed(
456 Event::StartElement(EventMetrics::zero(), qname(), attrs()),
457 &ctx,
458 ) {
459 Ok(None) => (),
460 other => panic!("unexpected result: {:?}", other),
461 };
462 match builder.feed(
463 Event::Text(EventMetrics::zero(), "hello world!".to_owned()),
464 &ctx,
465 ) {
466 Ok(None) => (),
467 other => panic!("unexpected result: {:?}", other),
468 };
469 match builder.feed(Event::EndElement(EventMetrics::zero()), &ctx) {
470 Ok(None) => (),
471 other => panic!("unexpected result: {:?}", other),
472 };
473 match builder.feed(
474 Event::Text(EventMetrics::zero(), "hello world!".to_owned()),
475 &ctx,
476 ) {
477 Ok(None) => (),
478 other => panic!("unexpected result: {:?}", other),
479 };
480 match builder.feed(
481 Event::StartElement(EventMetrics::zero(), qname(), attrs()),
482 &ctx,
483 ) {
484 Ok(None) => (),
485 other => panic!("unexpected result: {:?}", other),
486 };
487 match builder.feed(
488 Event::StartElement(EventMetrics::zero(), qname(), attrs()),
489 &ctx,
490 ) {
491 Ok(None) => (),
492 other => panic!("unexpected result: {:?}", other),
493 };
494 match builder.feed(
495 Event::Text(EventMetrics::zero(), "hello world!".to_owned()),
496 &ctx,
497 ) {
498 Ok(None) => (),
499 other => panic!("unexpected result: {:?}", other),
500 };
501 match builder.feed(Event::EndElement(EventMetrics::zero()), &ctx) {
502 Ok(None) => (),
503 other => panic!("unexpected result: {:?}", other),
504 };
505 match builder.feed(Event::EndElement(EventMetrics::zero()), &ctx) {
506 Ok(None) => (),
507 other => panic!("unexpected result: {:?}", other),
508 };
509 match builder.feed(Event::EndElement(EventMetrics::zero()), &ctx) {
510 Ok(Some(Err(Error::Other("some error")))) => (),
511 other => panic!("unexpected result: {:?}", other),
512 };
513 }
514
515 #[test]
516 fn fallible_builder_content_error_capture() {
517 let ctx = Context::empty();
518 let mut builder = match Result::<FailOnContent, Error>::from_events(qname(), attrs(), &ctx)
519 {
520 Ok(v) => v,
521 other => panic!("unexpected result: {:?}", other),
522 };
523 match builder.feed(Event::EndElement(EventMetrics::zero()), &ctx) {
524 Ok(Some(Err(Error::Other("content error")))) => (),
525 other => panic!("unexpected result: {:?}", other),
526 };
527 }
528
529 #[test]
530 fn fallible_builder_content_error_capture_with_more_content() {
531 let ctx = Context::empty();
532 let mut builder = match Result::<FailOnContent, Error>::from_events(qname(), attrs(), &ctx)
533 {
534 Ok(v) => v,
535 other => panic!("unexpected result: {:?}", other),
536 };
537 match builder.feed(
538 Event::Text(EventMetrics::zero(), "hello world!".to_owned()),
539 &ctx,
540 ) {
541 Ok(None) => (),
542 other => panic!("unexpected result: {:?}", other),
543 };
544 match builder.feed(Event::EndElement(EventMetrics::zero()), &ctx) {
545 Ok(Some(Err(Error::Other("content error")))) => (),
546 other => panic!("unexpected result: {:?}", other),
547 };
548 }
549
550 #[test]
551 fn fallible_builder_content_error_capture_with_nested_content() {
552 let ctx = Context::empty();
553 let mut builder = match Result::<FailOnContent, Error>::from_events(qname(), attrs(), &ctx)
554 {
555 Ok(v) => v,
556 other => panic!("unexpected result: {:?}", other),
557 };
558 match builder.feed(
559 Event::StartElement(EventMetrics::zero(), qname(), attrs()),
560 &ctx,
561 ) {
562 Ok(None) => (),
563 other => panic!("unexpected result: {:?}", other),
564 };
565 match builder.feed(
566 Event::Text(EventMetrics::zero(), "hello world!".to_owned()),
567 &ctx,
568 ) {
569 Ok(None) => (),
570 other => panic!("unexpected result: {:?}", other),
571 };
572 match builder.feed(Event::EndElement(EventMetrics::zero()), &ctx) {
573 Ok(None) => (),
574 other => panic!("unexpected result: {:?}", other),
575 };
576 match builder.feed(
577 Event::Text(EventMetrics::zero(), "hello world!".to_owned()),
578 &ctx,
579 ) {
580 Ok(None) => (),
581 other => panic!("unexpected result: {:?}", other),
582 };
583 match builder.feed(
584 Event::StartElement(EventMetrics::zero(), qname(), attrs()),
585 &ctx,
586 ) {
587 Ok(None) => (),
588 other => panic!("unexpected result: {:?}", other),
589 };
590 match builder.feed(
591 Event::StartElement(EventMetrics::zero(), qname(), attrs()),
592 &ctx,
593 ) {
594 Ok(None) => (),
595 other => panic!("unexpected result: {:?}", other),
596 };
597 match builder.feed(
598 Event::Text(EventMetrics::zero(), "hello world!".to_owned()),
599 &ctx,
600 ) {
601 Ok(None) => (),
602 other => panic!("unexpected result: {:?}", other),
603 };
604 match builder.feed(Event::EndElement(EventMetrics::zero()), &ctx) {
605 Ok(None) => (),
606 other => panic!("unexpected result: {:?}", other),
607 };
608 match builder.feed(Event::EndElement(EventMetrics::zero()), &ctx) {
609 Ok(None) => (),
610 other => panic!("unexpected result: {:?}", other),
611 };
612 match builder.feed(Event::EndElement(EventMetrics::zero()), &ctx) {
613 Ok(Some(Err(Error::Other("content error")))) => (),
614 other => panic!("unexpected result: {:?}", other),
615 };
616 }
617}