viz_core/
error.rs

1use std::error::Error as StdError;
2
3use crate::{IntoResponse, Response, StatusCode, ThisError};
4
5/// An owned dynamically typed [`StdError`].
6pub type BoxError = Box<dyn StdError + Send + Sync>;
7
8/// Represents errors that can occur handling application.
9#[derive(ThisError, Debug)]
10pub enum Error {
11    /// Receives a [`Response`] as an error.
12    #[error("response")]
13    Responder(Response),
14    /// Receives a boxed [`std::error::Error`][StdError] as an error.
15    #[error(transparent)]
16    Boxed(BoxError),
17    /// Receives a boxed [`std::error::Error`][StdError] and [`Response`] pair as an error.
18    #[error("report")]
19    Report(BoxError, Response),
20}
21
22impl Error {
23    /// Create a new error object from any error type.
24    pub fn boxed<T>(t: T) -> Self
25    where
26        T: Into<BoxError>,
27    {
28        Self::Boxed(t.into())
29    }
30
31    /// Forwards to the method defined on the type `dyn Error`.
32    #[inline]
33    pub fn is<T>(&self) -> bool
34    where
35        T: StdError + 'static,
36    {
37        match self {
38            Self::Boxed(e) | Self::Report(e, _) => e.is::<T>(),
39            Self::Responder(_) => false,
40        }
41    }
42
43    /// Attempt to downcast the error object to a concrete type.
44    ///
45    /// # Errors
46    ///
47    /// Throws an `Error` if downcast fails.
48    #[inline]
49    pub fn downcast<T>(self) -> Result<T, Self>
50    where
51        T: StdError + 'static,
52    {
53        if let Self::Boxed(e) = self {
54            return match e.downcast::<T>() {
55                Ok(e) => Ok(*e),
56                Err(e) => Err(Self::Boxed(e)),
57            };
58        }
59        if let Self::Report(e, r) = self {
60            return match e.downcast::<T>() {
61                Ok(e) => Ok(*e),
62                Err(e) => Err(Self::Report(e, r)),
63            };
64        }
65        Err(self)
66    }
67
68    /// Downcast this error object by reference.
69    #[inline]
70    pub fn downcast_ref<T>(&self) -> Option<&T>
71    where
72        T: StdError + 'static,
73    {
74        if let Self::Boxed(e) = self {
75            return e.downcast_ref::<T>();
76        }
77        if let Self::Report(e, _) = self {
78            return e.downcast_ref::<T>();
79        }
80        None
81    }
82
83    /// Downcast this error object by mutable reference.
84    #[inline]
85    pub fn downcast_mut<T>(&mut self) -> Option<&mut T>
86    where
87        T: StdError + 'static,
88    {
89        if let Self::Boxed(e) = self {
90            return e.downcast_mut::<T>();
91        }
92        if let Self::Report(e, _) = self {
93            return e.downcast_mut::<T>();
94        }
95        None
96    }
97}
98
99impl<E, T> From<(E, T)> for Error
100where
101    E: Into<BoxError>,
102    T: IntoResponse,
103{
104    fn from((e, t): (E, T)) -> Self {
105        Self::Report(e.into(), t.into_response())
106    }
107}
108
109impl From<http::Error> for Error {
110    fn from(e: http::Error) -> Self {
111        (e, StatusCode::BAD_REQUEST).into()
112    }
113}
114
115impl From<hyper::Error> for Error {
116    fn from(e: hyper::Error) -> Self {
117        (e, StatusCode::BAD_REQUEST).into()
118    }
119}
120
121impl From<std::convert::Infallible> for Error {
122    fn from(e: std::convert::Infallible) -> Self {
123        Self::boxed(e)
124    }
125}
126
127impl From<std::io::Error> for Error {
128    fn from(e: std::io::Error) -> Self {
129        Self::boxed(e)
130    }
131}
132
133impl From<BoxError> for Error {
134    fn from(value: BoxError) -> Self {
135        Self::Boxed(value)
136    }
137}