1//! HTTP error types
23use std::error::Error as StdError;
4use std::fmt::{self, Debug, Display};
56use crate::StatusCode;
7use std::convert::TryInto;
89/// A specialized `Result` type for HTTP operations.
10///
11/// This type is broadly used across `http_types` for any operation which may
12/// produce an error.
13pub type Result<T> = std::result::Result<T, Error>;
1415/// The error type for HTTP operations.
16pub struct Error {
17 error: anyhow::Error,
18 status: crate::StatusCode,
19 type_name: Option<&'static str>,
20}
2122#[allow(unreachable_pub)]
23#[derive(Debug)]
24#[doc(hidden)]
25pub struct BacktracePlaceholder;
2627impl Display for BacktracePlaceholder {
28fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
29unreachable!()
30 }
31}
3233impl Error {
34/// Create a new error object from any error type.
35 ///
36 /// The error type must be threadsafe and 'static, so that the Error will be
37 /// as well. If the error type does not provide a backtrace, a backtrace will
38 /// be created here to ensure that a backtrace exists.
39pub fn new<S, E>(status: S, error: E) -> Self
40where
41S: TryInto<StatusCode>,
42 S::Error: Debug,
43 E: Into<anyhow::Error>,
44 {
45Self {
46 status: status
47 .try_into()
48 .expect("Could not convert into a valid `StatusCode`"),
49 error: error.into(),
50 type_name: Some(std::any::type_name::<E>()),
51 }
52 }
5354/// Create a new error object from static string.
55pub fn from_str<S, M>(status: S, msg: M) -> Self
56where
57S: TryInto<StatusCode>,
58 S::Error: Debug,
59 M: Display + Debug + Send + Sync + 'static,
60 {
61Self {
62 status: status
63 .try_into()
64 .expect("Could not convert into a valid `StatusCode`"),
65 error: anyhow::Error::msg(msg),
66 type_name: None,
67 }
68 }
69/// Create a new error from a message.
70pub(crate) fn new_adhoc<M>(message: M) -> Error
71where
72M: Display + Debug + Send + Sync + 'static,
73 {
74Self::from_str(StatusCode::InternalServerError, message)
75 }
7677/// Get the status code associated with this error.
78pub fn status(&self) -> StatusCode {
79self.status
80 }
8182/// Set the status code associated with this error.
83pub fn set_status<S>(&mut self, status: S)
84where
85S: TryInto<StatusCode>,
86 S::Error: Debug,
87 {
88self.status = status
89 .try_into()
90 .expect("Could not convert into a valid `StatusCode`");
91 }
9293/// Get the backtrace for this Error.
94 ///
95 /// Backtraces are only available on the nightly channel. Tracking issue:
96 /// [rust-lang/rust#53487][tracking].
97 ///
98 /// In order for the backtrace to be meaningful, the environment variable
99 /// `RUST_LIB_BACKTRACE=1` must be defined. Backtraces are somewhat
100 /// expensive to capture in Rust, so we don't necessarily want to be
101 /// capturing them all over the place all the time.
102 ///
103 /// [tracking]: https://github.com/rust-lang/rust/issues/53487
104 ///
105 /// Note: This function can be called whether or not backtraces
106 /// are enabled and available. It will return a `None` variant if
107 /// compiled on a toolchain that does not support backtraces, or
108 /// if executed without backtraces enabled with
109 /// `RUST_LIB_BACKTRACE=1`.
110#[cfg(backtrace)]
111pub fn backtrace(&self) -> Option<&std::backtrace::Backtrace> {
112let backtrace = self.error.backtrace();
113if let std::backtrace::BacktraceStatus::Captured = backtrace.status() {
114Some(backtrace)
115 } else {
116None
117}
118 }
119120#[cfg(not(backtrace))]
121 #[allow(missing_docs)]
122pub const fn backtrace(&self) -> Option<BacktracePlaceholder> {
123None
124}
125126/// Returns the inner [`anyhow::Error`]
127 /// Note: This will lose status code information
128pub fn into_inner(self) -> anyhow::Error {
129self.error
130 }
131132/// Attempt to downcast the error object to a concrete type.
133pub fn downcast<E>(self) -> std::result::Result<E, Self>
134where
135E: Display + Debug + Send + Sync + 'static,
136 {
137if self.error.downcast_ref::<E>().is_some() {
138Ok(self.error.downcast().unwrap())
139 } else {
140Err(self)
141 }
142 }
143144/// Downcast this error object by reference.
145pub fn downcast_ref<E>(&self) -> Option<&E>
146where
147E: Display + Debug + Send + Sync + 'static,
148 {
149self.error.downcast_ref::<E>()
150 }
151152/// Downcast this error object by mutable reference.
153pub fn downcast_mut<E>(&mut self) -> Option<&mut E>
154where
155E: Display + Debug + Send + Sync + 'static,
156 {
157self.error.downcast_mut::<E>()
158 }
159160/// Retrieves a reference to the type name of the error, if available.
161pub fn type_name(&self) -> Option<&str> {
162self.type_name.as_deref()
163 }
164165/// Converts anything which implements `Display` into an `http_types::Error`.
166 ///
167 /// This is handy for errors which are not `Send + Sync + 'static` because `std::error::Error` requires `Display`.
168 /// Note that any assiciated context not included in the `Display` output will be lost,
169 /// and so this may be lossy for some types which implement `std::error::Error`.
170 ///
171 /// **Note: Prefer `error.into()` via `From<Into<anyhow::Error>>` when possible!**
172pub fn from_display<D: Display>(error: D) -> Self {
173 anyhow::Error::msg(error.to_string()).into()
174 }
175176/// Converts anything which implements `Debug` into an `http_types::Error`.
177 ///
178 /// This is handy for errors which are not `Send + Sync + 'static` because `std::error::Error` requires `Debug`.
179 /// Note that any assiciated context not included in the `Debug` output will be lost,
180 /// and so this may be lossy for some types which implement `std::error::Error`.
181 ///
182 /// **Note: Prefer `error.into()` via `From<Into<anyhow::Error>>` when possible!**
183pub fn from_debug<D: Debug>(error: D) -> Self {
184 anyhow::Error::msg(format!("{:?}", error)).into()
185 }
186}
187188impl Display for Error {
189fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
190 Display::fmt(&self.error, formatter)
191 }
192}
193194impl Debug for Error {
195fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
196 Debug::fmt(&self.error, formatter)
197 }
198}
199200impl<E: Into<anyhow::Error>> From<E> for Error {
201fn from(error: E) -> Self {
202Self::new(StatusCode::InternalServerError, error)
203 }
204}
205206impl AsRef<dyn StdError + Send + Sync> for Error {
207fn as_ref(&self) -> &(dyn StdError + Send + Sync + 'static) {
208self.error.as_ref()
209 }
210}
211212impl AsRef<StatusCode> for Error {
213fn as_ref(&self) -> &StatusCode {
214&self.status
215 }
216}
217218impl AsMut<StatusCode> for Error {
219fn as_mut(&mut self) -> &mut StatusCode {
220&mut self.status
221 }
222}
223224impl AsRef<dyn StdError> for Error {
225fn as_ref(&self) -> &(dyn StdError + 'static) {
226self.error.as_ref()
227 }
228}
229230impl From<Error> for Box<dyn StdError + Send + Sync + 'static> {
231fn from(error: Error) -> Self {
232 error.error.into()
233 }
234}
235236impl From<Error> for Box<dyn StdError + 'static> {
237fn from(error: Error) -> Self {
238 Box::<dyn StdError + Send + Sync>::from(error.error)
239 }
240}
241242impl AsRef<anyhow::Error> for Error {
243fn as_ref(&self) -> &anyhow::Error {
244&self.error
245 }
246}