Skip to main content

zulip_api/message/response/
error_code.rs

1use serde::{Deserialize, Serialize};
2use zeroize::Zeroize;
3
4use crate::error::Error;
5use crate::result::Result;
6
7/// Represents the Zulip server response error code variants.
8#[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize, Serialize, Zeroize)]
9#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
10pub enum ErrorCode {
11    /// Indicates a general request error.
12    BadRequest,
13    /// Indicates an invalid API key.
14    InvalidApiKey,
15    /// Indicates a missing required request variable.
16    RequestVariableMissing,
17    /// Indicates the requested user is desctivated.
18    UserDeactivated,
19    /// Indicates the requested organization is desctivated.
20    RealmDeactivated,
21    /// Indicates the rate limit was exceeded.
22    RateLimitHit,
23    /// Indicates the requested stream does not exist.
24    StreamDoesNotExist,
25    /// Indicates a bad narrow filter.
26    BadNarrow,
27}
28
29impl ErrorCode {
30    /// Represents the string value for the general bad request [ErrorCode].
31    pub const BAD_REQUEST: &str = "BAD_REQUEST";
32    /// Represents the string value for the invalid API key [ErrorCode].
33    pub const INVALID_API_KEY: &str = "INVALID_API_KEY";
34    /// Represents the string value for the request variable missing [ErrorCode].
35    pub const REQUEST_VARIABLE_MISSING: &str = "REQUEST_VARIABLE_MISSING";
36    /// Represents the string value for the user deactivated [ErrorCode].
37    pub const USER_DEACTIVATED: &str = "USER_DEACTIVATED";
38    /// Represents the string value for the realm deactivated [ErrorCode].
39    pub const REALM_DEACTIVATED: &str = "REALM_DEACTIVATED";
40    /// Represents the string value for the rate limit hit [ErrorCode].
41    pub const RATE_LIMIT_HIT: &str = "RATE_LIMIT_HIT";
42    /// Represents the string value for the stream does not exist [ErrorCode].
43    pub const STREAM_DOES_NOT_EXIST: &str = "STREAM_DOES_NOT_EXIST";
44    /// Represents the string value for the bad narrow [ErrorCode].
45    pub const BAD_NARROW: &str = "BAD_NARROW";
46
47    /// Creates a new [ErrorCode].
48    pub const fn new() -> Self {
49        Self::BadRequest
50    }
51
52    /// Gets the string representation of the [ErrorCode].
53    pub const fn as_str(&self) -> &'static str {
54        match self {
55            Self::BadRequest => Self::BAD_REQUEST,
56            Self::InvalidApiKey => Self::INVALID_API_KEY,
57            Self::RequestVariableMissing => Self::REQUEST_VARIABLE_MISSING,
58            Self::UserDeactivated => Self::USER_DEACTIVATED,
59            Self::RealmDeactivated => Self::REALM_DEACTIVATED,
60            Self::RateLimitHit => Self::RATE_LIMIT_HIT,
61            Self::StreamDoesNotExist => Self::STREAM_DOES_NOT_EXIST,
62            Self::BadNarrow => Self::BAD_NARROW,
63        }
64    }
65
66    /// Attempts to convert a string into an [ErrorCode].
67    pub fn try_from_str<S: Into<String>>(val: S) -> Result<Self> {
68        match val.into().to_uppercase().as_str() {
69            Self::BAD_REQUEST => Ok(Self::BadRequest),
70            Self::INVALID_API_KEY => Ok(Self::InvalidApiKey),
71            Self::REQUEST_VARIABLE_MISSING => Ok(Self::RequestVariableMissing),
72            Self::USER_DEACTIVATED => Ok(Self::UserDeactivated),
73            Self::REALM_DEACTIVATED => Ok(Self::RealmDeactivated),
74            Self::RATE_LIMIT_HIT => Ok(Self::RateLimitHit),
75            Self::STREAM_DOES_NOT_EXIST => Ok(Self::StreamDoesNotExist),
76            Self::BAD_NARROW => Ok(Self::BadNarrow),
77            s => Err(Error::io_other(format!("invalid ErrorCode: {s}"))),
78        }
79    }
80}
81
82impl Default for ErrorCode {
83    fn default() -> Self {
84        Self::new()
85    }
86}
87
88impl From<ErrorCode> for &'static str {
89    fn from(val: ErrorCode) -> Self {
90        val.as_str()
91    }
92}
93
94impl From<ErrorCode> for String {
95    fn from(val: ErrorCode) -> Self {
96        val.as_str().to_string()
97    }
98}
99
100impl TryFrom<&str> for ErrorCode {
101    type Error = Error;
102
103    fn try_from(val: &str) -> Result<Self> {
104        Self::try_from_str(val)
105    }
106}
107
108impl TryFrom<String> for ErrorCode {
109    type Error = Error;
110
111    fn try_from(val: String) -> Result<Self> {
112        Self::try_from_str(val)
113    }
114}
115
116impl std::fmt::Display for ErrorCode {
117    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
118        write!(f, "{}", self.as_str())
119    }
120}
121
122#[cfg(test)]
123mod tests {
124    use super::*;
125
126    #[test]
127    fn test_error_code() {
128        [
129            (ErrorCode::BadRequest, ErrorCode::BAD_REQUEST),
130            (ErrorCode::InvalidApiKey, ErrorCode::INVALID_API_KEY),
131            (
132                ErrorCode::RequestVariableMissing,
133                ErrorCode::REQUEST_VARIABLE_MISSING,
134            ),
135            (ErrorCode::UserDeactivated, ErrorCode::USER_DEACTIVATED),
136            (ErrorCode::RealmDeactivated, ErrorCode::REALM_DEACTIVATED),
137            (ErrorCode::RateLimitHit, ErrorCode::RATE_LIMIT_HIT),
138            (
139                ErrorCode::StreamDoesNotExist,
140                ErrorCode::STREAM_DOES_NOT_EXIST,
141            ),
142            (ErrorCode::BadNarrow, ErrorCode::BAD_NARROW),
143        ]
144        .into_iter()
145        .for_each(|(code, code_str)| {
146            let code_json = format!(r#""{code}""#);
147            assert_eq!(code.as_str(), code_str);
148
149            assert_eq!(<&str>::from(code), code_str);
150            assert_eq!(String::from(code), code_str.to_string());
151
152            assert_eq!(ErrorCode::try_from_str(code_str), Ok(code));
153            assert_eq!(ErrorCode::try_from(code_str), Ok(code));
154            assert_eq!(ErrorCode::try_from(code_str.to_string()), Ok(code));
155
156            assert_eq!(serde_json::to_string(&code).unwrap(), code_json);
157            assert_eq!(serde_json::from_str::<ErrorCode>(&code_json).unwrap(), code);
158        });
159    }
160}