http_error/
result_ext.rs

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