1use std::fmt;
4use thiserror::Error;
5
6#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct XmlPath(String);
9
10impl XmlPath {
11 pub(crate) fn new(path: String) -> Self {
12 Self(path)
13 }
14
15 #[must_use]
17 pub fn as_str(&self) -> &str {
18 &self.0
19 }
20}
21
22impl fmt::Display for XmlPath {
23 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
24 formatter.write_str(&self.0)
25 }
26}
27
28#[derive(Debug, Error)]
30#[non_exhaustive]
31pub enum XmlError {
32 #[error("malformed XML: {0}")]
34 Malformed(String),
35 #[error("unparseable entity id {0:?}")]
37 BadId(String),
38 #[error("invalid {kind} scalar {value:?}")]
40 InvalidScalar {
41 kind: String,
43 value: String,
45 },
46 #[error("unknown value kind {0:?}")]
48 UnknownKind(String),
49 #[error("`{name}` names slot {slot}, which is already set")]
51 DuplicateSlot {
52 name: String,
54 slot: usize,
56 },
57 #[error("`{name}` names slot {slot}, but slot {missing} is absent")]
59 MissingSlot {
60 name: String,
62 slot: usize,
64 missing: usize,
66 },
67 #[error("element `{element}` has namespace {found:?}; expected `{expected}`")]
69 Namespace {
70 element: String,
72 expected: &'static str,
74 found: Option<String>,
76 },
77 #[error("ifcXML profile expects schema `{expected}`, found {found:?}")]
79 Profile {
80 expected: &'static str,
82 found: Option<String>,
84 },
85 #[error("strict ifcXML requires root `ifcXML`, found {found:?}")]
87 Root {
88 found: Option<String>,
90 },
91 #[error("{path}: {source}")]
93 At {
94 path: XmlPath,
96 #[source]
98 source: Box<XmlError>,
99 },
100 #[error("write failed: {0}")]
102 Write(String),
103}
104
105impl XmlError {
106 #[must_use]
108 pub fn path(&self) -> Option<&XmlPath> {
109 match self {
110 Self::At { path, .. } => Some(path),
111 _ => None,
112 }
113 }
114
115 #[must_use]
117 pub fn root_cause(&self) -> &Self {
118 match self {
119 Self::At { source, .. } => source.root_cause(),
120 error => error,
121 }
122 }
123
124 pub(crate) fn at(self, path: String) -> Self {
125 match self {
126 Self::At { .. } => self,
127 source => Self::At {
128 path: XmlPath::new(path),
129 source: Box::new(source),
130 },
131 }
132 }
133}
134
135impl From<quick_xml::Error> for XmlError {
136 fn from(error: quick_xml::Error) -> Self {
137 Self::Malformed(error.to_string())
138 }
139}