axum_core/
macros.rs

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