Skip to main content

endpoint_libs/libs/
error_code.rs

1use serde::*;
2use std::str::FromStr;
3
4/// `ErrorCode` is a wrapper around `u32` that represents an error code.
5#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
6pub struct ErrorCode {
7    /// The error code (e.g. `100400` for BadRequest).
8    code: u32,
9}
10
11impl ErrorCode {
12    /// Indicated a bad request.
13    pub const BAD_REQUEST: Self = Self::new(100400);
14
15    /// Indicates that authentication is required.
16    pub const UNAUTHORIZED: Self = Self::new(100401);
17
18    /// Indicates that payment is required.
19    pub const PAYMENT_REQUIRED: Self = Self::new(100402);
20
21    /// Indicates forbidden access.
22    pub const FORBIDDEN: Self = Self::new(100403);
23
24    /// Indicates that the requested resource was not found.
25    pub const NOT_FOUND: Self = Self::new(100404);
26
27    /// Indicates that the request method is not allowed.
28    pub const METHOD_NOT_ALLOWED: Self = Self::new(100405);
29
30    /// Indicates that the requested response format is not acceptable.
31    pub const NOT_ACCEPTABLE: Self = Self::new(100406);
32
33    /// Indicates that proxy authentication is required.
34    pub const PROXY_AUTHENTICATION_REQUIRED: Self = Self::new(100407);
35
36    /// Indicates that the request timed out.
37    pub const REQUEST_TIMEOUT: Self = Self::new(100408);
38
39    /// Indicates that the request conflicts with current state.
40    pub const CONFLICT: Self = Self::new(100409);
41
42    /// Indicates that the requested resource is gone.
43    pub const GONE: Self = Self::new(100410);
44
45    /// Indicates that the request must include a content length.
46    pub const LENGTH_REQUIRED: Self = Self::new(100411);
47
48    /// Indicates that a precondition failed.
49    pub const PRECONDITION_FAILED: Self = Self::new(100412);
50
51    /// Indicates that the payload is too large.
52    pub const PAYLOAD_TOO_LARGE: Self = Self::new(100413);
53
54    /// Indicates that the URI is too long.
55    pub const URI_TOO_LONG: Self = Self::new(100414);
56
57    /// Indicates that the media type is unsupported.
58    pub const UNSUPPORTED_MEDIA_TYPE: Self = Self::new(100415);
59
60    /// Indicates that the requested range cannot be satisfied.
61    pub const RANGE_NOT_SATISFIABLE: Self = Self::new(100416);
62
63    /// Indicates that an expectation failed.
64    pub const EXPECTATION_FAILED: Self = Self::new(100417);
65
66    /// Indicates an I'm a teapot response.
67    pub const IM_A_TEAPOT: Self = Self::new(100418);
68
69    /// Indicates that the request was misdirected.
70    pub const MISDIRECTED_REQUEST: Self = Self::new(100421);
71
72    /// Indicates that the entity could not be processed.
73    pub const UNPROCESSABLE_ENTITY: Self = Self::new(100422);
74
75    /// Indicates that the resource is locked.
76    pub const LOCKED: Self = Self::new(100423);
77
78    /// Indicates a failed dependency.
79    pub const FAILED_DEPENDENCY: Self = Self::new(100424);
80
81    /// Indicates that the request must be upgraded.
82    pub const UPGRADE_REQUIRED: Self = Self::new(100426);
83
84    /// Indicates that a precondition is required.
85    pub const PRECONDITION_REQUIRED: Self = Self::new(100428);
86
87    /// Indicates too many requests.
88    pub const TOO_MANY_REQUESTS: Self = Self::new(100429);
89
90    /// Indicates that request header fields are too large.
91    pub const REQUEST_HEADER_FIELDS_TOO_LARGE: Self = Self::new(100431);
92
93    /// Indicates that the request is unavailable for legal reasons.
94    pub const UNAVAILABLE_FOR_LEGAL_REASONS: Self = Self::new(100451);
95
96    /// Indicates an internal server error.
97    pub const INTERNAL_ERROR: Self = Self::new(100500);
98
99    /// Indicates a non-implemented endpoint.
100    pub const NOT_IMPLEMENTED: Self = Self::new(100501);
101
102    /// Indicates a bad gateway.
103    pub const BAD_GATEWAY: Self = Self::new(100502);
104
105    /// Indicates that the service is unavailable.
106    pub const SERVICE_UNAVAILABLE: Self = Self::new(100503);
107
108    /// Indicates a gateway timeout.
109    pub const GATEWAY_TIMEOUT: Self = Self::new(100504);
110
111    /// Indicates that the HTTP version is not supported.
112    pub const HTTP_VERSION_NOT_SUPPORTED: Self = Self::new(100505);
113
114    /// Indicates that content negotiation also found a variant problem.
115    pub const VARIANT_ALSO_NEGOTIATES: Self = Self::new(100506);
116
117    /// Indicates insufficient storage.
118    pub const INSUFFICIENT_STORAGE: Self = Self::new(100507);
119
120    /// Indicates that a loop was detected.
121    pub const LOOP_DETECTED: Self = Self::new(100508);
122
123    /// Indicates that the request must be extended.
124    pub const NOT_EXTENDED: Self = Self::new(100510);
125
126    /// Indicates that network authentication is required.
127    pub const NETWORK_AUTHENTICATION_REQUIRED: Self = Self::new(100511);
128
129    /// Create a new `ErrorCode` from a `u32`.
130    pub const fn new(code: u32) -> Self {
131        Self { code }
132    }
133
134    /// Get the `ErrorCode` as a `u32`.
135    /// Just returns the code field.
136    pub const fn to_u32(self) -> u32 {
137        self.code
138    }
139
140    /// Getter for the `ErrorCode` code field.
141    pub const fn code(self) -> u32 {
142        self.to_u32()
143    }
144
145    pub const fn kind(self) -> &'static str {
146        match self.code {
147            100400 => "BadRequest",
148            100401 => "Unauthorized",
149            100402 => "PaymentRequired",
150            100403 => "Forbidden",
151            100404 => "NotFound",
152            100405 => "MethodNotAllowed",
153            100406 => "NotAcceptable",
154            100407 => "ProxyAuthenticationRequired",
155            100408 => "RequestTimeout",
156            100409 => "Conflict",
157            100410 => "Gone",
158            100411 => "LengthRequired",
159            100412 => "PreconditionFailed",
160            100413 => "PayloadTooLarge",
161            100414 => "UriTooLong",
162            100415 => "UnsupportedMediaType",
163            100416 => "RangeNotSatisfiable",
164            100417 => "ExpectationFailed",
165            100418 => "ImATeapot",
166            100421 => "MisdirectedRequest",
167            100422 => "UnprocessableEntity",
168            100423 => "Locked",
169            100424 => "FailedDependency",
170            100426 => "UpgradeRequired",
171            100428 => "PreconditionRequired",
172            100429 => "TooManyRequests",
173            100431 => "RequestHeaderFieldsTooLarge",
174            100451 => "UnavailableForLegalReasons",
175            100500 => "InternalError",
176            100501 => "NotImplemented",
177            100502 => "BadGateway",
178            100503 => "ServiceUnavailable",
179            100504 => "GatewayTimeout",
180            100505 => "HttpVersionNotSupported",
181            100506 => "VariantAlsoNegotiates",
182            100507 => "InsufficientStorage",
183            100508 => "LoopDetected",
184            100510 => "NotExtended",
185            100511 => "NetworkAuthenticationRequired",
186            _ => "CustomError",
187        }
188    }
189
190    pub fn from_name(name: &str) -> Option<Self> {
191        let normalized: String = name
192            .chars()
193            .filter(|c| c.is_ascii_alphanumeric())
194            .flat_map(char::to_uppercase)
195            .collect();
196
197        match normalized.as_str() {
198            "BADREQUEST" => Some(Self::BAD_REQUEST),
199            "UNAUTHORIZED" => Some(Self::UNAUTHORIZED),
200            "PAYMENTREQUIRED" => Some(Self::PAYMENT_REQUIRED),
201            "FORBIDDEN" => Some(Self::FORBIDDEN),
202            "NOTFOUND" => Some(Self::NOT_FOUND),
203            "METHODNOTALLOWED" => Some(Self::METHOD_NOT_ALLOWED),
204            "NOTACCEPTABLE" => Some(Self::NOT_ACCEPTABLE),
205            "PROXYAUTHENTICATIONREQUIRED" => Some(Self::PROXY_AUTHENTICATION_REQUIRED),
206            "REQUESTTIMEOUT" => Some(Self::REQUEST_TIMEOUT),
207            "CONFLICT" => Some(Self::CONFLICT),
208            "GONE" => Some(Self::GONE),
209            "LENGTHREQUIRED" => Some(Self::LENGTH_REQUIRED),
210            "PRECONDITIONFAILED" => Some(Self::PRECONDITION_FAILED),
211            "PAYLOADTOOLARGE" => Some(Self::PAYLOAD_TOO_LARGE),
212            "URITOOLONG" => Some(Self::URI_TOO_LONG),
213            "UNSUPPORTEDMEDIATYPE" => Some(Self::UNSUPPORTED_MEDIA_TYPE),
214            "RANGENOTSATISFIABLE" => Some(Self::RANGE_NOT_SATISFIABLE),
215            "EXPECTATIONFAILED" => Some(Self::EXPECTATION_FAILED),
216            "IMATEAPOT" => Some(Self::IM_A_TEAPOT),
217            "MISDIRECTEDREQUEST" => Some(Self::MISDIRECTED_REQUEST),
218            "UNPROCESSABLEENTITY" => Some(Self::UNPROCESSABLE_ENTITY),
219            "LOCKED" => Some(Self::LOCKED),
220            "FAILEDDEPENDENCY" => Some(Self::FAILED_DEPENDENCY),
221            "UPGRADEREQUIRED" => Some(Self::UPGRADE_REQUIRED),
222            "PRECONDITIONREQUIRED" => Some(Self::PRECONDITION_REQUIRED),
223            "TOOMANYREQUESTS" => Some(Self::TOO_MANY_REQUESTS),
224            "REQUESTHEADERFIELDSTOOLARGE" => Some(Self::REQUEST_HEADER_FIELDS_TOO_LARGE),
225            "UNAVAILABLEFORLEGALREASONS" => Some(Self::UNAVAILABLE_FOR_LEGAL_REASONS),
226            "INTERNALERROR" => Some(Self::INTERNAL_ERROR),
227            "NOTIMPLEMENTED" => Some(Self::NOT_IMPLEMENTED),
228            "BADGATEWAY" => Some(Self::BAD_GATEWAY),
229            "SERVICEUNAVAILABLE" => Some(Self::SERVICE_UNAVAILABLE),
230            "GATEWAYTIMEOUT" => Some(Self::GATEWAY_TIMEOUT),
231            "HTTPVERSIONNOTSUPPORTED" => Some(Self::HTTP_VERSION_NOT_SUPPORTED),
232            "VARIANTALSONEGOTIATES" => Some(Self::VARIANT_ALSO_NEGOTIATES),
233            "INSUFFICIENTSTORAGE" => Some(Self::INSUFFICIENT_STORAGE),
234            "LOOPDETECTED" => Some(Self::LOOP_DETECTED),
235            "NOTEXTENDED" => Some(Self::NOT_EXTENDED),
236            "NETWORKAUTHENTICATIONREQUIRED" => Some(Self::NETWORK_AUTHENTICATION_REQUIRED),
237            _ => None,
238        }
239    }
240}
241
242impl FromStr for ErrorCode {
243    type Err = ParseErrorCodeError;
244
245    fn from_str(value: &str) -> Result<Self, Self::Err> {
246        if let Some(code) = Self::from_name(value) {
247            return Ok(code);
248        }
249
250        value
251            .parse::<u32>()
252            .map(Self::new)
253            .map_err(|_| ParseErrorCodeError)
254    }
255}
256
257#[derive(Debug, Clone, Copy, PartialEq, Eq)]
258pub struct ParseErrorCodeError;
259
260impl std::fmt::Display for ParseErrorCodeError {
261    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
262        f.write_str("invalid error code")
263    }
264}
265
266impl std::error::Error for ParseErrorCodeError {}