time_scheduler_server/
err.rs

1use std::fmt::{self, Display};
2
3use axum::{
4    body::Body,
5    http::{Response, StatusCode},
6    response::IntoResponse,
7};
8
9#[macro_export]
10macro_rules! err_from_type {
11    ($error_type:expr) => {
12        Error {
13            error_type: $error_type,
14            file: file!(),
15            line: line!(),
16            column: column!(),
17            additional: None,
18        }
19    };
20    ($error_type:expr, $($args:tt)*) => {
21        Error {
22            error_type: $error_type,
23            file: file!(),
24            line: line!(),
25            column: column!(),
26            additional: Some(format!($($args)*)),
27        }
28    }
29}
30
31#[macro_export]
32macro_rules! err_with_context {
33    ($err:expr) => {
34        Error::from(($err, file!(), line!(), column!(), None))
35    };
36    ($err:expr, $($args:tt)*) => {
37        Error::from((
38            $err,
39            file!(),
40            line!(),
41            column!(),
42            Some(format!($($args)*)),
43        ))
44    };
45}
46
47pub enum ErrorType {
48    AxumError(axum::http::Error),
49    SerdeError(serde_json::Error),
50    Tokio(tokio::io::Error),
51    Jwt(jsonwebtoken::errors::Error),
52    Chrono,
53    IdenticalBlockType,
54    NotFound,
55    InternalRustError,
56    TokenExpired,
57    Unauthorized,
58}
59
60impl Display for ErrorType {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        match self {
63            ErrorType::AxumError(error) => write!(f, "Axum error: {}", error),
64            ErrorType::SerdeError(error) => write!(f, "Serde error: {}", error),
65            ErrorType::Tokio(error) => write!(f, "Tokio error: {}", error),
66            ErrorType::Jwt(error) => write!(f, "JWT error: {}", error),
67            ErrorType::Chrono => write!(f, "Chrono error"),
68            ErrorType::IdenticalBlockType => write!(f, "Blocktypes Identical"),
69            ErrorType::NotFound => write!(f, "Timeblock Not Found"),
70            ErrorType::InternalRustError => write!(f, "Internal Rust error"),
71            ErrorType::TokenExpired => write!(f, "Access Token timed out"),
72            ErrorType::Unauthorized => write!(f, "Unauthorized Access"),
73        }
74    }
75}
76
77pub struct Error {
78    pub error_type: ErrorType,
79    pub file: &'static str,
80    pub line: u32,
81    pub column: u32,
82    pub additional: Option<String>,
83}
84
85impl Display for Error {
86    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87        write!(
88            f,
89            "ERROR: {}:{}:{} : {}",
90            self.file, self.line, self.column, self.error_type
91        )?;
92        if let Some(additional) = &self.additional {
93            write!(f, "\n\tAdditional: {}", additional)?;
94        }
95        Ok(())
96    }
97}
98
99impl IntoResponse for Error {
100    #[allow(clippy::unwrap_used)]
101    fn into_response(self) -> Response<Body> {
102        let status_code = StatusCode::INTERNAL_SERVER_ERROR;
103        Response::builder()
104            .status(status_code)
105            .body(Body::from(self.to_string()))
106            .unwrap()
107    }
108}
109
110impl<E> From<(E, &'static str, u32, u32, Option<String>)> for Error
111where
112    E: Into<ErrorType>,
113{
114    fn from(
115        (err, file, line, column, additional): (E, &'static str, u32, u32, Option<String>),
116    ) -> Self {
117        Error {
118            error_type: err.into(),
119            file,
120            line,
121            column,
122            additional,
123        }
124    }
125}
126
127// Conversions for error types
128impl From<axum::http::Error> for ErrorType {
129    fn from(err: axum::http::Error) -> Self {
130        ErrorType::AxumError(err)
131    }
132}
133
134impl From<serde_json::Error> for ErrorType {
135    fn from(err: serde_json::Error) -> Self {
136        ErrorType::SerdeError(err)
137    }
138}
139
140impl From<tokio::io::Error> for ErrorType {
141    fn from(err: tokio::io::Error) -> Self {
142        ErrorType::Tokio(err)
143    }
144}
145
146impl From<chrono::OutOfRangeError> for ErrorType {
147    fn from(_err: chrono::OutOfRangeError) -> Self {
148        ErrorType::Chrono
149    }
150}
151
152impl From<chrono::ParseError> for ErrorType {
153    fn from(_err: chrono::ParseError) -> Self {
154        ErrorType::Chrono
155    }
156}
157
158impl From<jsonwebtoken::errors::Error> for ErrorType {
159    fn from(err: jsonwebtoken::errors::Error) -> Self {
160        ErrorType::Jwt(err)
161    }
162}