1use std::fmt;
8
9use crate::ast::IXamlLineInfo;
10
11#[derive(Debug, Clone)]
13pub struct XamlParseException {
14 pub title: String,
16 pub line_number: i32,
17 pub line_position: i32,
18 pub document: Option<String>,
19 pub inner_exception: Option<Box<XamlError>>,
20 pub derived_type_name: Option<&'static str>,
26}
27
28impl XamlParseException {
29 pub fn new(
30 message: impl Into<String>,
31 line: i32,
32 position: i32,
33 inner: Option<XamlError>,
34 ) -> Self {
35 Self {
36 title: message.into(),
37 line_number: line,
38 line_position: position,
39 document: None,
40 inner_exception: inner.map(Box::new),
41 derived_type_name: None,
42 }
43 }
44
45 pub fn message(&self) -> String {
47 if self.line_number == 0 && self.line_position == 0 {
48 self.title.clone()
49 } else {
50 format!(
51 "{} Line {}, position {}.",
52 self.title, self.line_number, self.line_position
53 )
54 }
55 }
56}
57
58#[derive(Debug, Clone)]
60pub struct XamlTypeSystemException {
61 pub message: String,
62 pub inner_exception: Option<Box<XamlError>>,
63}
64
65#[derive(Debug, Clone)]
68pub struct XamlInternalException {
69 pub type_name: &'static str,
71 pub message: String,
72}
73
74#[derive(Debug, Clone)]
75pub enum XamlError {
76 Xml(XamlParseException),
78 Parse(XamlParseException),
80 Transform(XamlParseException),
82 Load(XamlParseException),
84 TypeSystem(XamlTypeSystemException),
86 Internal(XamlInternalException),
88 Aggregate(Vec<XamlError>),
90}
91
92pub type XamlResult<T> = Result<T, XamlError>;
93
94fn li(line_info: Option<&dyn IXamlLineInfo>) -> (i32, i32) {
95 line_info
96 .map(|l| (l.line(), l.position()))
97 .unwrap_or((0, 0))
98}
99
100impl XamlError {
101 pub fn xml_exception(message: impl Into<String>, line: i32, position: i32) -> Self {
102 XamlError::Xml(XamlParseException::new(message, line, position, None))
103 }
104
105 pub fn parse_exception_at(message: impl Into<String>, line: i32, position: i32) -> Self {
106 XamlError::Parse(XamlParseException::new(message, line, position, None))
107 }
108
109 pub fn parse_exception(
110 message: impl Into<String>,
111 line_info: Option<&dyn IXamlLineInfo>,
112 ) -> Self {
113 let (l, p) = li(line_info);
114 XamlError::Parse(XamlParseException::new(message, l, p, None))
115 }
116
117 pub fn parse_exception_with_inner(
118 message: impl Into<String>,
119 line_info: Option<&dyn IXamlLineInfo>,
120 inner: XamlError,
121 ) -> Self {
122 let (l, p) = li(line_info);
123 XamlError::Parse(XamlParseException::new(message, l, p, Some(inner)))
124 }
125
126 pub fn transform_exception(
127 message: impl Into<String>,
128 line_info: Option<&dyn IXamlLineInfo>,
129 ) -> Self {
130 let (l, p) = li(line_info);
131 XamlError::Transform(XamlParseException::new(message, l, p, None))
132 }
133
134 pub fn transform_exception_with_inner(
135 message: impl Into<String>,
136 line_info: Option<&dyn IXamlLineInfo>,
137 inner: XamlError,
138 ) -> Self {
139 let (l, p) = li(line_info);
140 XamlError::Transform(XamlParseException::new(message, l, p, Some(inner)))
141 }
142
143 pub fn load_exception(
144 message: impl Into<String>,
145 line_info: Option<&dyn IXamlLineInfo>,
146 ) -> Self {
147 let (l, p) = li(line_info);
148 XamlError::Load(XamlParseException::new(message, l, p, None))
149 }
150
151 pub fn type_system_exception(message: impl Into<String>) -> Self {
152 XamlError::TypeSystem(XamlTypeSystemException {
153 message: message.into(),
154 inner_exception: None,
155 })
156 }
157
158 pub fn internal(type_name: &'static str, message: impl Into<String>) -> Self {
159 XamlError::Internal(XamlInternalException {
160 type_name,
161 message: message.into(),
162 })
163 }
164
165 pub fn invalid_operation(message: impl Into<String>) -> Self {
166 Self::internal("InvalidOperationException", message)
167 }
168
169 pub fn argument(message: impl Into<String>) -> Self {
170 Self::internal("ArgumentException", message)
171 }
172
173 pub fn invalid_cast(message: impl Into<String>) -> Self {
174 Self::internal("InvalidCastException", message)
175 }
176
177 pub fn not_supported(message: impl Into<String>) -> Self {
178 Self::internal("NotSupportedException", message)
179 }
180
181 pub fn is_xml_exception(&self) -> bool {
183 matches!(
184 self,
185 XamlError::Xml(_) | XamlError::Parse(_) | XamlError::Transform(_) | XamlError::Load(_)
186 )
187 }
188
189 pub fn is_xaml_parse_exception(&self) -> bool {
191 matches!(
192 self,
193 XamlError::Parse(_) | XamlError::Transform(_) | XamlError::Load(_)
194 )
195 }
196
197 pub fn is_type_system_exception(&self) -> bool {
198 matches!(self, XamlError::TypeSystem(_))
199 }
200
201 pub fn as_xml_exception(&self) -> Option<&XamlParseException> {
203 match self {
204 XamlError::Xml(e)
205 | XamlError::Parse(e)
206 | XamlError::Transform(e)
207 | XamlError::Load(e) => Some(e),
208 _ => None,
209 }
210 }
211
212 fn as_xml_exception_mut(&mut self) -> Option<&mut XamlParseException> {
213 match self {
214 XamlError::Xml(e)
215 | XamlError::Parse(e)
216 | XamlError::Transform(e)
217 | XamlError::Load(e) => Some(e),
218 _ => None,
219 }
220 }
221
222 pub fn with_derived_type_name(mut self, type_name: &'static str) -> Self {
226 if let Some(e) = self.as_xml_exception_mut() {
227 e.derived_type_name = Some(type_name);
228 }
229 self
230 }
231
232 pub fn derived_type_name(&self) -> Option<&'static str> {
234 self.as_xml_exception().and_then(|e| e.derived_type_name)
235 }
236
237 pub fn is_derived_type(&self, type_name: &str) -> bool {
239 self.derived_type_name() == Some(type_name)
240 }
241
242 pub fn type_name(&self) -> &'static str {
244 if let Some(derived) = self.derived_type_name() {
245 return derived;
246 }
247 match self {
248 XamlError::Xml(_) => "XmlException",
249 XamlError::Parse(_) => "XamlParseException",
250 XamlError::Transform(_) => "XamlTransformException",
251 XamlError::Load(_) => "XamlLoadException",
252 XamlError::TypeSystem(_) => "XamlTypeSystemException",
253 XamlError::Internal(e) => e.type_name,
254 XamlError::Aggregate(_) => "AggregateException",
255 }
256 }
257
258 pub fn message(&self) -> String {
260 match self {
261 XamlError::Xml(e)
262 | XamlError::Parse(e)
263 | XamlError::Transform(e)
264 | XamlError::Load(e) => e.message(),
265 XamlError::TypeSystem(e) => e.message.clone(),
266 XamlError::Internal(e) => e.message.clone(),
267 XamlError::Aggregate(errors) => {
268 let inner: Vec<String> = errors
269 .iter()
270 .map(|e| format!("({})", e.message()))
271 .collect();
272 format!("One or more errors occurred. {}", inner.join(" "))
273 }
274 }
275 }
276
277 pub fn line_number(&self) -> Option<i32> {
278 self.as_xml_exception().map(|e| e.line_number)
279 }
280
281 pub fn line_position(&self) -> Option<i32> {
282 self.as_xml_exception().map(|e| e.line_position)
283 }
284
285 pub fn document(&self) -> Option<&str> {
287 match self {
288 XamlError::Parse(e) | XamlError::Transform(e) | XamlError::Load(e) => {
289 e.document.as_deref()
290 }
291 _ => None,
292 }
293 }
294
295 pub fn with_document(mut self, document: Option<String>) -> Self {
297 if let Some(e) = self.as_xml_exception_mut() {
298 e.document = document;
299 }
300 self
301 }
302
303 pub fn inner_exception(&self) -> Option<&XamlError> {
304 match self {
305 XamlError::Xml(e)
306 | XamlError::Parse(e)
307 | XamlError::Transform(e)
308 | XamlError::Load(e) => e.inner_exception.as_deref(),
309 XamlError::TypeSystem(e) => e.inner_exception.as_deref(),
310 _ => None,
311 }
312 }
313}
314
315impl fmt::Display for XamlError {
316 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
317 write!(f, "{}: {}", self.type_name(), self.message())
318 }
319}
320
321impl std::error::Error for XamlError {}