1use crate::registry::{
4 http_headers, http_status, render_debug, render_graphql, render_html, render_json,
5 render_jsonrpc, render_text,
6};
7
8fn fallback_json(message: impl std::fmt::Display) -> serde_json::Value {
10 serde_json::json!({
11 "error": "UNKNOWN_ERROR",
12 "message": message.to_string()
13 })
14}
15
16fn fallback_html(message: impl std::fmt::Display) -> String {
18 format!(
19 "<div class=\"error\">\n<h3 class=\"error-code\">UNKNOWN_ERROR</h3>\n<p class=\"error-message\">{message}</p>\n</div>"
20 )
21}
22
23fn fallback_graphql(message: impl std::fmt::Display) -> serde_json::Value {
25 serde_json::json!({
26 "message": message.to_string(),
27 "extensions": {
28 "code": "UNKNOWN_ERROR"
29 }
30 })
31}
32
33fn fallback_text(message: impl std::fmt::Display) -> String {
35 format!("[UNKNOWN_ERROR] {message}")
36}
37
38fn fallback_jsonrpc(message: impl std::fmt::Display) -> serde_json::Value {
40 serde_json::json!({
41 "code": crate::private::DEFAULT_JSONRPC_CODE,
42 "message": message.to_string(),
43 "data": {
44 "diagnostic_code": "UNKNOWN_ERROR"
45 }
46 })
47}
48
49pub trait ErrorExt {
66 fn to_json(&self) -> Result<serde_json::Value, serde_json::Error>;
72
73 fn to_html(&self) -> String;
75
76 fn to_graphql(&self) -> Result<serde_json::Value, serde_json::Error>;
82
83 fn to_text(&self) -> String;
85
86 fn to_debug(&self) -> String;
88
89 fn to_jsonrpc(&self) -> Result<serde_json::Value, serde_json::Error>;
95
96 fn http_status(&self) -> http::StatusCode;
98
99 fn http_headers(&self) -> Vec<(http::HeaderName, http::HeaderValue)>;
101}
102
103impl<E: std::error::Error + 'static> ErrorExt for E {
105 fn to_json(&self) -> Result<serde_json::Value, serde_json::Error> {
106 render_json(self).unwrap_or_else(|| Ok(fallback_json(self)))
107 }
108
109 fn to_html(&self) -> String {
110 render_html(self).unwrap_or_else(|| fallback_html(self))
111 }
112
113 fn to_graphql(&self) -> Result<serde_json::Value, serde_json::Error> {
114 render_graphql(self).unwrap_or_else(|| Ok(fallback_graphql(self)))
115 }
116
117 fn to_text(&self) -> String {
118 render_text(self).unwrap_or_else(|| fallback_text(self))
119 }
120
121 fn to_debug(&self) -> String {
122 render_debug(self).unwrap_or_else(|| format!("{self:?}"))
123 }
124
125 fn to_jsonrpc(&self) -> Result<serde_json::Value, serde_json::Error> {
126 render_jsonrpc(self).unwrap_or_else(|| Ok(fallback_jsonrpc(self)))
127 }
128
129 fn http_status(&self) -> http::StatusCode {
130 http_status(self).unwrap_or(http::StatusCode::INTERNAL_SERVER_ERROR)
131 }
132
133 fn http_headers(&self) -> Vec<(http::HeaderName, http::HeaderValue)> {
134 http_headers(self).unwrap_or_default()
135 }
136}
137
138pub trait HeapErrorExt {
168 fn to_json(&self) -> Result<serde_json::Value, serde_json::Error>;
174
175 fn to_html(&self) -> String;
177
178 fn to_graphql(&self) -> Result<serde_json::Value, serde_json::Error>;
184
185 fn to_text(&self) -> String;
187
188 fn to_debug(&self) -> String;
190
191 fn to_jsonrpc(&self) -> Result<serde_json::Value, serde_json::Error>;
197
198 fn http_status(&self) -> http::StatusCode;
200
201 fn http_headers(&self) -> Vec<(http::HeaderName, http::HeaderValue)>;
203}
204
205impl HeapErrorExt for Box<dyn std::error::Error + Send + Sync> {
211 fn to_json(&self) -> Result<serde_json::Value, serde_json::Error> {
212 let error_ref: &dyn std::error::Error = self.as_ref();
213
214 if let Some(nested_arc) =
216 error_ref.downcast_ref::<std::sync::Arc<dyn std::error::Error + Send + Sync>>()
217 {
218 return HeapErrorExt::to_json(nested_arc);
219 }
220
221 render_json(error_ref).unwrap_or_else(|| Ok(fallback_json(error_ref)))
222 }
223
224 fn to_html(&self) -> String {
225 let error_ref: &dyn std::error::Error = self.as_ref();
226
227 if let Some(nested_arc) =
229 error_ref.downcast_ref::<std::sync::Arc<dyn std::error::Error + Send + Sync>>()
230 {
231 return HeapErrorExt::to_html(nested_arc);
232 }
233
234 render_html(error_ref).unwrap_or_else(|| fallback_html(error_ref))
235 }
236
237 fn to_graphql(&self) -> Result<serde_json::Value, serde_json::Error> {
238 let error_ref: &dyn std::error::Error = self.as_ref();
239
240 if let Some(nested_arc) =
242 error_ref.downcast_ref::<std::sync::Arc<dyn std::error::Error + Send + Sync>>()
243 {
244 return HeapErrorExt::to_graphql(nested_arc);
245 }
246
247 render_graphql(error_ref).unwrap_or_else(|| Ok(fallback_graphql(error_ref)))
248 }
249
250 fn to_text(&self) -> String {
251 let error_ref: &dyn std::error::Error = self.as_ref();
252
253 if let Some(nested_arc) =
255 error_ref.downcast_ref::<std::sync::Arc<dyn std::error::Error + Send + Sync>>()
256 {
257 return HeapErrorExt::to_text(nested_arc);
258 }
259
260 render_text(error_ref).unwrap_or_else(|| fallback_text(error_ref))
261 }
262
263 fn to_debug(&self) -> String {
264 let error_ref: &dyn std::error::Error = self.as_ref();
265
266 if let Some(nested_arc) =
268 error_ref.downcast_ref::<std::sync::Arc<dyn std::error::Error + Send + Sync>>()
269 {
270 return HeapErrorExt::to_debug(nested_arc);
271 }
272
273 render_debug(error_ref).unwrap_or_else(|| format!("{error_ref:?}"))
274 }
275
276 fn to_jsonrpc(&self) -> Result<serde_json::Value, serde_json::Error> {
277 let error_ref: &dyn std::error::Error = self.as_ref();
278
279 if let Some(nested_arc) =
281 error_ref.downcast_ref::<std::sync::Arc<dyn std::error::Error + Send + Sync>>()
282 {
283 return HeapErrorExt::to_jsonrpc(nested_arc);
284 }
285
286 render_jsonrpc(error_ref).unwrap_or_else(|| Ok(fallback_jsonrpc(error_ref)))
287 }
288
289 fn http_status(&self) -> http::StatusCode {
290 let error_ref: &dyn std::error::Error = self.as_ref();
291
292 if let Some(nested_arc) =
294 error_ref.downcast_ref::<std::sync::Arc<dyn std::error::Error + Send + Sync>>()
295 {
296 return HeapErrorExt::http_status(nested_arc);
297 }
298
299 http_status(error_ref).unwrap_or(http::StatusCode::INTERNAL_SERVER_ERROR)
300 }
301
302 fn http_headers(&self) -> Vec<(http::HeaderName, http::HeaderValue)> {
303 let error_ref: &dyn std::error::Error = self.as_ref();
304
305 if let Some(nested_arc) =
307 error_ref.downcast_ref::<std::sync::Arc<dyn std::error::Error + Send + Sync>>()
308 {
309 return HeapErrorExt::http_headers(nested_arc);
310 }
311
312 http_headers(error_ref).unwrap_or_default()
313 }
314}
315
316impl HeapErrorExt for std::sync::Arc<dyn std::error::Error + Send + Sync> {
322 fn to_json(&self) -> Result<serde_json::Value, serde_json::Error> {
323 let error_ref: &dyn std::error::Error = self.as_ref();
324 render_json(error_ref).unwrap_or_else(|| Ok(fallback_json(error_ref)))
325 }
326
327 fn to_html(&self) -> String {
328 let error_ref: &dyn std::error::Error = self.as_ref();
329 render_html(error_ref).unwrap_or_else(|| fallback_html(error_ref))
330 }
331
332 fn to_graphql(&self) -> Result<serde_json::Value, serde_json::Error> {
333 let error_ref: &dyn std::error::Error = self.as_ref();
334 render_graphql(error_ref).unwrap_or_else(|| Ok(fallback_graphql(error_ref)))
335 }
336
337 fn to_text(&self) -> String {
338 let error_ref: &dyn std::error::Error = self.as_ref();
339 render_text(error_ref).unwrap_or_else(|| fallback_text(error_ref))
340 }
341
342 fn to_debug(&self) -> String {
343 let error_ref: &dyn std::error::Error = self.as_ref();
344 render_debug(error_ref).unwrap_or_else(|| format!("{error_ref:?}"))
345 }
346
347 fn to_jsonrpc(&self) -> Result<serde_json::Value, serde_json::Error> {
348 let error_ref: &dyn std::error::Error = self.as_ref();
349 render_jsonrpc(error_ref).unwrap_or_else(|| Ok(fallback_jsonrpc(error_ref)))
350 }
351
352 fn http_status(&self) -> http::StatusCode {
353 let error_ref: &dyn std::error::Error = self.as_ref();
354 http_status(error_ref).unwrap_or(http::StatusCode::INTERNAL_SERVER_ERROR)
355 }
356
357 fn http_headers(&self) -> Vec<(http::HeaderName, http::HeaderValue)> {
358 let error_ref: &dyn std::error::Error = self.as_ref();
359 http_headers(error_ref).unwrap_or_default()
360 }
361}