1use std::{borrow::Cow, collections::HashMap};
2
3use quick_xml::{
4 NsReader, XmlVersion,
5 escape::unescape,
6 events::{BytesStart, Event},
7 name::{QName, ResolveResult},
8};
9use thiserror::Error;
10
11use crate::{
12 EMLVersion, MultipleEMLErrors, NS_EML, NS_KR, OASIS_EML_SCHEMA_VERSION,
13 error::{EMLError, EMLErrorKind, EMLResultExt},
14 io::{EMLElement, QualifiedName},
15 utils::{StringValue, StringValueData},
16};
17
18pub trait EMLRead {
20 fn parse_eml(input: &str, parsing_mode: EMLParsingMode) -> EMLReadResult<Self>
29 where
30 Self: Sized;
31
32 fn parse_eml_fragment(
35 input: &str,
36 parsing_mode: EMLParsingMode,
37 document_version: EMLVersion,
38 ) -> EMLReadResult<Self>
39 where
40 Self: Sized;
41}
42
43#[must_use]
45#[derive(Debug)]
46pub enum EMLReadResult<T> {
47 Ok(T, Vec<EMLError>),
49 Err(EMLError),
51}
52
53impl<T> EMLReadResult<T> {
54 pub fn errors(&self) -> &[EMLError] {
56 match self {
57 EMLReadResult::Ok(_, errors) => errors,
58 EMLReadResult::Err(EMLError::Multiple(MultipleEMLErrors { errors })) => errors,
59 EMLReadResult::Err(err) => std::slice::from_ref(err),
60 }
61 }
62
63 pub fn ok(self) -> Result<T, EMLError> {
66 self.into()
67 }
68
69 pub fn ok_with_errors(self) -> Result<(T, Vec<EMLError>), EMLError> {
72 self.into()
73 }
74
75 pub fn unwrap(self) -> T {
77 self.ok().unwrap()
78 }
79
80 pub fn expect(self, msg: &str) -> T {
82 self.ok().expect(msg)
83 }
84}
85
86impl<T> From<EMLReadResult<T>> for Result<T, EMLError> {
87 fn from(value: EMLReadResult<T>) -> Self {
88 match value {
89 EMLReadResult::Ok(doc, _) => Ok(doc),
90 EMLReadResult::Err(e) => Err(e),
91 }
92 }
93}
94
95impl<T> From<EMLReadResult<T>> for Result<(T, Vec<EMLError>), EMLError> {
96 fn from(value: EMLReadResult<T>) -> Self {
97 match value {
98 EMLReadResult::Ok(doc, errors) => Ok((doc, errors)),
99 EMLReadResult::Err(e) => Err(e),
100 }
101 }
102}
103
104impl<T> EMLRead for T
105where
106 T: EMLReadElement + 'static,
107{
108 fn parse_eml(input: &str, parsing_mode: EMLParsingMode) -> EMLReadResult<Self>
109 where
110 Self: Sized + 'static,
111 {
112 match EMLReader::try_init_from_str(input, parsing_mode) {
113 Ok(r) => read_eml_details(r),
114 Err(e) => EMLReadResult::Err(e),
115 }
116 }
117
118 fn parse_eml_fragment(
119 input: &str,
120 parsing_mode: EMLParsingMode,
121 document_version: EMLVersion,
122 ) -> EMLReadResult<Self>
123 where
124 Self: Sized + 'static,
125 {
126 read_eml_details(EMLReader::init_from_str_with_version(
127 input,
128 parsing_mode,
129 document_version,
130 ))
131 }
132}
133
134fn read_eml_details<T: EMLReadElement + 'static>(mut reader: EMLReader<'_>) -> EMLReadResult<T> {
135 let res = reader.with_next_element(|r| T::read_eml_element(r));
136
137 let e = match res {
138 Ok(doc) => return EMLReadResult::Ok(doc, reader.errors),
139 Err(e) => e,
140 };
141
142 if reader.errors.is_empty() {
143 EMLReadResult::Err(e)
144 } else {
145 EMLReadResult::Err(EMLError::from_vec_with_additional(reader.errors, e))
146 }
147}
148
149pub(crate) trait EMLReadElement {
151 fn read_eml_element<'a, 'b>(elem: &mut EMLElementReader<'a, 'b>) -> Result<Self, EMLError>
152 where
153 Self: Sized + 'static;
154}
155
156#[derive(Debug, Clone, Copy, PartialEq, Eq)]
158pub struct Span {
159 pub start: u64,
161 pub end: u64,
163}
164
165impl Span {
166 pub fn new(start: u64, end: u64) -> Span {
168 Span { start, end }
169 }
170}
171
172impl std::fmt::Display for Span {
173 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
174 write!(f, "{} until {}", self.start, self.end)
175 }
176}
177
178#[derive(Debug, Clone, Copy, PartialEq, Eq)]
189pub enum EMLParsingMode {
190 Strict,
192
193 StrictFallback,
197
198 Loose,
200}
201
202impl EMLParsingMode {
203 pub fn is_strict(&self) -> bool {
205 matches!(self, EMLParsingMode::Strict)
206 }
207}
208
209pub(crate) struct EMLReader<'a> {
214 inner: NsReader<&'a [u8]>,
215 xml_version: XmlVersion,
216 version: EMLVersion,
217 parsing_mode: EMLParsingMode,
218 errors: Vec<EMLError>,
219}
220
221impl<'a> EMLReader<'a> {
222 pub fn try_init_from_str(
227 data: &'a str,
228 parsing_mode: EMLParsingMode,
229 ) -> Result<EMLReader<'a>, EMLError> {
230 let reader = NsReader::from_str(data);
231 let version = extract_eml_nl_version(EMLReader {
232 inner: reader.clone(),
233 xml_version: XmlVersion::default(),
234 version: EMLVersion::V1_2_2,
235 parsing_mode: EMLParsingMode::Loose,
236 errors: Vec::new(),
237 })?;
238 Ok(Self::from_reader(reader, parsing_mode, version))
239 }
240
241 pub fn init_from_str_with_version(
243 data: &'a str,
244 parsing_mode: EMLParsingMode,
245 version: EMLVersion,
246 ) -> EMLReader<'a> {
247 Self::from_reader(NsReader::from_str(data), parsing_mode, version)
248 }
249
250 fn from_reader(
251 reader: NsReader<&'a [u8]>,
252 parsing_mode: EMLParsingMode,
253 version: EMLVersion,
254 ) -> EMLReader<'a> {
255 EMLReader {
256 inner: reader,
257 version,
258 xml_version: XmlVersion::default(),
259 parsing_mode,
260 errors: Vec::new(),
261 }
262 }
263
264 fn next(&mut self) -> Result<(Event<'a>, Span), EMLError> {
265 let span_start = self.inner.buffer_position();
266 let event = self.inner.read_event();
267 let event = match event {
268 Ok(evt) => evt,
269 Err(xml_err) => {
270 let error_pos = self.inner.error_position();
271 if error_pos == 0 {
272 return Err(xml_err)
277 .with_span(Span::new(span_start, self.inner.buffer_position()));
278 } else {
279 return Err(xml_err).with_span(Span::new(error_pos, error_pos));
280 }
281 }
282 };
283 let span = Span::new(span_start, self.inner.buffer_position());
284
285 if let Event::Decl(d) = &event {
287 self.xml_version = d.xml_version().with_span(span)?;
288 }
289
290 Ok((event, span))
291 }
292
293 pub fn next_element<'tmp>(&'tmp mut self) -> Result<EMLElementReader<'tmp, 'a>, EMLError> {
294 loop {
295 match self.next()? {
296 (Event::Start(start), span) => {
297 return Ok(EMLElementReader::from_start(self, start, false, span));
298 }
299 (Event::Empty(start), span) => {
300 return Ok(EMLElementReader::from_start(self, start, true, span));
301 }
302 (Event::Eof, span) => {
303 return Err(EMLErrorKind::UnexpectedEof).with_span(span);
304 }
305 _other => {
306 }
308 }
309 }
310 }
311
312 pub fn with_next_element<R>(
313 &mut self,
314 f: impl for<'d, 'e> FnOnce(&mut EMLElementReader<'d, 'e>) -> Result<R, EMLError>,
315 ) -> Result<R, EMLError> {
316 let mut root = self.next_element()?;
317 f(&mut root)
318 }
319
320 pub fn document_version(&self) -> EMLVersion {
322 self.version
323 }
324}
325
326fn extract_eml_nl_version(mut reader: EMLReader) -> Result<EMLVersion, EMLError> {
327 let mut root = reader.next_element()?;
329 if !root.has_name(("EML", Some(NS_EML)))? {
330 return Err(EMLErrorKind::InvalidRootElement).with_span(root.span());
331 }
332
333 let schema_version = root.attribute_value_req(("SchemaVersion", None))?;
334 if schema_version != OASIS_EML_SCHEMA_VERSION {
335 return Err(EMLErrorKind::SchemaVersionNotSupported(
336 schema_version.to_string(),
337 ))
338 .with_span(root.span());
339 }
340
341 while let Some(child) = root.next_child()? {
343 if child.has_name(("Schema", Some(NS_KR)))? {
344 let version = child.attribute_value(("Version", None))?;
345 if let Some(version) = version {
346 return Ok(version.as_ref().parse::<EMLVersion>()?);
347 }
348 }
349 }
350
351 Ok(EMLVersion::V1_2_2)
352}
353
354pub(crate) struct EMLElementReader<'r, 'input> {
360 reader: &'r mut EMLReader<'input>,
361 start: BytesStart<'input>,
362 depth: usize,
363 found_matching_end: bool,
364 is_empty: bool,
365 span: Span,
366 last_span: Span,
367}
368
369impl<'r, 'input> EMLElementReader<'r, 'input> {
370 pub fn document_version(&self) -> EMLVersion {
372 self.reader.document_version()
373 }
374
375 pub fn from_start(
382 reader: &'r mut EMLReader<'input>,
383 start: BytesStart<'input>,
384 is_empty: bool,
385 span: Span,
386 ) -> EMLElementReader<'r, 'input> {
387 EMLElementReader {
388 reader,
389 start,
390 depth: 1,
391 found_matching_end: is_empty,
392 is_empty,
393 span,
394 last_span: span,
395 }
396 }
397
398 pub fn name(&self) -> Result<QualifiedName<'_, '_>, EMLError> {
401 self.get_resolved_name(self.start.name(), self.span, false)
402 }
403
404 pub fn has_name<'a, 'b>(
406 &self,
407 name: impl Into<QualifiedName<'a, 'b>>,
408 ) -> Result<bool, EMLError> {
409 self.is_resolved_name(self.start.name(), self.span, name, false)
410 }
411
412 pub fn next_child(&mut self) -> Result<Option<EMLElementReader<'_, 'input>>, EMLError> {
417 loop {
418 match self.next()? {
419 Some((Event::Start(start), span)) => {
420 self.depth -= 1; return Ok(Some(EMLElementReader::from_start(
422 self.reader,
423 start,
424 false,
425 span,
426 )));
427 }
428 Some((Event::Empty(start), span)) => {
429 return Ok(Some(EMLElementReader::from_start(
430 self.reader,
431 start,
432 true,
433 span,
434 )));
435 }
436 None => return Ok(None),
437 _other => {
438 }
440 }
441 }
442 }
443
444 pub fn attribute_value_req<'a, 'b>(
447 &self,
448 name: impl Into<QualifiedName<'a, 'b>>,
449 ) -> Result<Cow<'_, str>, EMLError> {
450 let name = name.into();
451 self.attribute_value(name.clone())?
452 .ok_or_else(|| EMLErrorKind::MissingAttribute(name.as_owned()))
453 .with_span(self.span)
454 }
455
456 pub fn attribute_value<'a, 'b>(
459 &self,
460 name: impl Into<QualifiedName<'a, 'b>>,
461 ) -> Result<Option<Cow<'_, str>>, EMLError> {
462 let name = name.into();
463 for attr in self.start.attributes() {
465 let attr = attr.with_span(self.span)?;
466 if self.is_resolved_name(attr.key, self.span, name.clone(), true)? {
467 return Ok(Some(
468 attr.decoded_and_normalized_value(
469 self.reader.xml_version,
470 self.reader.inner.decoder(),
471 )
472 .with_span(self.span)?,
473 ));
474 }
475 }
476 Ok(None)
477 }
478
479 #[expect(unused)]
481 pub fn attributes(&self) -> Result<HashMap<QualifiedName<'_, '_>, Cow<'_, str>>, EMLError> {
482 let mut attributes = HashMap::new();
483 for attr in self.start.attributes() {
485 let attr = attr.with_span(self.span)?;
486 let name = self.get_resolved_name(attr.key, self.span, true)?;
487 let value = attr
488 .decoded_and_normalized_value(self.reader.xml_version, self.reader.inner.decoder())
489 .with_span(self.span)?;
490 attributes.insert(name, value);
491 }
492 Ok(attributes)
493 }
494
495 pub fn text_without_children_opt(&mut self) -> Result<Option<Box<str>>, EMLError> {
498 if self.is_empty {
499 Ok(None)
500 } else {
501 let text = self.text_without_children()?;
502 if text.is_empty() {
503 Ok(None)
504 } else {
505 Ok(Some(text))
506 }
507 }
508 }
509
510 pub fn text_without_children(&mut self) -> Result<Box<str>, EMLError> {
514 let mut text = String::new();
515 loop {
516 match self.next()? {
517 Some((Event::Text(t), span)) => {
518 let decoded = t.xml_content(self.reader.xml_version).with_span(span)?;
519 text.push_str(decoded.as_ref());
520 }
521 Some((Event::CData(t), span)) => {
522 let decoded = t.xml_content(self.reader.xml_version).with_span(span)?;
523 text.push_str(decoded.as_ref());
524 }
525 Some((Event::GeneralRef(r), span)) => {
526 let ref_name = r.decode().with_span(span)?;
527 let formatted_entity = format!("&{};", ref_name);
528
529 text.push_str(unescape(&formatted_entity).with_span(span)?.as_ref());
530 }
531 Some((Event::Comment(_), _)) => {
532 }
534 None => break,
535 Some((_other, span)) => {
536 return Err(EMLErrorKind::UnexpectedEvent).with_span(span);
537 }
538 }
539 }
540 Ok(text.into())
541 }
542
543 pub fn read_bool(&mut self) -> Result<bool, EMLError> {
548 let text = self.text_without_children()?;
549 match text.as_ref() {
550 "true" | "1" => Ok(true),
551 "false" | "0" => Ok(false),
552 other => {
553 let err = EMLErrorKind::InvalidValue(
554 self.name()?.as_owned(),
555 Box::new(InvalidBooleanValue(other.to_owned())),
556 )
557 .with_span(self.full_span());
558 if self.parsing_mode() == EMLParsingMode::Strict {
559 Err(err)
560 } else {
561 self.push_err(err);
562 Ok(false)
563 }
564 }
565 }
566 }
567
568 pub fn skip(&mut self) -> Result<(), EMLError> {
571 while let Some(_evt) = self.next()? {
572 }
574 Ok(())
575 }
576
577 pub fn span(&self) -> Span {
579 self.span
580 }
581
582 pub fn last_span(&self) -> Span {
584 self.last_span
585 }
586
587 pub fn full_span(&self) -> Span {
591 Span::new(self.span.start, self.last_span.end)
592 }
593
594 pub fn inner_span(&self) -> Span {
599 Span::new(self.span.end, self.last_span.start)
600 }
601
602 pub fn parsing_mode(&self) -> EMLParsingMode {
604 self.reader.parsing_mode
605 }
606
607 pub fn push_err(&mut self, err: EMLError) {
609 if let EMLError::Multiple(MultipleEMLErrors { errors }) = err {
610 self.reader.errors.extend(errors);
611 } else {
612 self.reader.errors.push(err);
613 }
614 }
615
616 pub fn read_element<T: EMLElement>(&mut self) -> Result<T, EMLError> {
618 if !T::EML_VERSIONS.contains(self.document_version()) {
619 return Err(EMLErrorKind::ElementNotSupportedInVersion(
620 T::EML_NAME.as_owned(),
621 self.document_version(),
622 )
623 .with_span(self.span()));
624 }
625
626 T::read_eml(self)
627 }
628
629 pub fn report_validation(
634 &mut self,
635 result: Result<(), EMLError>,
636 span: Span,
637 ) -> Result<(), EMLError> {
638 if let Err(e) = result {
639 let e = e.into_kind().with_span(span);
640 if self.parsing_mode().is_strict() {
641 return Err(e);
642 } else {
643 self.push_err(e);
644 }
645 }
646 Ok(())
647 }
648
649 fn map_value_error<'a, 'b, T: StringValueData>(
651 &self,
652 parsing_error: Result<StringValue<T>, T::Error>,
653 name: QualifiedName<'a, 'b>,
654 span: Span,
655 ) -> Result<StringValue<T>, EMLError> {
656 parsing_error.map_err(|e| EMLError::invalid_value(name.as_owned(), e, Some(span)))
657 }
658
659 pub(crate) fn string_value_from_text<'a, 'b, T: StringValueData>(
663 &mut self,
664 text: Box<str>,
665 name: Option<QualifiedName<'a, 'b>>,
666 span: Span,
667 ) -> Result<StringValue<T>, EMLError> {
668 let name = name.map_or_else(|| self.name(), Ok)?;
669 match self.parsing_mode() {
670 EMLParsingMode::Strict => {
671 self.map_value_error(StringValue::<T>::from_raw_parsed(&text), name, span)
672 }
673 EMLParsingMode::StrictFallback => {
674 match self.map_value_error(StringValue::<T>::from_raw_parsed(&text), name, span) {
675 Ok(v) => Ok(v),
676 Err(e) => {
677 self.push_err(e);
678 Ok(StringValue::<T>::Raw(text))
679 }
680 }
681 }
682 EMLParsingMode::Loose => Ok(StringValue::Raw(text)),
683 }
684 }
685
686 pub fn string_value<T: StringValueData>(&mut self) -> Result<StringValue<T>, EMLError> {
695 let text = self.text_without_children()?;
696 self.string_value_from_text(text, None, self.inner_span())
697 }
698
699 pub fn string_value_opt<T: StringValueData>(
709 &mut self,
710 ) -> Result<Option<StringValue<T>>, EMLError> {
711 self.text_without_children_opt()?
712 .map(|v| self.string_value_from_text(v, None, self.inner_span()))
713 .transpose()
714 }
715
716 pub fn string_value_attr_opt<'a, 'b, T: StringValueData>(
722 &mut self,
723 attr_name: impl Into<QualifiedName<'a, 'b>>,
724 ) -> Result<Option<StringValue<T>>, EMLError> {
725 let attr_name = attr_name.into();
726 match self.attribute_value(attr_name.clone())? {
727 Some(value) => Ok(Some(self.string_value_from_text(
728 value.into(),
729 Some(attr_name),
730 self.span(),
731 )?)),
732 None => Ok(None),
733 }
734 }
735
736 pub fn string_value_attr<'a, 'b, T: StringValueData>(
742 &mut self,
743 attr_name: impl Into<QualifiedName<'a, 'b>>,
744 default_value: Option<&str>,
745 ) -> Result<StringValue<T>, EMLError> {
746 let attr_name = attr_name.into();
747 let value = self
748 .attribute_value(attr_name.clone())?
749 .or_else(|| default_value.map(Cow::Borrowed));
750 match value {
751 Some(value) => self.string_value_from_text(value.into(), Some(attr_name), self.span()),
752 None => {
753 Err(EMLErrorKind::MissingAttribute(attr_name.as_owned())).with_span(self.span())
754 }
755 }
756 }
757
758 fn namespace_name<'a>(
760 &self,
761 resolve_result: ResolveResult<'a>,
762 span: Span,
763 ) -> Result<Option<Cow<'a, str>>, EMLError> {
764 match resolve_result {
765 ResolveResult::Bound(namespace) => Ok(Some(
766 self.reader
767 .inner
768 .decoder()
769 .decode(namespace.into_inner())
770 .with_span(span)?,
771 )),
772 ResolveResult::Unbound => Ok(None),
773 ResolveResult::Unknown(scope) => Err(EMLErrorKind::UnknownNamespace(
774 self.reader
775 .inner
776 .decoder()
777 .decode(&scope)
778 .with_span(span)?
779 .into_owned(),
780 ))
781 .with_span(span),
782 }
783 }
784
785 fn is_resolved_name<'a, 'b, 'c>(
788 &self,
789 name: QName<'a>,
790 span: Span,
791 expected_name: impl Into<QualifiedName<'b, 'c>>,
792 is_attribute: bool,
793 ) -> Result<bool, EMLError> {
794 let expected_name = expected_name.into();
795 let resolved_name = self.get_resolved_name(name, span, is_attribute)?;
796 let matches_local = resolved_name.local_name.as_ref() == expected_name.local_name.as_ref();
797 let matches_namespace = match (
798 expected_name.namespace.as_deref(),
799 resolved_name.namespace.as_deref(),
800 ) {
801 (Some(expected), Some(found)) => expected == found,
802 (None, None) => true,
803 _ => false,
804 };
805 Ok(matches_local && matches_namespace)
806 }
807
808 fn get_resolved_name<'a>(
812 &'a self,
813 name: QName<'a>,
814 span: Span,
815 is_attribute: bool,
816 ) -> Result<QualifiedName<'a, 'a>, EMLError> {
817 let (resolved, local_name) = if is_attribute {
818 self.reader.inner.resolver().resolve_attribute(name)
819 } else {
820 self.reader.inner.resolver().resolve_element(name)
821 };
822 let namespace = self.namespace_name(resolved, span)?;
823 let local_name = self
824 .reader
825 .inner
826 .decoder()
827 .decode(local_name.into_inner())
828 .with_span(span)?;
829
830 Ok(QualifiedName::new(local_name, namespace))
831 }
832
833 fn next(&mut self) -> Result<Option<(Event<'input>, Span)>, EMLError> {
836 if self.found_matching_end {
837 return Ok(None);
838 }
839
840 let (evt, span) = self.reader.next()?;
841 self.last_span = span;
842 if matches!(evt, Event::Start(_)) {
843 self.depth += 1;
844 }
845
846 if matches!(evt, Event::End(_)) {
847 self.depth -= 1;
848 }
849
850 if matches!(evt, Event::Eof) {
851 return Err(EMLErrorKind::UnexpectedEof).with_span(span);
852 }
853
854 if self.depth == 0
855 && let Event::End(e) = &evt
856 {
857 if e.name() == self.start.name() {
858 self.found_matching_end = true;
859 return Ok(None);
860 } else {
861 return Err(EMLErrorKind::UnexpectedEndElement).with_span(span);
862 }
863 }
864
865 Ok(Some((evt, span)))
866 }
867
868 pub fn is_empty(&self) -> bool {
870 self.is_empty
871 }
872}
873
874impl Drop for EMLElementReader<'_, '_> {
875 fn drop(&mut self) {
876 let _ = self.skip();
878 }
879}
880
881#[derive(Debug, Clone, PartialEq, Eq, Error)]
883#[error("invalid boolean value: {0}")]
884pub struct InvalidBooleanValue(String);
885
886impl From<InvalidBooleanValue> for EMLError {
887 fn from(err: InvalidBooleanValue) -> Self {
888 EMLError::value_conversion(err)
889 }
890}
891
892macro_rules! collect_struct {
893 ( $root:expr, $ty:ident { $($rest:tt)* }) => {
910 collect_struct!(@expand [$root] [$ty] [] $($rest)* )
911 };
912
913 ( @expand [$root:expr] [$ty:ident] [$($items:tt ; )*]
915 $field:ident: $namespaced_name:expr $(; $version_range:expr)? => |$var:ident| $map:expr ,
916 $($tail:tt)*
917 ) => {
918 collect_struct!(@expand [$root] [$ty] [
919 $($items ; )*
920 (@field [$field] [$namespaced_name] [$($version_range)?] [$var] [$map]) ;
921 ] $($tail)*)
922 };
923
924 ( @expand [$root:expr] [$ty:ident] [$($items:tt ; )*]
926 $field:ident as None: $namespaced_name:expr $(; $version_range:expr)? => |$var:ident| $map:expr ,
927 $($tail:tt)*
928 ) => {
929 collect_struct!(@expand [$root] [$ty] [
930 $($items ; )*
931 (@parse_only [$field] [$namespaced_name] [$($version_range)?] [$var] [$map]) ;
932 ] $($tail)*)
933 };
934
935 ( @expand [$root:expr] [$ty:ident] [$($items:tt ; )*]
937 $field:ident as Default($default:expr): $namespaced_name:expr $(; $version_range:expr)? => |$var:ident| $map:expr ,
938 $($tail:tt)*
939 ) => {
940 collect_struct!(@expand [$root] [$ty] [
941 $($items ; )*
942 (@default [$field] [$namespaced_name] [$($version_range)?] [$var] [$map] [$default]) ;
943 ] $($tail)*)
944 };
945
946 ( @expand [$root:expr] [$ty:ident] [$($items:tt ; )*]
948 $field:ident as Option: $namespaced_name:expr $(; $version_range:expr)? => |$var:ident| $map:expr ,
949 $($tail:tt)*
950 ) => {
951 collect_struct!(@expand [$root] [$ty] [
952 $($items ; )*
953 (@optional [$field] [$namespaced_name] [$($version_range)?] [$var] [$map]) ;
954 ] $($tail)*)
955 };
956
957 ( @expand [$root:expr] [$ty:ident] [$($items:tt ; )*]
959 $field:ident as BTreeMap: $namespaced_name:expr $(; $version_range:expr)? => |$var:ident| $map:expr,
960 $($tail:tt)*
961 ) => {
962 collect_struct!(@expand [$root] [$ty] [
963 $($items ; )*
964 (@btreemap [$field] [$namespaced_name] [$($version_range)?] [$var] [$map]) ;
965 ] $($tail)*)
966 };
967
968 ( @expand [$root:expr] [$ty:ident] [$($items:tt ; )*]
970 $field:ident as Vec: $namespaced_name:expr $(; $version_range:expr)? => |$var:ident| $map:expr ,
971 $($tail:tt)*
972 ) => {
973 collect_struct!(@expand [$root] [$ty] [
974 $($items ; )*
975 (@vec [$field] [$namespaced_name] [$($version_range)?] [$var] [$map]) ;
976 ] $($tail)*)
977 };
978
979 ( @expand [$root:expr] [$ty:ident] [$($items:tt ; )*]
981 $field:ident: $value:expr ,
982 $($tail:tt)*
983 ) => {
984 collect_struct!(@expand [$root] [$ty] [
985 $($items ; )*
986 (@direct [$field] [$value]) ;
987 ] $($tail)*)
988 };
989
990 ( @expand [$root:expr] [$ty:ident] [$($items:tt ; )*] ) => {
992 collect_struct!(@emit [$root] [$ty] [$($items ; )*])
993 };
994
995 ( @emit [$root:expr] [$ty:ident] [$($items:tt ; )*] ) => {{
997 $( collect_struct!(@decl $items); )*
998
999 let elem_name = $root.name()?.as_owned();
1000 while let Some(mut next_child) = $root.next_child()? {
1001 let name = next_child.name()?.as_owned().into_inner();
1002 #[allow(unused_mut)]
1003 let mut handled = false;
1004
1005 $( collect_struct!(@matcher next_child, name, handled, $items); )*
1006
1007 if !handled {
1008 next_child.push_err($crate::error::EMLError::Positioned {
1009 kind: $crate::error::EMLErrorKind::UnexpectedElement(name.as_owned(), elem_name.clone()),
1010 span: next_child.span(),
1011 });
1012 next_child.skip()?;
1014 }
1015 }
1016
1017 $( collect_struct!(@process $root, $items); )*
1018
1019 collect_struct!(@assign $root, $ty, [], $($items ; )*)
1020 }};
1021
1022 (@decl (@parse_only [$field:ident] [$namespaced_name:expr] [$($version_range:expr)?] [$var:ident] [$map:expr])) => {
1024 let mut $field: Option<_> = None;
1025 };
1026 (@decl (@direct [$field:ident] [$value:expr])) => {};
1027 (@decl (@optional [$field:ident] [$namespaced_name:expr] [$($version_range:expr)?] [$var:ident] [$map:expr])) => {
1028 let mut $field: Option<_> = None;
1029 };
1030 (@decl (@default [$field:ident] [$namespaced_name:expr] [$($version_range:expr)?] [$var:ident] [$map:expr] [$default:expr])) => {
1031 let mut $field: Option<_> = None;
1032 };
1033 (@decl (@btreemap [$field:ident] [$namespaced_name:expr] [$($version_range:expr)?] [$var:ident] [$map:expr])) => {
1034 let mut $field: std::collections::BTreeMap<_, _> = std::collections::BTreeMap::new();
1035 };
1036 (@decl (@field [$field:ident] [$namespaced_name:expr] [$($version_range:expr)?] [$var:ident] [$map:expr])) => {
1037 let mut $field: Option<_> = None;
1038 };
1039 (@decl (@vec [$field:ident] [$namespaced_name:expr] [$($version_range:expr)?] [$var:ident] [$map:expr])) => {
1040 let mut $field: Vec<_> = Vec::new();
1041 };
1042
1043 (@matcher $next_child:ident, $name:ident, $handled:ident, (@direct [$field:ident] [$value:expr])) => {};
1045 (@matcher $next_child:ident, $name:ident, $handled:ident, (@optional [$field:ident] [$namespaced_name:expr] [$($version_range:expr)?] [$var:ident] [$map:expr])) => {
1046 collect_struct!(@matcher $next_child, $name, $handled, (@field [$field] [$namespaced_name] [$($version_range)?] [$var] [$map]));
1047 };
1048 (@matcher $next_child:ident, $name:ident, $handled:ident, (@default [$field:ident] [$namespaced_name:expr] [$($version_range:expr)?] [$var:ident] [$map:expr] [$default:expr])) => {
1049 collect_struct!(@matcher $next_child, $name, $handled, (@field [$field] [$namespaced_name] [$($version_range)?] [$var] [$map]));
1050 };
1051 (@matcher $next_child:ident, $name:ident, $handled:ident, (@parse_only [$field:ident] [$namespaced_name:expr] [$($version_range:expr)?] [$var:ident] [$map:expr])) => {
1052 collect_struct!(@matcher $next_child, $name, $handled, (@field [$field] [$namespaced_name] [$($version_range)?] [$var] [$map]));
1053 };
1054 (@matcher $next_child:ident, $name:ident, $handled:ident, (@field [$field:ident] [$namespaced_name:expr] [$($version_range:expr)?] [$var:ident] [$map:expr])) => {
1055 if !$handled &&
1056 &$name == $crate::io::IntoQualifiedNameCow::into_qname_cow($namespaced_name).as_ref()
1057 {
1058 $(collect_struct!(@version_check $next_child, [$namespaced_name] [$version_range]);)?
1059
1060 let $var = &mut $next_child;
1061 $field = Some($map);
1062 $var.skip()?;
1063 $handled = true;
1064 }
1065 };
1066 (@matcher $next_child:ident, $name:ident, $handled:ident, (@vec [$field:ident] [$namespaced_name:expr] [$($version_range:expr)?] [$var:ident] [$map:expr])) => {
1067 if !$handled &&
1068 &$name == $crate::io::IntoQualifiedNameCow::into_qname_cow($namespaced_name).as_ref()
1069 {
1070 $(collect_struct!(@version_check $next_child, [$namespaced_name] [$version_range]);)?
1071
1072 let $var = &mut $next_child;
1073 $field.push($map);
1074 $var.skip()?;
1075 $handled = true;
1076 }
1077 };
1078 (@matcher $next_child:ident, $name:ident, $handled:ident, (@btreemap [$field:ident] [$namespaced_name:expr] [$($version_range:expr)?] [$var:ident] [$map:expr])) => {
1079 if !$handled &&
1080 &$name == $crate::io::IntoQualifiedNameCow::into_qname_cow($namespaced_name).as_ref()
1081 {
1082 $(collect_struct!(@version_check $next_child, [$namespaced_name] [$version_range]);)?
1083
1084 let $var = &mut $next_child;
1085 let (k, v) = $map;
1086 $field.insert(k, v);
1087 $var.skip()?;
1088 $handled = true;
1089 }
1090 };
1091
1092 (@version_check $next_child:expr, [$namespaced_name:expr] [$version_range:expr]) => {
1093 if !$version_range.contains($next_child.document_version()) {
1094 return $crate::error::EMLResultExt::with_span(
1095 Err($crate::error::EMLErrorKind::ElementNotSupportedInVersion(
1096 $crate::io::IntoQualifiedNameCow::into_qname_cow($namespaced_name).as_owned(),
1097 $next_child.document_version(),
1098 )),
1099 $next_child.span()
1100 );
1101 }
1102 };
1103
1104 (@process $root:expr, (@parse_only [$field:ident] [$namespaced_name:expr] [$($version_range:expr)?] [$var:ident] [$map:expr])) => {
1106 $crate::error::EMLResultExt::with_span(
1107 $field.ok_or_else(|| $crate::error::EMLErrorKind::MissingElement(
1108 $crate::io::QualifiedName::from($namespaced_name).as_owned()
1109 )),
1110 $root.last_span()
1111 )?;
1112 };
1113 (@process $root:expr, (@direct [$field:ident] [$value:expr])) => {};
1114 (@process $root:expr, (@optional [$field:ident] [$namespaced_name:expr] [$($version_range:expr)?] [$var:ident] [$map:expr])) => {};
1115 (@process $root:expr, (@default [$field:ident] [$namespaced_name:expr] [$($version_range:expr)?] [$var:ident] [$map:expr] [$default:expr])) => {};
1116 (@process $root:expr, (@btreemap [$field:ident] [$namespaced_name:expr] [$($version_range:expr)?] [$var:ident] [$map:expr])) => {};
1117 (@process $root:expr, (@field [$field:ident] [$namespaced_name:expr] [$($version_range:expr)?] [$var:ident] [$map:expr])) => {};
1118 (@process $root:expr, (@vec [$field:ident] [$namespaced_name:expr] [$($version_range:expr)?] [$var:ident] [$map:expr])) => {};
1119
1120 (@build_struct $root:expr, $ty:ident, $($items:tt ; )* ) => {
1122 $ty {
1123 collect_struct!(@assign $root, $($items ; )*)
1124 }
1125 };
1126
1127 (@assign $root:expr, $ty:ident, [$($out:tt)*], (@direct [$field:ident] [$value:expr]) ; $($tail:tt)*) => {
1129 collect_struct!(@assign $root, $ty, [
1130 $($out)*
1131 $field: $value,
1132 ], $($tail)*)
1133 };
1134 (@assign $root:expr, $ty:ident, [$($out:tt)*], (@parse_only [$field:ident] [$namespaced_name:expr] [$($version_range:expr)?] [$var:ident] [$map:expr]) ; $($tail:tt)*) => {
1135 collect_struct!(@assign $root, $ty, [
1136 $($out)*
1137 ], $($tail)*)
1138 };
1139 (@assign $root:expr, $ty:ident, [$($out:tt)*], (@optional [$field:ident] [$namespaced_name:expr] [$($version_range:expr)?] [$var:ident] [$map:expr]) ; $($tail:tt)*) => {
1140 collect_struct!(@assign $root, $ty, [
1141 $($out)*
1142 $field: $field,
1143 ], $($tail)*)
1144 };
1145 (@assign $root:expr, $ty:ident, [$($out:tt)*], (@default [$field:ident] [$namespaced_name:expr] [$($version_range:expr)?] [$var:ident] [$map:expr] [$default:expr]) ; $($tail:tt)*) => {
1146 collect_struct!(@assign $root, $ty, [
1147 $($out)*
1148 $field: match $field {
1149 Some(v) => v,
1150 None => $default,
1151 },
1152 ], $($tail)*)
1153 };
1154 (@assign $root:expr, $ty:ident, [$($out:tt)*], (@vec [$field:ident] [$namespaced_name:expr] [$($version_range:expr)?] [$var:ident] [$map:expr]) ; $($tail:tt)*) => {
1155 collect_struct!(@assign $root, $ty, [
1156 $($out)*
1157 $field: $field,
1158 ], $($tail)*)
1159 };
1160 (@assign $root:expr, $ty:ident, [$($out:tt)*], (@btreemap [$field:ident] [$namespaced_name:expr] [$($version_range:expr)?] [$var:ident] [$map:expr]) ; $($tail:tt)*) => {
1161 collect_struct!(@assign $root, $ty, [
1162 $($out)*
1163 $field: $field,
1164 ], $($tail)*)
1165 };
1166 (@assign $root:expr, $ty:ident, [$($out:tt)*], (@field [$field:ident] [$namespaced_name:expr] [$($version_range:expr)?] [$var:ident] [$map:expr]) ; $($tail:tt)*) => {
1167 collect_struct!(@assign $root, $ty, [
1168 $($out)*
1169 $field: $crate::error::EMLResultExt::with_span(
1170 $field.ok_or_else(|| $crate::error::EMLErrorKind::MissingElement(
1171 $crate::io::QualifiedName::from($namespaced_name).as_owned()
1172 )),
1173 $root.last_span()
1174 )?,
1175 ], $($tail)*)
1176 };
1177 (@assign $root:expr, $ty:ident, [$($out:tt)*], ) => {
1178 $ty {
1179 $($out)*
1180 }
1181 };
1182}
1183pub(crate) use collect_struct;
1184
1185#[cfg(test)]
1186mod tests {
1187 use super::*;
1188
1189 #[test]
1190 fn test_unknown_namespace() {
1191 let document = r#"<eml:UnknownElement />"#;
1192 let mut reader = EMLReader::init_from_str_with_version(
1193 document,
1194 EMLParsingMode::Strict,
1195 EMLVersion::V1_2_2,
1196 );
1197 let root = reader.next_element().unwrap();
1198 let error = root.name().unwrap_err();
1199 assert!(matches!(
1200 error.kind(),
1201 EMLErrorKind::UnknownNamespace(ns) if ns == "eml"
1202 ));
1203 }
1204
1205 #[test]
1208 fn test_input_without_element_returns_unexpected_eof() {
1209 for document in [
1210 "",
1211 "5738 d520 a7f2 89b8 8875 ebfe cfc8 6012 d7b6 f65f 3271 d0e1 180b ccdd 8134 cd5d\n",
1212 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
1213 ] {
1214 let mut reader = EMLReader::init_from_str_with_version(
1215 document,
1216 EMLParsingMode::Strict,
1217 EMLVersion::V1_2_2,
1218 );
1219 let Err(error) = reader.next_element() else {
1220 panic!("expected an error for input {document:?}");
1221 };
1222 assert!(matches!(error.kind(), EMLErrorKind::UnexpectedEof));
1223 }
1224 }
1225}