1use std::{error::Error as StdError, fmt};
2
3use http::{header::CONTENT_TYPE, HeaderValue, StatusCode};
4use mime::TEXT_PLAIN_UTF_8;
5
6use crate::{location::Location, response::Response, response_error::ResponseError};
7
8pub type BoxError = Box<dyn StdError + Send + Sync>;
10
11#[derive(Debug)]
12pub struct Error {
13 response: Response,
14 inner: BoxError,
15 error_stack: Box<[Box<str>]>,
16}
17
18impl Error {
19 pub fn is<T>(&self) -> bool
20 where
21 T: StdError + 'static,
22 {
23 self.inner.is::<T>()
24 }
25
26 pub fn downcast_ref<T>(&self) -> Option<&T>
27 where
28 T: StdError + 'static,
29 {
30 self.inner.downcast_ref::<T>()
31 }
32
33 #[allow(clippy::type_complexity)]
34 pub fn downcast<T>(self) -> Result<(Response, T, Box<[Box<str>]>), Self>
35 where
36 T: StdError + 'static,
37 {
38 let Self {
39 response,
40 inner,
41 error_stack,
42 } = self;
43
44 match inner.downcast::<T>() {
45 Ok(err) => Ok((response, *err, error_stack)),
46 Err(err) => Err(Self {
47 response,
48 inner: err,
49 error_stack,
50 }),
51 }
52 }
53
54 pub fn status(&self) -> StatusCode {
55 self.response.status()
56 }
57
58 pub fn response(self) -> Response {
59 self.response
60 }
61
62 pub fn error_stack(&self) -> &[Box<str>] {
63 &self.error_stack
64 }
65}
66
67impl<T> From<T> for Error
68where
69 T: ResponseError,
70{
71 fn from(error: T) -> Self {
72 let response = error.as_response();
73 let error_stack = error.error_stack();
74
75 let inner = error.inner();
76
77 Self {
78 response,
79 inner,
80 error_stack,
81 }
82 }
83}
84
85impl From<(StatusCode, BoxError)> for Error {
86 #[track_caller]
87 fn from((status, mut error): (StatusCode, BoxError)) -> Self {
88 loop {
89 match error.downcast::<Error>() {
90 Ok(o) => {
91 if o.inner.is::<Error>() {
92 error = o.inner;
93 } else {
94 return *o;
95 }
96 }
97 Err(e) => {
98 error = e;
99 break;
100 }
101 }
102 }
103
104 let response = Response::builder()
105 .status(status)
106 .header(
107 CONTENT_TYPE,
108 HeaderValue::from_static(TEXT_PLAIN_UTF_8.as_ref()),
109 )
110 .body(error.to_string().into())
111 .unwrap();
112
113 let mut stack = Vec::new();
114 stack.push(format!("0: {}, at: {}", error, Location::caller()).into_boxed_str());
115
116 Self {
117 response,
118 inner: error,
119 error_stack: stack.into_boxed_slice(),
120 }
121 }
122}
123
124impl From<BoxError> for Error {
125 #[track_caller]
126 #[inline]
127 fn from(error: BoxError) -> Self {
128 Error::from((StatusCode::INTERNAL_SERVER_ERROR, error))
129 }
130}
131
132impl fmt::Display for Error {
133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 fmt::Display::fmt(&self.inner, f)
135 }
136}
137
138impl StdError for Error {
139 fn source(&self) -> Option<&(dyn StdError + 'static)> {
140 Some(&*self.inner)
141 }
142}
143
144impl AsRef<dyn StdError + Send + Sync> for Error {
145 fn as_ref(&self) -> &(dyn StdError + Send + Sync + 'static) {
146 &*self.inner
147 }
148}
149
150impl AsRef<dyn StdError> for Error {
151 fn as_ref(&self) -> &(dyn StdError + 'static) {
152 &*self.inner
153 }
154}