1use core::marker::PhantomData;
4
5use crate::service::Service;
6
7#[doc(hidden)]
8mod marker {
9 pub struct EraseReqBody;
10 pub struct EraseResBody;
11
12 pub struct EraseErr;
13}
14
15use marker::*;
16
17pub struct TypeEraser<M>(PhantomData<M>);
62
63impl<M> Clone for TypeEraser<M> {
64 fn clone(&self) -> Self {
65 Self(PhantomData)
66 }
67}
68
69impl TypeEraser<EraseReqBody> {
70 pub const fn request_body() -> Self {
74 TypeEraser(PhantomData)
75 }
76}
77
78impl TypeEraser<EraseResBody> {
79 pub const fn response_body() -> Self {
83 TypeEraser(PhantomData)
84 }
85}
86
87impl TypeEraser<EraseErr> {
88 pub const fn error() -> Self {
92 TypeEraser(PhantomData)
93 }
94}
95
96impl<M, S, E> Service<Result<S, E>> for TypeEraser<M> {
97 type Response = service::EraserService<M, S>;
98 type Error = E;
99
100 async fn call(&self, res: Result<S, E>) -> Result<Self::Response, Self::Error> {
101 res.map(|service| service::EraserService {
102 service,
103 _erase: PhantomData,
104 })
105 }
106}
107
108mod service {
109 use core::cell::RefCell;
110
111 use crate::{
112 WebContext, body::BodyStream, body::ResponseBody, error::Error, http::WebResponse, service::ready::ReadyService,
113 };
114
115 use super::*;
116
117 pub struct EraserService<M, S> {
118 pub(super) service: S,
119 pub(super) _erase: PhantomData<M>,
120 }
121
122 impl<'r, S, C, ReqB, ResB, Err> Service<WebContext<'r, C, ReqB>> for EraserService<EraseReqBody, S>
123 where
124 S: for<'rs> Service<WebContext<'rs, C>, Response = WebResponse<ResB>, Error = Err>,
125 ReqB: BodyStream + Default + 'static,
126 ResB: BodyStream + 'static,
127 {
128 type Response = WebResponse;
129 type Error = Err;
130
131 async fn call(&self, mut ctx: WebContext<'r, C, ReqB>) -> Result<Self::Response, Self::Error> {
132 let body = ctx.take_body_mut();
133 let body = crate::body::downcast_body(body);
134 let mut body = RefCell::new(body);
135 let WebContext { req, ctx, .. } = ctx;
136 let res = self.service.call(WebContext::new(req, &mut body, ctx)).await?;
137 Ok(res.map(ResponseBody::boxed))
138 }
139 }
140
141 impl<S, Req, ResB> Service<Req> for EraserService<EraseResBody, S>
142 where
143 S: Service<Req, Response = WebResponse<ResB>>,
144 ResB: BodyStream + 'static,
145 {
146 type Response = WebResponse;
147 type Error = S::Error;
148
149 #[inline]
150 async fn call(&self, req: Req) -> Result<Self::Response, Self::Error> {
151 let res = self.service.call(req).await?;
152 Ok(res.map(ResponseBody::boxed))
153 }
154 }
155
156 impl<'r, C, B, S> Service<WebContext<'r, C, B>> for EraserService<EraseErr, S>
157 where
158 S: Service<WebContext<'r, C, B>>,
159 S::Error: Into<Error>,
160 {
161 type Response = S::Response;
162 type Error = Error;
163
164 #[inline]
165 async fn call(&self, ctx: WebContext<'r, C, B>) -> Result<Self::Response, Self::Error> {
166 self.service.call(ctx).await.map_err(Into::into)
167 }
168 }
169
170 impl<M, S> ReadyService for EraserService<M, S>
171 where
172 S: ReadyService,
173 {
174 type Ready = S::Ready;
175
176 #[inline]
177 async fn ready(&self) -> Self::Ready {
178 self.service.ready().await
179 }
180 }
181}
182
183#[cfg(test)]
184mod test {
185 use xitca_unsafe_collection::futures::NowOrPanic;
186
187 use crate::{
188 App, WebContext,
189 body::Full,
190 bytes::Bytes,
191 error::Error,
192 handler::handler_service,
193 http::{Request, StatusCode, WebResponse},
194 middleware::Group,
195 service::ServiceExt,
196 };
197
198 use super::*;
199
200 async fn handler(_: &WebContext<'_>) -> &'static str {
201 "996"
202 }
203
204 async fn map_body<S, C, B, Err>(_: &S, _: WebContext<'_, C, B>) -> Result<WebResponse<Full<Bytes>>, Err>
205 where
206 S: for<'r> Service<WebContext<'r, C, B>, Response = WebResponse, Error = Err>,
207 {
208 Ok(WebResponse::new(Full::new(Bytes::new())))
209 }
210
211 async fn middleware_fn<S, C, B, Err>(s: &S, ctx: WebContext<'_, C, B>) -> Result<WebResponse, Err>
212 where
213 S: for<'r> Service<WebContext<'r, C, B>, Response = WebResponse, Error = Err>,
214 {
215 s.call(ctx).await
216 }
217
218 #[test]
219 fn erase_body() {
220 let _ = App::new()
221 .at("/", handler_service(handler).enclosed_fn(map_body))
223 .enclosed(TypeEraser::response_body())
225 .enclosed_fn(middleware_fn)
227 .finish()
228 .call(())
229 .now_or_panic()
230 .unwrap()
231 .call(Request::default())
232 .now_or_panic()
233 .unwrap();
234 }
235
236 #[test]
237 fn erase_error() {
238 async fn middleware_fn<S, C, B, Err>(s: &S, ctx: WebContext<'_, C, B>) -> Result<WebResponse, StatusCode>
239 where
240 S: for<'r> Service<WebContext<'r, C, B>, Response = WebResponse, Error = Err>,
241 {
242 s.call(ctx).await.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)
243 }
244
245 async fn middleware_fn2<S, C, B>(s: &S, ctx: WebContext<'_, C, B>) -> Result<WebResponse, Error>
246 where
247 S: for<'r> Service<WebContext<'r, C, B>, Response = WebResponse, Error = Error>,
248 {
249 s.call(ctx).await
250 }
251
252 let _ = App::new()
253 .at("/", handler_service(handler).enclosed(TypeEraser::error()))
255 .enclosed(
256 Group::new()
257 .enclosed_fn(middleware_fn)
258 .enclosed(TypeEraser::error())
259 .enclosed_fn(middleware_fn2),
260 )
261 .finish()
262 .call(())
263 .now_or_panic()
264 .unwrap()
265 .call(Request::default())
266 .now_or_panic()
267 .unwrap();
268 }
269}