1use std::fmt;
2
3#[allow(clippy::module_name_repetitions)]
4#[derive(Debug)]
5pub enum Error {
6 Other(String),
7 Db(String),
8 Params(String),
9 Busy(String),
10 NotFound(String),
11 Ser(String),
12 Access(String),
13}
14
15impl fmt::Display for Error {
16 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17 match self {
18 Error::Other(s) | Error::Busy(s) => write!(f, "{}", s),
19 Error::Db(s) => write!(f, "database error: {}", s),
20 Error::Params(s) => write!(f, "invalid params: {}", s),
21 Error::NotFound(s) => write!(f, "not found: {}", s),
22 Error::Ser(s) => write!(f, "serde error: {}", s),
23 Error::Access(s) => write!(f, "access error: {}", s),
24 }
25 }
26}
27
28impl std::error::Error for Error {}
29
30impl Error {
31 pub fn other(e: impl fmt::Display) -> Self {
32 Self::Other(e.to_string())
33 }
34 pub fn not_found(e: impl fmt::Display) -> Self {
35 Self::NotFound(e.to_string())
36 }
37 pub fn ser<E: std::error::Error>(e: E) -> Self {
38 Self::Ser(e.to_string())
39 }
40 pub fn db<E: std::error::Error>(e: E) -> Self {
41 Self::Db(e.to_string())
42 }
43 pub fn params(e: impl fmt::Display) -> Self {
44 Self::Params(e.to_string())
45 }
46 pub fn access(e: impl fmt::Display) -> Self {
47 Self::Access(e.to_string())
48 }
49 pub fn busy(e: impl fmt::Display) -> Self {
50 Self::Busy(e.to_string())
51 }
52}
53
54#[cfg(feature = "ci")]
55impl From<async_channel::RecvError> for Error {
56 fn from(e: async_channel::RecvError) -> Self {
57 Self::other(e)
58 }
59}
60
61#[cfg(feature = "ci")]
62impl From<sqlx::Error> for Error {
63 fn from(e: sqlx::Error) -> Self {
64 Self::db(e)
65 }
66}
67
68#[cfg(feature = "server")]
69impl From<regex::Error> for Error {
70 fn from(e: regex::Error) -> Self {
71 Self::params(e)
72 }
73}
74
75#[cfg(feature = "ci")]
76impl From<serde_json::Error> for Error {
77 fn from(e: serde_json::Error) -> Self {
78 Self::ser(e)
79 }
80}
81
82impl From<std::num::TryFromIntError> for Error {
83 fn from(e: std::num::TryFromIntError) -> Self {
84 Self::other(e)
85 }
86}
87
88impl From<std::fmt::Error> for Error {
89 fn from(e: std::fmt::Error) -> Self {
90 Self::other(e)
91 }
92}
93
94impl From<std::io::Error> for Error {
95 fn from(e: std::io::Error) -> Self {
96 if e.kind() == std::io::ErrorKind::NotFound {
97 Self::not_found(e)
98 } else {
99 Self::other(e)
100 }
101 }
102}
103
104#[cfg(feature = "http")]
105pub mod http {
106 use super::Error as RciError;
107 use axum::http::StatusCode;
108
109 pub type Error = (StatusCode, String);
110
111 impl From<RciError> for Error {
112 fn from(e: RciError) -> Self {
113 match e {
114 RciError::NotFound(s) => (StatusCode::NOT_FOUND, s),
115 RciError::Params(s) => (StatusCode::BAD_REQUEST, s),
116 RciError::Busy(s) => (StatusCode::LOCKED, s),
117 RciError::Other(s) | RciError::Db(s) | RciError::Ser(s) => {
118 (StatusCode::INTERNAL_SERVER_ERROR, s)
119 }
120 RciError::Access(s) => (StatusCode::FORBIDDEN, s),
121 }
122 }
123 }
124}