1use alloc::borrow::Cow;
2use alloc::boxed::Box;
3#[cfg(feature = "openapi")]
4use alloc::collections::BTreeMap;
5use alloc::string::String;
6use alloc::vec::Vec;
7use core::convert::Infallible;
8use core::pin::Pin;
9use http_kit::error::BoxHttpError;
10use http_kit::header::{HeaderMap, HeaderName, HeaderValue};
11use http_kit::HttpError;
12use http_kit::{
13 utils::{AsyncBufRead, ByteStr, Bytes},
14 Body, Request, Response,
15};
16
17#[cfg(feature = "openapi")]
18use crate::openapi::{ResponseSchema, SchemaRef};
19use crate::Error;
20
21pub trait Responder: Sized + Send + Sync + 'static {
23 type Error: HttpError;
25 fn respond_to(self, _request: &Request, response: &mut Response) -> Result<(), Self::Error>;
31
32 #[cfg(feature = "openapi")]
34 #[must_use]
35 fn openapi() -> Option<Vec<ResponseSchema>> {
36 None
37 }
38
39 #[cfg(feature = "openapi")]
41 fn register_openapi_schemas(_defs: &mut BTreeMap<String, SchemaRef>) {}
42}
43
44macro_rules! impl_tuple_responder {
45 ($($ty:ident),*) => {
46 const _:() = {
47 #[doc(hidden)]
49 pub enum TupleResponderError<$($ty:Responder),*> {
50 $($ty(<$ty as Responder>::Error),)*
51 }
52
53 impl <$($ty: Responder),*>core::fmt::Display for TupleResponderError<$($ty),*> {
54 #[allow(unused_variables)]
55 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
56 match self {
57 $(TupleResponderError::$ty(e) => write!(f,"{}",e),)*
58 #[allow(unreachable_patterns)]
59 _ => unreachable!(),
60 }
61 }
62 }
63
64 impl<$($ty: Responder),*>core::fmt::Debug for TupleResponderError<$($ty),*> {
65 #[allow(unused_variables)]
66 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
67 match self {
68 $(TupleResponderError::$ty(e) => write!(f,"{:?}",e),)*
69 #[allow(unreachable_patterns)]
70 _ => unreachable!(),
71 }
72 }
73 }
74
75 impl <$($ty: Responder),*>core::error::Error for TupleResponderError<$($ty),*> {}
76
77 impl<$($ty: Responder),*>http_kit::HttpError for TupleResponderError<$($ty),*> {
78 fn status(&self) -> http_kit::StatusCode { {
79 match self {
80 $(TupleResponderError::$ty(e) => e.status(),)*
81 #[allow(unreachable_patterns)]
82 _ => unreachable!(),
83 }
84 } }
85 }
86
87
88 #[allow(non_snake_case)]
89 #[allow(unused_variables)]
90 impl <$($ty:Responder,)*>Responder for ($($ty,)*){
91 type Error=TupleResponderError<$($ty),*>;
92 fn respond_to(self, request: &Request,response:&mut Response) -> Result<(),Self::Error>{
93 let ($($ty,)*)=self;
94 $($ty.respond_to(request,response).map_err(|e| TupleResponderError::$ty(e))?;)*
95 Ok(())
96 }
97
98 #[cfg(feature = "openapi")]
99 fn openapi() -> Option<Vec<ResponseSchema>> {
100 #[allow(unused_mut)]
101 let mut schemas = Vec::new();
102 $(
103 if let Some(mut inner) = <$ty as Responder>::openapi() {
104 schemas.append(&mut inner);
105 }
106 )*
107 if schemas.is_empty() { None } else { Some(schemas) }
108 }
109
110 #[cfg(feature = "openapi")]
111 fn register_openapi_schemas(defs: &mut BTreeMap<String, SchemaRef>) {
112 $(
113 <$ty as Responder>::register_openapi_schemas(defs);
114 )*
115 }
116 }
117 };
118 };
119}
120
121tuples!(impl_tuple_responder);
122
123impl_base_responder![Bytes, Vec<u8>, Body, &'static [u8], Cow<'static, [u8]>];
124
125impl Responder for Pin<Box<dyn AsyncBufRead + Send + Sync + 'static>> {
126 type Error = core::convert::Infallible;
127 fn respond_to(self, _request: &Request, response: &mut Response) -> Result<(), Self::Error> {
128 *response.body_mut() = Body::from_reader(self, None);
129 Ok(())
130 }
131}
132
133impl_base_utf8_responder![ByteStr, String, &'static str, Cow<'static, str>];
134
135impl Responder for Response {
136 type Error = core::convert::Infallible;
137 fn respond_to(self, _request: &Request, response: &mut Response) -> Result<(), Self::Error> {
138 *response = self;
139 Ok(())
140 }
141
142 #[cfg(feature = "openapi")]
143 fn openapi() -> Option<Vec<ResponseSchema>> {
144 Some(vec![ResponseSchema {
145 status: None,
146 description: None,
147 schema: None,
148 content_type: None,
149 }])
150 }
151}
152
153impl<T: Responder, E: HttpError> Responder for core::result::Result<T, E> {
154 type Error = BoxHttpError;
155 fn respond_to(self, request: &Request, response: &mut Response) -> Result<(), Self::Error> {
156 match self {
157 Ok(responder) => responder
158 .respond_to(request, response)
159 .map_err(|e| Box::new(e) as BoxHttpError),
160 Err(e) => Err(Box::new(e) as BoxHttpError),
161 }
162 }
163
164 #[cfg(feature = "openapi")]
165 fn openapi() -> Option<Vec<ResponseSchema>> {
166 let mut schemas = Vec::new();
167 if let Some(mut inner) = T::openapi() {
168 schemas.append(&mut inner);
169 }
170 schemas.push(ResponseSchema {
171 status: Some(http_kit::StatusCode::SERVICE_UNAVAILABLE),
172 description: None,
173 schema: None,
174 content_type: None,
175 });
176 if schemas.is_empty() {
177 None
178 } else {
179 Some(schemas)
180 }
181 }
182
183 #[cfg(feature = "openapi")]
184 fn register_openapi_schemas(defs: &mut BTreeMap<String, SchemaRef>) {
185 T::register_openapi_schemas(defs);
186 }
187}
188
189impl<T: Responder> Responder for core::result::Result<T, Error> {
190 type Error = BoxHttpError;
191 fn respond_to(self, request: &Request, response: &mut Response) -> Result<(), Self::Error> {
192 match self {
193 Ok(responder) => responder
194 .respond_to(request, response)
195 .map_err(|e| Box::new(e) as BoxHttpError),
196 Err(e) => Err(e.into_boxed_http_error()),
197 }
198 }
199
200 #[cfg(feature = "openapi")]
201 fn openapi() -> Option<Vec<ResponseSchema>> {
202 let mut schemas = Vec::new();
203 if let Some(mut inner) = T::openapi() {
204 schemas.append(&mut inner);
205 }
206 if schemas.is_empty() {
207 None
208 } else {
209 Some(schemas)
210 }
211 }
212
213 #[cfg(feature = "openapi")]
214 fn register_openapi_schemas(defs: &mut BTreeMap<String, SchemaRef>) {
215 T::register_openapi_schemas(defs);
216 }
217}
218
219impl Responder for HeaderMap {
220 type Error = Infallible;
221 fn respond_to(self, _request: &Request, response: &mut Response) -> Result<(), Self::Error> {
222 response.headers_mut().extend(self);
223 Ok(())
224 }
225
226 #[cfg(feature = "openapi")]
227 fn openapi() -> Option<Vec<ResponseSchema>> {
228 Some(vec![ResponseSchema {
229 status: None,
230 description: None,
231 schema: None,
232 content_type: None,
233 }])
234 }
235}
236
237impl Responder for (HeaderName, HeaderValue) {
238 type Error = Infallible;
239 fn respond_to(self, _request: &Request, response: &mut Response) -> Result<(), Self::Error> {
240 let (key, value) = self;
241 response.headers_mut().append(key, value);
242 Ok(())
243 }
244
245 #[cfg(feature = "openapi")]
246 fn openapi() -> Option<Vec<ResponseSchema>> {
247 Some(vec![ResponseSchema {
248 status: None,
249 description: None,
250 schema: None,
251 content_type: None,
252 }])
253 }
254}