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