1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
use std::error::Error as StdError;

use crate::{IntoResponse, Response, StatusCode, ThisError};

/// An owned dynamically typed [`StdError`].
pub type BoxError = Box<dyn StdError + Send + Sync>;

/// Represents errors that can occur handling application.
#[derive(ThisError, Debug)]
pub enum Error {
    /// Receives a [`Response`] as an error.
    #[error("response")]
    Responder(Response),
    /// Receives a boxed [`std::error::Error`][StdError] as an error.
    #[error(transparent)]
    Boxed(BoxError),
    /// Receives a boxed [`std::error::Error`][StdError] and [`Response`] pair as an error.
    #[error("report")]
    Report(BoxError, Response),
}

impl Error {
    /// Create a new error object from any error type.
    pub fn boxed<T>(t: T) -> Self
    where
        T: Into<BoxError>,
    {
        Self::Boxed(t.into())
    }

    /// Forwards to the method defined on the type `dyn Error`.
    #[inline]
    pub fn is<T>(&self) -> bool
    where
        T: StdError + 'static,
    {
        match self {
            Self::Boxed(e) | Self::Report(e, _) => e.is::<T>(),
            Self::Responder(_) => false,
        }
    }

    /// Attempt to downcast the error object to a concrete type.
    ///
    /// # Errors
    ///
    /// Throws an `Error` if downcast fails.
    #[inline]
    pub fn downcast<T>(self) -> Result<T, Self>
    where
        T: StdError + 'static,
    {
        if let Self::Boxed(e) = self {
            return match e.downcast::<T>() {
                Ok(e) => Ok(*e),
                Err(e) => Err(Self::Boxed(e)),
            };
        }
        if let Self::Report(e, r) = self {
            return match e.downcast::<T>() {
                Ok(e) => Ok(*e),
                Err(e) => Err(Self::Report(e, r)),
            };
        }
        Err(self)
    }

    /// Downcast this error object by reference.
    #[inline]
    pub fn downcast_ref<T>(&self) -> Option<&T>
    where
        T: StdError + 'static,
    {
        if let Self::Boxed(e) = self {
            return e.downcast_ref::<T>();
        }
        if let Self::Report(e, _) = self {
            return e.downcast_ref::<T>();
        }
        None
    }

    /// Downcast this error object by mutable reference.
    #[inline]
    pub fn downcast_mut<T>(&mut self) -> Option<&mut T>
    where
        T: StdError + 'static,
    {
        if let Self::Boxed(e) = self {
            return e.downcast_mut::<T>();
        }
        if let Self::Report(e, _) = self {
            return e.downcast_mut::<T>();
        }
        None
    }
}

impl<E, T> From<(E, T)> for Error
where
    E: Into<BoxError>,
    T: IntoResponse,
{
    fn from((e, t): (E, T)) -> Self {
        Self::Report(e.into(), t.into_response())
    }
}

impl From<http::Error> for Error {
    fn from(e: http::Error) -> Self {
        (e, StatusCode::BAD_REQUEST).into()
    }
}

impl From<hyper::Error> for Error {
    fn from(e: hyper::Error) -> Self {
        (e, StatusCode::BAD_REQUEST).into()
    }
}

impl From<std::convert::Infallible> for Error {
    fn from(e: std::convert::Infallible) -> Self {
        Self::boxed(e)
    }
}

impl From<std::io::Error> for Error {
    fn from(e: std::io::Error) -> Self {
        Self::boxed(e)
    }
}

impl From<BoxError> for Error {
    fn from(value: BoxError) -> Self {
        Self::Boxed(value)
    }
}