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: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 pub fn body_text(&self) -> String {
64 $body.into()
65 }
66
67 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 pub fn body_text(&self) -> String {
121 format!(concat!($body, ": {}"), self.0).into()
122 }
123
124 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#[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 pub fn body_text(&self) -> String {
178 match self {
179 $(
180 Self::$variant(inner) => inner.body_text(),
181 )+
182 }
183 }
184
185 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#[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 #[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}