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 #[must_use]
110 pub fn body_text(&self) -> String {
111 self.to_string()
112 }
113
114 #[must_use]
116 pub fn status(&self) -> http::StatusCode {
117 http::StatusCode::$status
118 }
119 }
120
121 impl $crate::response::IntoResponse for $name {
122 fn into_response(self) -> $crate::response::Response {
123 let status = self.status();
124 let body_text = self.body_text();
125
126 $crate::__log_rejection!(
127 rejection_type = $name,
128 body_text = body_text,
129 status = status,
130 );
131 (status, body_text).into_response()
132 }
133 }
134
135 impl std::fmt::Display for $name {
136 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137 f.write_str($body)?;
138 f.write_str(": ")?;
139 self.0.fmt(f)
140 }
141 }
142
143 impl std::error::Error for $name {
144 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
145 Some(&self.0)
146 }
147 }
148 };
149}
150
151#[doc(hidden)]
153#[macro_export]
154macro_rules! __composite_rejection {
155 (
156 $(#[$m:meta])*
157 pub enum $name:ident {
158 $($variant:ident),+
159 $(,)?
160 }
161 ) => {
162 $(#[$m])*
163 #[derive(Debug)]
164 #[non_exhaustive]
165 pub enum $name {
166 $(
167 #[allow(missing_docs)]
168 $variant($variant)
169 ),+
170 }
171
172 impl $crate::response::IntoResponse for $name {
173 fn into_response(self) -> $crate::response::Response {
174 match self {
175 $(
176 Self::$variant(inner) => inner.into_response(),
177 )+
178 }
179 }
180 }
181
182 impl $name {
183 #[must_use]
185 pub fn body_text(&self) -> String {
186 match self {
187 $(
188 Self::$variant(inner) => inner.body_text(),
189 )+
190 }
191 }
192
193 #[must_use]
195 pub fn status(&self) -> http::StatusCode {
196 match self {
197 $(
198 Self::$variant(inner) => inner.status(),
199 )+
200 }
201 }
202 }
203
204 $(
205 impl From<$variant> for $name {
206 fn from(inner: $variant) -> Self {
207 Self::$variant(inner)
208 }
209 }
210 )+
211
212 impl std::fmt::Display for $name {
213 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
214 match self {
215 $(
216 Self::$variant(inner) => write!(f, "{inner}"),
217 )+
218 }
219 }
220 }
221
222 impl std::error::Error for $name {
223 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
224 match self {
225 $(
226 Self::$variant(inner) => inner.source(),
227 )+
228 }
229 }
230 }
231 };
232}
233
234#[rustfmt::skip]
235macro_rules! all_the_tuples {
236 ($name:ident) => {
237 $name!([], T1);
238 $name!([T1], T2);
239 $name!([T1, T2], T3);
240 $name!([T1, T2, T3], T4);
241 $name!([T1, T2, T3, T4], T5);
242 $name!([T1, T2, T3, T4, T5], T6);
243 $name!([T1, T2, T3, T4, T5, T6], T7);
244 $name!([T1, T2, T3, T4, T5, T6, T7], T8);
245 $name!([T1, T2, T3, T4, T5, T6, T7, T8], T9);
246 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9], T10);
247 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], T11);
248 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], T12);
249 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], T13);
250 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], T14);
251 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], T15);
252 $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], T16);
253 };
254}
255
256macro_rules! all_the_tuples_no_last_special_case {
257 ($name:ident) => {
258 $name!(T1);
259 $name!(T1, T2);
260 $name!(T1, T2, T3);
261 $name!(T1, T2, T3, T4);
262 $name!(T1, T2, T3, T4, T5);
263 $name!(T1, T2, T3, T4, T5, T6);
264 $name!(T1, T2, T3, T4, T5, T6, T7);
265 $name!(T1, T2, T3, T4, T5, T6, T7, T8);
266 $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9);
267 $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
268 $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
269 $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
270 $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13);
271 $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14);
272 $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15);
273 $name!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16);
274 };
275}
276
277#[doc(hidden)]
279#[macro_export]
280macro_rules! __impl_deref {
281 ($ident:ident) => {
282 impl<T> std::ops::Deref for $ident<T> {
283 type Target = T;
284
285 #[inline]
286 fn deref(&self) -> &Self::Target {
287 &self.0
288 }
289 }
290
291 impl<T> std::ops::DerefMut for $ident<T> {
292 #[inline]
293 fn deref_mut(&mut self) -> &mut Self::Target {
294 &mut self.0
295 }
296 }
297 };
298
299 ($ident:ident: $ty:ty) => {
300 impl std::ops::Deref for $ident {
301 type Target = $ty;
302
303 #[inline]
304 fn deref(&self) -> &Self::Target {
305 &self.0
306 }
307 }
308
309 impl std::ops::DerefMut for $ident {
310 #[inline]
311 fn deref_mut(&mut self) -> &mut Self::Target {
312 &mut self.0
313 }
314 }
315 };
316}
317
318#[cfg(test)]
319mod composite_rejection_tests {
320 use self::defs::*;
321 use crate::Error;
322 use std::error::Error as _;
323
324 #[allow(dead_code, unreachable_pub)]
325 mod defs {
326 __define_rejection! {
327 #[status = BAD_REQUEST]
328 #[body = "error message 1"]
329 pub struct Inner1;
330 }
331 __define_rejection! {
332 #[status = BAD_REQUEST]
333 #[body = "error message 2"]
334 pub struct Inner2(Error);
335 }
336 __composite_rejection! {
337 pub enum Outer { Inner1, Inner2 }
338 }
339 }
340
341 #[test]
346 fn source_gives_inner_source() {
347 let rejection = Outer::Inner1(Inner1);
348 assert!(rejection.source().is_none());
349
350 let msg = "hello world";
351 let rejection = Outer::Inner2(Inner2(Error::new(msg)));
352 assert_eq!(rejection.source().unwrap().to_string(), msg);
353 }
354}