rustical_store/
error.rs

1use axum::response::IntoResponse;
2use http::StatusCode;
3use tracing::error;
4
5#[derive(Debug, thiserror::Error)]
6pub enum Error {
7    #[error("Not found")]
8    NotFound,
9
10    #[error("Resource already exists and overwrite=false")]
11    AlreadyExists,
12
13    #[error("Invalid principal type: {0}")]
14    InvalidPrincipalType(String),
15
16    #[error("Read-only")]
17    ReadOnly,
18
19    #[error("Error generating password hash")]
20    PasswordHash,
21
22    #[error(transparent)]
23    IO(#[from] std::io::Error),
24
25    #[error(transparent)]
26    Other(#[from] anyhow::Error),
27
28    #[error(transparent)]
29    IcalError(#[from] caldata::parser::ParserError),
30}
31
32impl Error {
33    #[must_use]
34    pub const fn status_code(&self) -> StatusCode {
35        match self {
36            Self::NotFound => StatusCode::NOT_FOUND,
37            Self::AlreadyExists => StatusCode::CONFLICT,
38            Self::ReadOnly => StatusCode::FORBIDDEN,
39            Self::IcalError(_err) => StatusCode::INTERNAL_SERVER_ERROR,
40            Self::InvalidPrincipalType(_) => StatusCode::BAD_REQUEST,
41            _ => StatusCode::INTERNAL_SERVER_ERROR,
42        }
43    }
44
45    #[must_use]
46    pub const fn is_not_found(&self) -> bool {
47        matches!(self, Self::NotFound)
48    }
49}
50
51impl IntoResponse for Error {
52    fn into_response(self) -> axum::response::Response {
53        if matches!(
54            self.status_code(),
55            StatusCode::INTERNAL_SERVER_ERROR | StatusCode::CONFLICT
56        ) {
57            error!("{self}");
58        }
59        (self.status_code(), self.to_string()).into_response()
60    }
61}