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 trait_fn!(bad_request);
36 trait_fn!(unauthorized);
38 trait_fn!(payment_required);
40 trait_fn!(forbidden);
42 trait_fn!(not_found);
44 trait_fn!(method_not_allowed);
46 trait_fn!(not_acceptable);
48 trait_fn!(proxy_authentication_required);
50 trait_fn!(request_timeout);
52 trait_fn!(conflict);
54 trait_fn!(gone);
56 trait_fn!(length_required);
58 trait_fn!(precondition_failed);
60 trait_fn!(payload_too_large);
62 trait_fn!(uri_too_long);
64 trait_fn!(unsupported_media_type);
66 trait_fn!(range_not_satisfiable);
68 trait_fn!(expectation_failed);
70 trait_fn!(im_a_teapot);
72
73 trait_fn!(misdirected_request);
75 trait_fn!(unprocessable_entity);
77 trait_fn!(locked);
79 trait_fn!(failed_dependency);
81
82 trait_fn!(upgrade_required);
84
85 trait_fn!(precondition_required);
87 trait_fn!(too_many_requests);
89
90 trait_fn!(request_header_fields_too_large);
92
93 trait_fn!(unavailable_for_legal_reasons);
95
96 trait_fn!(internal_server_error);
98 trait_fn!(not_implemented);
100 trait_fn!(bad_gateway);
102 trait_fn!(service_unavailable);
104 trait_fn!(gateway_timeout);
106 trait_fn!(http_version_not_supported);
108 trait_fn!(variant_also_negotiates);
110 trait_fn!(insufficient_storage);
112 trait_fn!(loop_detected);
114
115 trait_fn!(not_extended);
117 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}