xitca_web/error/
status.rs

1use core::{convert::Infallible, fmt};
2
3use std::error;
4
5use std::backtrace::Backtrace;
6
7use crate::{
8    WebContext,
9    body::ResponseBody,
10    http::{StatusCode, WebResponse},
11    service::Service,
12};
13
14use super::Error;
15
16/// error type derive from http status code. produce minimal "StatusCode Reason" response and stack backtrace
17/// of the location status code error occurs.
18pub struct ErrorStatus {
19    status: StatusCode,
20    _back_trace: Backtrace,
21}
22
23impl ErrorStatus {
24    /// construct an ErrorStatus type from [`StatusCode::INTERNAL_SERVER_ERROR`]
25    pub fn internal() -> Self {
26        // verbosity of constructor is desired here so back trace capture
27        // can direct capture the call site.
28        Self {
29            status: StatusCode::INTERNAL_SERVER_ERROR,
30            _back_trace: Backtrace::capture(),
31        }
32    }
33
34    /// construct an ErrorStatus type from [`StatusCode::BAD_REQUEST`]
35    pub fn bad_request() -> Self {
36        Self {
37            status: StatusCode::BAD_REQUEST,
38            _back_trace: Backtrace::capture(),
39        }
40    }
41}
42
43impl fmt::Debug for ErrorStatus {
44    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45        fmt::Debug::fmt(&self.status, f)
46    }
47}
48
49impl fmt::Display for ErrorStatus {
50    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51        fmt::Display::fmt(&self.status, f)
52    }
53}
54
55impl error::Error for ErrorStatus {
56    #[cfg(feature = "nightly")]
57    fn provide<'a>(&'a self, request: &mut error::Request<'a>) {
58        request.provide_ref(&self._back_trace);
59    }
60}
61
62impl From<StatusCode> for ErrorStatus {
63    fn from(status: StatusCode) -> Self {
64        Self {
65            status,
66            _back_trace: Backtrace::capture(),
67        }
68    }
69}
70
71impl From<StatusCode> for Error {
72    fn from(e: StatusCode) -> Self {
73        Error::from(ErrorStatus::from(e))
74    }
75}
76
77impl From<ErrorStatus> for Error {
78    fn from(e: ErrorStatus) -> Self {
79        Error::from_service(e)
80    }
81}
82
83impl<'r, C, B> Service<WebContext<'r, C, B>> for ErrorStatus {
84    type Response = WebResponse;
85    type Error = Infallible;
86
87    async fn call(&self, ctx: WebContext<'r, C, B>) -> Result<Self::Response, Self::Error> {
88        self.status.call(ctx).await
89    }
90}
91
92impl<'r, C, B> Service<WebContext<'r, C, B>> for StatusCode {
93    type Response = WebResponse;
94    type Error = Infallible;
95
96    async fn call(&self, ctx: WebContext<'r, C, B>) -> Result<Self::Response, Self::Error> {
97        let mut res = ctx.into_response(ResponseBody::empty());
98        *res.status_mut() = *self;
99        Ok(res)
100    }
101}