1use axum::{
2 http::StatusCode,
3 response::{IntoResponse, Response},
4};
5use type_sets::Contains;
6
7pub type ApiResult<T, S> = Result<T, ApiResponse<S>>;
8
9pub trait WrapsResponse: Sized {
10 const STATUS_CODE: StatusCode;
12
13 type Inner;
15
16 type Pure: WrapsResponse<Inner = ()>;
18
19 fn into_inner(self) -> Self::Inner;
21
22 fn into_set<E>(self) -> ApiResponse<E>
25 where
26 Self::Inner: IntoResponse,
27 E: Contains<Self>,
28 {
29 ApiResponse::new(self)
30 }
31}
32
33pub struct ApiResponse<S> {
34 response: Response,
35 code: StatusCode,
36 _marker: std::marker::PhantomData<fn() -> S>,
37}
38
39impl<S> ApiResponse<S> {
40 pub fn new<T>(wrapper: T) -> Self
41 where
42 S: Contains<T>,
43 T: WrapsResponse<Inner: IntoResponse>,
44 {
45 Self {
46 response: wrapper.into_inner().into_response(),
47 code: T::STATUS_CODE,
48 _marker: std::marker::PhantomData,
49 }
50 }
51}
52
53impl<S> IntoResponse for ApiResponse<S> {
54 fn into_response(self) -> Response {
55 (self.code, self.response).into_response()
56 }
57}
58
59macro_rules! impl_operation_output {
60 ($($n:tt => ($($E:ident),*)),+ $(,)?) => {
61 $(
62 #[cfg(feature = "aide")]
63 impl<$($E),*> aide::OperationOutput for ApiResponse<($($E,)*)>
64 where
65 $(
66 $E: WrapsResponse<Inner: aide::OperationOutput>,
67 )*
68 {
69 type Inner = (StatusCode, Response);
70
71 fn operation_response(
72 _ctx: &mut aide::generate::GenContext,
73 _operation: &mut aide::openapi::Operation,
74 ) -> Option<aide::openapi::Response> {
75 None
76 }
77
78 fn inferred_responses(
79 ctx: &mut aide::generate::GenContext,
80 operation: &mut aide::openapi::Operation,
81 ) -> Vec<(Option<u16>, aide::openapi::Response)> {
82 vec![
83 $((
84 Some($E::STATUS_CODE.as_u16()),
85 <$E::Inner as aide::OperationOutput>
86 ::operation_response(ctx, operation)
87 .unwrap_or_default(),
88 )),*
89 ]
90 }
91 }
92 )+
93 };
94}
95
96impl_operation_output!(
97 0 => (),
98 1 => (E1),
99 2 => (E1, E2),
100 3 => (E1, E2, E3),
101 4 => (E1, E2, E3, E4),
102 5 => (E1, E2, E3, E4, E5),
103 6 => (E1, E2, E3, E4, E5, E6),
104 7 => (E1, E2, E3, E4, E5, E6, E7),
105 8 => (E1, E2, E3, E4, E5, E6, E7, E8),
106);
107
108pub mod codes;