revolt_result/
lib.rs

1use std::fmt::Display;
2
3#[cfg(feature = "serde")]
4#[macro_use]
5extern crate serde;
6
7#[cfg(feature = "schemas")]
8#[macro_use]
9extern crate schemars;
10
11#[cfg(feature = "utoipa")]
12#[macro_use]
13extern crate utoipa;
14
15#[cfg(feature = "rocket")]
16pub mod rocket;
17
18#[cfg(feature = "axum")]
19pub mod axum;
20
21#[cfg(feature = "okapi")]
22pub mod okapi;
23
24/// Result type with custom Error
25pub type Result<T, E = Error> = std::result::Result<T, E>;
26
27/// Error information
28#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
29#[cfg_attr(feature = "schemas", derive(JsonSchema))]
30#[cfg_attr(feature = "utoipa", derive(ToSchema))]
31#[derive(Debug, Clone)]
32pub struct Error {
33    /// Type of error and additional information
34    #[cfg_attr(feature = "serde", serde(flatten))]
35    pub error_type: ErrorType,
36
37    /// Where this error occurred
38    pub location: String,
39}
40
41impl Display for Error {
42    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43        write!(f, "{:?} occurred in {}", self.error_type, self.location)
44    }
45}
46
47impl std::error::Error for Error {}
48
49/// Possible error types
50#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
51#[cfg_attr(feature = "serde", serde(tag = "type"))]
52#[cfg_attr(feature = "schemas", derive(JsonSchema))]
53#[cfg_attr(feature = "utoipa", derive(ToSchema))]
54#[derive(Debug, Clone)]
55pub enum ErrorType {
56    /// This error was not labeled :(
57    LabelMe,
58
59    // ? Onboarding related errors
60    AlreadyOnboarded,
61
62    // ? User related errors
63    UsernameTaken,
64    InvalidUsername,
65    DiscriminatorChangeRatelimited,
66    UnknownUser,
67    AlreadyFriends,
68    AlreadySentRequest,
69    Blocked,
70    BlockedByOther,
71    NotFriends,
72    TooManyPendingFriendRequests {
73        max: usize,
74    },
75
76    // ? Channel related errors
77    UnknownChannel,
78    UnknownAttachment,
79    UnknownMessage,
80    CannotEditMessage,
81    CannotJoinCall,
82    TooManyAttachments {
83        max: usize,
84    },
85    TooManyEmbeds {
86        max: usize,
87    },
88    TooManyReplies {
89        max: usize,
90    },
91    TooManyChannels {
92        max: usize,
93    },
94    EmptyMessage,
95    PayloadTooLarge,
96    CannotRemoveYourself,
97    GroupTooLarge {
98        max: usize,
99    },
100    AlreadyInGroup,
101    NotInGroup,
102    AlreadyPinned,
103    NotPinned,
104
105    // ? Server related errors
106    UnknownServer,
107    InvalidRole,
108    Banned,
109    TooManyServers {
110        max: usize,
111    },
112    TooManyEmoji {
113        max: usize,
114    },
115    TooManyRoles {
116        max: usize,
117    },
118    AlreadyInServer,
119    CannotTimeoutYourself,
120
121    // ? Bot related errors
122    ReachedMaximumBots,
123    IsBot,
124    IsNotBot,
125    BotIsPrivate,
126
127    // ? User safety related errors
128    CannotReportYourself,
129
130    // ? Permission errors
131    MissingPermission {
132        permission: String,
133    },
134    MissingUserPermission {
135        permission: String,
136    },
137    NotElevated,
138    NotPrivileged,
139    CannotGiveMissingPermissions,
140    NotOwner,
141
142    // ? General errors
143    DatabaseError {
144        operation: String,
145        collection: String,
146    },
147    InternalError,
148    InvalidOperation,
149    InvalidCredentials,
150    InvalidProperty,
151    InvalidSession,
152    InvalidFlagValue,
153    NotAuthenticated,
154    DuplicateNonce,
155    NotFound,
156    NoEffect,
157    FailedValidation {
158        error: String,
159    },
160
161    // ? Micro-service errors
162    ProxyError,
163    FileTooSmall,
164    FileTooLarge {
165        max: usize,
166    },
167    FileTypeNotAllowed,
168    ImageProcessingFailed,
169    NoEmbedData,
170
171    // ? Legacy errors
172    VosoUnavailable,
173
174    // ? Feature flag disabled in the config
175    FeatureDisabled {
176        feature: String,
177    },
178}
179
180#[macro_export]
181macro_rules! create_error {
182    ( $error: ident $( $tt:tt )? ) => {
183        $crate::Error {
184            error_type: $crate::ErrorType::$error $( $tt )?,
185            location: format!("{}:{}:{}", file!(), line!(), column!()),
186        }
187    };
188}
189
190#[macro_export]
191macro_rules! create_database_error {
192    ( $operation: expr, $collection: expr ) => {
193        $crate::create_error!(DatabaseError {
194            operation: $operation.to_string(),
195            collection: $collection.to_string()
196        })
197    };
198}
199
200#[cfg(test)]
201mod tests {
202    use crate::ErrorType;
203
204    #[test]
205    fn use_macro_to_construct_error() {
206        let error = create_error!(LabelMe);
207        assert!(matches!(error.error_type, ErrorType::LabelMe));
208    }
209
210    #[test]
211    fn use_macro_to_construct_complex_error() {
212        let error = create_error!(LabelMe);
213        assert!(matches!(error.error_type, ErrorType::LabelMe));
214    }
215}