http_error/
option_ext.rs

1use std::borrow::Cow;
2use std::{error, fmt};
3
4use http::StatusCode;
5
6use crate::HttpError;
7
8#[derive(Debug)]
9pub struct StatusError {
10    status: StatusCode,
11    context: Cow<'static, str>,
12    #[cfg(feature = "tracing")]
13    span: tracing::Span,
14}
15
16impl StatusError {
17    pub fn new(status: StatusCode, context: impl Into<Cow<'static, str>>) -> Self {
18        Self {
19            status,
20            context: context.into(),
21            #[cfg(feature = "tracing")]
22            span: tracing::Span::current(),
23        }
24    }
25}
26
27macro_rules! trait_fn {
28    ($name:ident) => {
29        fn $name(self, context: impl Into<Cow<'static, str>>) -> Result<T, StatusError>;
30    };
31}
32macro_rules! impl_fn {
33    ($name:ident, $status:ident) => {
34        fn $name(self, context: impl Into<Cow<'static, str>>) -> Result<T, StatusError> {
35            self.ok_or_else(|| StatusError::new(StatusCode::$status, context))
36        }
37    };
38}
39
40pub trait OptionExt<T> {
41    // 400 Bad Request
42    trait_fn!(ok_or_bad_request);
43    // 401 Unauthorized
44    trait_fn!(ok_or_unauthorized);
45    // 402 Payment Required
46    trait_fn!(ok_or_payment_required);
47    // 403 Forbidden
48    trait_fn!(ok_or_forbidden);
49    // 404 Not Found
50    trait_fn!(ok_or_not_found);
51    // 405 Method Not Allowed
52    trait_fn!(ok_or_method_not_allowed);
53    // 406 Not Acceptable
54    trait_fn!(ok_or_not_acceptable);
55    // 407 Proxy Authentication Required
56    trait_fn!(ok_or_proxy_authentication_required);
57    // 408 Request Timeout
58    trait_fn!(ok_or_request_timeout);
59    // 409 Conflict
60    trait_fn!(ok_or_conflict);
61    // 410 Gone
62    trait_fn!(ok_or_gone);
63    // 411 Length Required
64    trait_fn!(ok_or_length_required);
65    // 412 Precondition Failed
66    trait_fn!(ok_or_precondition_failed);
67    // 413 Payload Too Large
68    trait_fn!(ok_or_payload_too_large);
69    // 414 URI Too Long
70    trait_fn!(ok_or_uri_too_long);
71    // 415 Unsupported Media Type
72    trait_fn!(ok_or_unsupported_media_type);
73    // 416 Range Not Satisfiable
74    trait_fn!(ok_or_range_not_satisfiable);
75    // 417 Expectation Failed
76    trait_fn!(ok_or_expectation_failed);
77    // 418 I'm a teapot
78    trait_fn!(ok_or_im_a_teapot);
79
80    // 421 Misdirected Request
81    trait_fn!(ok_or_misdirected_request);
82    // 422 Unprocessable Entity
83    trait_fn!(ok_or_unprocessable_entity);
84    // 423 Locked
85    trait_fn!(ok_or_locked);
86    // 424 Failed Dependency
87    trait_fn!(ok_or_failed_dependency);
88
89    // 426 Upgrade Required
90    trait_fn!(ok_or_upgrade_required);
91
92    // 428 Precondition Required
93    trait_fn!(ok_or_precondition_required);
94    // 429 Too Many Requests
95    trait_fn!(ok_or_too_many_requests);
96
97    // 431 Request Header Fields Too Large
98    trait_fn!(ok_or_request_header_fields_too_large);
99
100    // 451 Unavailable For Legal Reasons
101    trait_fn!(ok_or_unavailable_for_legal_reasons);
102
103    // 500 Internal Server Error
104    trait_fn!(ok_or_internal_server_error);
105    // 501 Not Implemented
106    trait_fn!(ok_or_not_implemented);
107    // 502 Bad Gateway
108    trait_fn!(ok_or_bad_gateway);
109    // 503 Service Unavailable
110    trait_fn!(ok_or_service_unavailable);
111    // 504 Gateway Timeout
112    trait_fn!(ok_or_gateway_timeout);
113    // 505 HTTP Version Not Supported
114    trait_fn!(ok_or_http_version_not_supported);
115    // 506 Variant Also Negotiates
116    trait_fn!(ok_or_variant_also_negotiates);
117    // 507 Insufficient Storage
118    trait_fn!(ok_or_insufficient_storage);
119    // 508 Loop Detected
120    trait_fn!(ok_or_loop_detected);
121
122    // 510 Not Extended
123    trait_fn!(ok_or_not_extended);
124    // 511 Network Authentication Required
125    trait_fn!(ok_or_network_authentication_required);
126}
127impl<T> OptionExt<T> for Option<T> {
128    impl_fn!(ok_or_bad_request, BAD_REQUEST);
129    impl_fn!(ok_or_unauthorized, UNAUTHORIZED);
130    impl_fn!(ok_or_payment_required, PAYMENT_REQUIRED);
131    impl_fn!(ok_or_forbidden, FORBIDDEN);
132    impl_fn!(ok_or_not_found, NOT_FOUND);
133    impl_fn!(ok_or_method_not_allowed, METHOD_NOT_ALLOWED);
134    impl_fn!(ok_or_not_acceptable, NOT_ACCEPTABLE);
135    impl_fn!(
136        ok_or_proxy_authentication_required,
137        PROXY_AUTHENTICATION_REQUIRED
138    );
139    impl_fn!(ok_or_request_timeout, REQUEST_TIMEOUT);
140    impl_fn!(ok_or_conflict, CONFLICT);
141    impl_fn!(ok_or_gone, GONE);
142    impl_fn!(ok_or_length_required, LENGTH_REQUIRED);
143    impl_fn!(ok_or_precondition_failed, PRECONDITION_FAILED);
144    impl_fn!(ok_or_payload_too_large, PAYLOAD_TOO_LARGE);
145    impl_fn!(ok_or_uri_too_long, URI_TOO_LONG);
146    impl_fn!(ok_or_unsupported_media_type, UNSUPPORTED_MEDIA_TYPE);
147    impl_fn!(ok_or_range_not_satisfiable, RANGE_NOT_SATISFIABLE);
148    impl_fn!(ok_or_expectation_failed, EXPECTATION_FAILED);
149    impl_fn!(ok_or_im_a_teapot, IM_A_TEAPOT);
150
151    impl_fn!(ok_or_misdirected_request, MISDIRECTED_REQUEST);
152    impl_fn!(ok_or_unprocessable_entity, UNPROCESSABLE_ENTITY);
153    impl_fn!(ok_or_locked, LOCKED);
154    impl_fn!(ok_or_failed_dependency, FAILED_DEPENDENCY);
155
156    impl_fn!(ok_or_upgrade_required, UPGRADE_REQUIRED);
157
158    impl_fn!(ok_or_precondition_required, PRECONDITION_REQUIRED);
159    impl_fn!(ok_or_too_many_requests, TOO_MANY_REQUESTS);
160
161    impl_fn!(
162        ok_or_request_header_fields_too_large,
163        REQUEST_HEADER_FIELDS_TOO_LARGE
164    );
165
166    impl_fn!(
167        ok_or_unavailable_for_legal_reasons,
168        UNAVAILABLE_FOR_LEGAL_REASONS
169    );
170
171    impl_fn!(ok_or_internal_server_error, INTERNAL_SERVER_ERROR);
172    impl_fn!(ok_or_not_implemented, NOT_IMPLEMENTED);
173    impl_fn!(ok_or_bad_gateway, BAD_GATEWAY);
174    impl_fn!(ok_or_service_unavailable, SERVICE_UNAVAILABLE);
175    impl_fn!(ok_or_gateway_timeout, GATEWAY_TIMEOUT);
176    impl_fn!(ok_or_http_version_not_supported, HTTP_VERSION_NOT_SUPPORTED);
177    impl_fn!(ok_or_variant_also_negotiates, VARIANT_ALSO_NEGOTIATES);
178    impl_fn!(ok_or_insufficient_storage, INSUFFICIENT_STORAGE);
179    impl_fn!(ok_or_loop_detected, LOOP_DETECTED);
180
181    impl_fn!(ok_or_not_extended, NOT_EXTENDED);
182    impl_fn!(
183        ok_or_network_authentication_required,
184        NETWORK_AUTHENTICATION_REQUIRED
185    );
186}
187
188impl error::Error for StatusError {
189    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
190        None
191    }
192}
193
194impl fmt::Display for StatusError {
195    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196        f.write_str(&self.context)
197    }
198}
199
200impl HttpError for StatusError {
201    fn status_code(&self) -> StatusCode {
202        self.status
203    }
204
205    #[cfg(feature = "tracing")]
206    fn span(&self) -> Option<&tracing::Span> {
207        Some(&self.span)
208    }
209}