1#[cfg(feature = "tracing")]
3#[doc(hidden)]
4#[macro_export]
5macro_rules! __log_rejection {
6 (
7 rejection_type = $ty:ident,
8 body_text = $body_text:expr,
9 status = $status:expr,
10 ) => {
11 {
12 $crate::__private::tracing::event!(
13 target: "axum::rejection",
14 $crate::__private::tracing::Level::TRACE,
15 status = $status.as_u16(),
16 body = $body_text,
17 rejection_type = ::std::any::type_name::<$ty>(),
18 "rejecting request",
19 );
20 }
21 };
22}
23
24#[cfg(not(feature = "tracing"))]
25#[doc(hidden)]
26#[macro_export]
27macro_rules! __log_rejection {
28 (
29 rejection_type = $ty:ident,
30 body_text = $body_text:expr,
31 status = $status:expr,
32 ) => {};
33}
34
35#[doc(hidden)]
37#[macro_export]
38macro_rules! __define_rejection {
39 (
40 #[status = $status:ident]
41 #[body = $body:literal]
42 $(#[$m:meta])*
43 pub struct $name:ident;
44 ) => {
45 $(#[$m])*
46 #[derive(Debug)]
47 #[non_exhaustive]
48 pub struct $name;
49
50 impl $name {
51 pub fn body_text(&self) -> String {
53 self.to_string()
54 }
55
56 pub fn status(&self) -> http::StatusCode {
58 http::StatusCode::$status
59 }
60 }
61
62 impl $crate::response::IntoResponse for $name {
63 fn into_response(self) -> $crate::response::Response {
64 let status = self.status();
65
66 $crate::__log_rejection!(
67 rejection_type = $name,
68 body_text = $body,
69 status = status,
70 );
71 (status, $body).into_response()
72 }
73 }
74
75 impl std::fmt::Display for $name {
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 write!(f, "{}", $body)
78 }
79 }
80
81 impl std::error::Error for $name {}
82
83 impl Default for $name {
84 fn default() -> Self {
85 Self
86 }
87 }
88 };
89
90 (
91 #[status = $status:ident]
92 #[body = $body:literal]
93 $(#[$m:meta])*
94 pub struct $name:ident (Error);
95 ) => {
96 $(#[$m])*
97 #[derive(Debug)]
98 pub struct $name(pub(crate) $crate::Error);
99
100 impl $name {
101 pub(crate) fn from_err<E>(err: E) -> Self
102 where
103 E: Into<$crate::BoxError>,
104 {
105 Self($crate::Error::new(err))
106 }
107
108 pub fn body_text(&self) -> String {
110 self.to_string()
111 }
112
113 pub fn status(&self) -> http::StatusCode {
115 http::StatusCode::$status
116 }
117 }
118
119 impl $crate::response::IntoResponse for $name {
120 fn into_response(self) -> $crate::response::Response {
121 let status = self.status();
122 let body_text = self.body_text();
123
124 $crate::__log_rejection!(
125 rejection_type = $name,
126 body_text = body_text,
127 status = status,
128 );
129 (status, body_text).into_response()
130 }
131 }
132
133 impl std::fmt::Display for $name {
134 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
135 f.write_str($body)?;
136 f.write_str(": ")?;
137 self.0.fmt(f)
138 }
139 }
140
141 impl std::error::Error for $name {
142 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
143 Some(&self.0)
144 }
145 }
146 };
147}
148
149#[doc(hidden)]
151#[macro_export]
152macro_rules! __composite_rejection {
153 (
154 $(#[$m:meta])*
155 pub enum $name:ident {
156 $($variant:ident),+
157 $(,)?
158 }
159 ) => {
160 $(#[$m])*
161 #[derive(Debug)]
162 #[non_exhaustive]
163 pub enum $name {
164 $(
165 #[allow(missing_docs)]
166 $variant($variant)
167 ),+
168 }
169
170 impl $crate::response::IntoResponse for $name {
171 fn into_response(self) -> $crate::response::Response {
172 match self {
173 $(
174 Self::$variant(inner) => inner.into_response(),
175 )+
176 }
177 }
178 }
179
180 impl $name {
181 pub fn body_text(&self) -> String {
183 match self {
184 $(
185 Self::$variant(inner) => inner.body_text(),
186 )+
187 }
188 }
189
190 pub fn status(&self) -> http::StatusCode {
192 match self {
193 $(
194 Self::$variant(inner) => inner.status(),
195 )+
196 }
197 }
198 }
199
200 $(
201 impl From<$variant> for $name {
202 fn from(inner: $variant) -> Self {
203 Self::$variant(inner)
204 }
205 }
206 )+
207
208 impl std::fmt::Display for $name {
209 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
210 match self {
211 $(
212 Self::$variant(inner) => write!(f, "{inner}"),
213 )+
214 }
215 }
216 }
217
218 impl std::error::Error for $name {
219 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
220 match self {
221 $(
222 Self::$variant(inner) => inner.source(),
223 )+
224 }
225 }
226 }
227 };
228}
229
230#[rustfmt::skip]
231macro_rules! all_the_tuples {
232 ($name:ident) => {
233 $name!([], T1);
234 $name!([T1], T2);
235 $name!([T1, T2], T3);
236 $name!([T1, T2, T3], T4);
237 $name!([T1, T2, T3, T4], T5);
238 $name!([T1, T2, T3, T4, T5], T6);
239 $name!([T1, T2, T3, T4, T5, T6], T7);
240 $name!([T1, T2, T3, T4, T5, T6, T7], T8);
241 $name!([T1, T2, T3, T4, T5, T6, T7, T8], T9);
242 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9], T10);
243 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], T11);
244 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], T12);
245 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], T13);
246 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], T14);
247 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], T15);
248 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], T16);
249 };
250}
251
252macro_rules! all_the_tuples_no_last_special_case {
253 ($name:ident) => {
254 $name!(T1);
255 $name!(T1, T2);
256 $name!(T1, T2, T3);
257 $name!(T1, T2, T3, T4);
258 $name!(T1, T2, T3, T4, T5);
259 $name!(T1, T2, T3, T4, T5, T6);
260 $name!(T1, T2, T3, T4, T5, T6, T7);
261 $name!(T1, T2, T3, T4, T5, T6, T7, T8);
262 $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9);
263 $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
264 $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
265 $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
266 $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13);
267 $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14);
268 $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15);
269 $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16);
270 };
271}
272
273#[doc(hidden)]
275#[macro_export]
276macro_rules! __impl_deref {
277 ($ident:ident) => {
278 impl<T> std::ops::Deref for $ident<T> {
279 type Target = T;
280
281 #[inline]
282 fn deref(&self) -> &Self::Target {
283 &self.0
284 }
285 }
286
287 impl<T> std::ops::DerefMut for $ident<T> {
288 #[inline]
289 fn deref_mut(&mut self) -> &mut Self::Target {
290 &mut self.0
291 }
292 }
293 };
294
295 ($ident:ident: $ty:ty) => {
296 impl std::ops::Deref for $ident {
297 type Target = $ty;
298
299 #[inline]
300 fn deref(&self) -> &Self::Target {
301 &self.0
302 }
303 }
304
305 impl std::ops::DerefMut for $ident {
306 #[inline]
307 fn deref_mut(&mut self) -> &mut Self::Target {
308 &mut self.0
309 }
310 }
311 };
312}
313
314#[cfg(test)]
315mod composite_rejection_tests {
316 use self::defs::*;
317 use crate::Error;
318 use std::error::Error as _;
319
320 #[allow(dead_code, unreachable_pub)]
321 mod defs {
322 __define_rejection! {
323 #[status = BAD_REQUEST]
324 #[body = "error message 1"]
325 pub struct Inner1;
326 }
327 __define_rejection! {
328 #[status = BAD_REQUEST]
329 #[body = "error message 2"]
330 pub struct Inner2(Error);
331 }
332 __composite_rejection! {
333 pub enum Outer { Inner1, Inner2 }
334 }
335 }
336
337 #[test]
342 fn source_gives_inner_source() {
343 let rejection = Outer::Inner1(Inner1);
344 assert!(rejection.source().is_none());
345
346 let msg = "hello world";
347 let rejection = Outer::Inner2(Inner2(Error::new(msg)));
348 assert_eq!(rejection.source().unwrap().to_string(), msg);
349 }
350}