1use std::{fmt, marker::PhantomData};
2
3use crate::{IntoService, IntoServiceFactory, Service, ServiceCtx, ServiceFactory};
4
5#[inline]
6pub fn fn_service<F, Req, Res, Err, Cfg>(f: F) -> FnServiceFactory<F, Req, Res, Err, Cfg>
8where
9 F: AsyncFn(Req) -> Result<Res, Err> + Clone,
10{
11 FnServiceFactory::new(f)
12}
13
14#[inline]
15pub fn fn_factory<F, Srv, Req, Err>(f: F) -> FnServiceNoConfig<F, Srv, Req, Err>
51where
52 F: AsyncFn() -> Result<Srv, Err>,
53 Srv: Service<Req>,
54{
55 FnServiceNoConfig::new(f)
56}
57
58#[inline]
59pub fn fn_factory_with_config<F, Cfg, Srv, Req, Err>(
90 f: F,
91) -> FnServiceConfig<F, Cfg, Srv, Req, Err>
92where
93 F: AsyncFn(Cfg) -> Result<Srv, Err>,
94 Srv: Service<Req>,
95{
96 FnServiceConfig { f, _t: PhantomData }
97}
98
99pub struct FnService<F, Req> {
100 f: F,
101 _t: PhantomData<Req>,
102}
103
104impl<F, Req> Clone for FnService<F, Req>
105where
106 F: Clone,
107{
108 fn clone(&self) -> Self {
109 Self {
110 f: self.f.clone(),
111 _t: PhantomData,
112 }
113 }
114}
115
116impl<F, Req> fmt::Debug for FnService<F, Req> {
117 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118 f.debug_struct("FnService")
119 .field("f", &std::any::type_name::<F>())
120 .finish()
121 }
122}
123
124impl<F, Req, Res, Err> Service<Req> for FnService<F, Req>
125where
126 F: AsyncFn(Req) -> Result<Res, Err>,
127{
128 type Response = Res;
129 type Error = Err;
130
131 #[inline]
132 async fn call(&self, req: Req, _: ServiceCtx<'_, Self>) -> Result<Res, Err> {
133 (self.f)(req).await
134 }
135}
136
137impl<F, Req, Res, Err> IntoService<FnService<F, Req>, Req> for F
138where
139 F: AsyncFn(Req) -> Result<Res, Err>,
140{
141 #[inline]
142 fn into_service(self) -> FnService<F, Req> {
143 FnService {
144 f: self,
145 _t: PhantomData,
146 }
147 }
148}
149
150pub struct FnServiceFactory<F, Req, Res, Err, Cfg>
151where
152 F: AsyncFn(Req) -> Result<Res, Err>,
153{
154 f: F,
155 _t: PhantomData<(Req, Cfg)>,
156}
157
158impl<F, Req, Res, Err, Cfg> FnServiceFactory<F, Req, Res, Err, Cfg>
159where
160 F: AsyncFn(Req) -> Result<Res, Err> + Clone,
161{
162 fn new(f: F) -> Self {
163 FnServiceFactory { f, _t: PhantomData }
164 }
165}
166
167impl<F, Req, Res, Err, Cfg> Clone for FnServiceFactory<F, Req, Res, Err, Cfg>
168where
169 F: AsyncFn(Req) -> Result<Res, Err> + Clone,
170{
171 #[inline]
172 fn clone(&self) -> Self {
173 Self {
174 f: self.f.clone(),
175 _t: PhantomData,
176 }
177 }
178}
179
180impl<F, Req, Res, Err, Cfg> fmt::Debug for FnServiceFactory<F, Req, Res, Err, Cfg>
181where
182 F: AsyncFn(Req) -> Result<Res, Err>,
183{
184 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185 f.debug_struct("FnServiceFactory")
186 .field("f", &std::any::type_name::<F>())
187 .finish()
188 }
189}
190
191impl<F, Req, Res, Err> Service<Req> for FnServiceFactory<F, Req, Res, Err, ()>
192where
193 F: AsyncFn(Req) -> Result<Res, Err>,
194{
195 type Response = Res;
196 type Error = Err;
197
198 #[inline]
199 async fn call(&self, req: Req, _: ServiceCtx<'_, Self>) -> Result<Res, Err> {
200 (self.f)(req).await
201 }
202}
203
204impl<F, Req, Res, Err, Cfg> ServiceFactory<Req, Cfg>
205 for FnServiceFactory<F, Req, Res, Err, Cfg>
206where
207 F: AsyncFn(Req) -> Result<Res, Err> + Clone,
208{
209 type Response = Res;
210 type Error = Err;
211
212 type Service = FnService<F, Req>;
213 type InitError = ();
214
215 #[inline]
216 async fn create(&self, _: Cfg) -> Result<Self::Service, Self::InitError> {
217 Ok(FnService {
218 f: self.f.clone(),
219 _t: PhantomData,
220 })
221 }
222}
223
224impl<F, Req, Res, Err, Cfg>
225 IntoServiceFactory<FnServiceFactory<F, Req, Res, Err, Cfg>, Req, Cfg> for F
226where
227 F: AsyncFn(Req) -> Result<Res, Err> + Clone,
228{
229 #[inline]
230 fn into_factory(self) -> FnServiceFactory<F, Req, Res, Err, Cfg> {
231 FnServiceFactory::new(self)
232 }
233}
234
235pub struct FnServiceConfig<F, Cfg, Srv, Req, Err>
237where
238 F: AsyncFn(Cfg) -> Result<Srv, Err>,
239 Srv: Service<Req>,
240{
241 f: F,
242 _t: PhantomData<(Cfg, Srv, Req, Err)>,
243}
244
245impl<F, Cfg, Srv, Req, Err> Clone for FnServiceConfig<F, Cfg, Srv, Req, Err>
246where
247 F: AsyncFn(Cfg) -> Result<Srv, Err> + Clone,
248 Srv: Service<Req>,
249{
250 #[inline]
251 fn clone(&self) -> Self {
252 FnServiceConfig {
253 f: self.f.clone(),
254 _t: PhantomData,
255 }
256 }
257}
258
259impl<F, Cfg, Srv, Req, Err> fmt::Debug for FnServiceConfig<F, Cfg, Srv, Req, Err>
260where
261 F: AsyncFn(Cfg) -> Result<Srv, Err>,
262 Srv: Service<Req>,
263{
264 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
265 f.debug_struct("FnServiceConfig")
266 .field("f", &std::any::type_name::<F>())
267 .finish()
268 }
269}
270
271impl<F, Cfg, Srv, Req, Err> ServiceFactory<Req, Cfg>
272 for FnServiceConfig<F, Cfg, Srv, Req, Err>
273where
274 F: AsyncFn(Cfg) -> Result<Srv, Err>,
275 Srv: Service<Req>,
276{
277 type Response = Srv::Response;
278 type Error = Srv::Error;
279
280 type Service = Srv;
281 type InitError = Err;
282
283 #[inline]
284 async fn create(&self, cfg: Cfg) -> Result<Self::Service, Self::InitError> {
285 (self.f)(cfg).await
286 }
287}
288
289pub struct FnServiceNoConfig<F, S, Req, E>
291where
292 F: AsyncFn() -> Result<S, E>,
293 S: Service<Req>,
294{
295 f: F,
296 _t: PhantomData<Req>,
297}
298
299impl<F, S, Req, E> FnServiceNoConfig<F, S, Req, E>
300where
301 F: AsyncFn() -> Result<S, E>,
302 S: Service<Req>,
303{
304 fn new(f: F) -> Self {
305 Self { f, _t: PhantomData }
306 }
307}
308
309impl<F, S, Req, E, C> ServiceFactory<Req, C> for FnServiceNoConfig<F, S, Req, E>
310where
311 F: AsyncFn() -> Result<S, E>,
312 S: Service<Req>,
313 C: 'static,
314{
315 type Response = S::Response;
316 type Error = S::Error;
317 type Service = S;
318 type InitError = E;
319
320 #[inline]
321 async fn create(&self, _: C) -> Result<S, E> {
322 (self.f)().await
323 }
324}
325
326impl<F, S, Req, E> Clone for FnServiceNoConfig<F, S, Req, E>
327where
328 F: AsyncFn() -> Result<S, E> + Clone,
329 S: Service<Req>,
330{
331 #[inline]
332 fn clone(&self) -> Self {
333 Self::new(self.f.clone())
334 }
335}
336
337impl<F, S, Req, E> fmt::Debug for FnServiceNoConfig<F, S, Req, E>
338where
339 F: AsyncFn() -> Result<S, E>,
340 S: Service<Req>,
341{
342 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
343 f.debug_struct("FnServiceNoConfig")
344 .field("f", &std::any::type_name::<F>())
345 .finish()
346 }
347}
348
349#[cfg(test)]
350mod tests {
351 use ntex_util::future::lazy;
352 use std::task::Poll;
353
354 use super::*;
355 use crate::Pipeline;
356
357 #[ntex::test]
358 async fn test_fn_service() {
359 let new_srv = fn_service(async |()| Ok::<_, ()>("srv")).clone();
360 let _ = format!("{:?}", new_srv);
361
362 let srv = Pipeline::new(new_srv.create(()).await.unwrap()).bind();
363 let res = srv.call(()).await;
364 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
365 assert!(res.is_ok());
366 assert_eq!(res.unwrap(), "srv");
367 let _ = format!("{:?}", srv);
368
369 let srv2 = Pipeline::new(new_srv.clone()).bind();
370 let res = srv2.call(()).await;
371 assert!(res.is_ok());
372 assert_eq!(res.unwrap(), "srv");
373 let _ = format!("{:?}", srv2);
374
375 assert_eq!(lazy(|cx| srv2.poll_shutdown(cx)).await, Poll::Ready(()));
376 }
377
378 #[ntex::test]
379 async fn test_fn_service_comp() {
380 let new_srv = fn_service(|()| async { Ok::<_, ()>("srv") }).clone();
381 let _ = format!("{:?}", new_srv);
382
383 let srv = Pipeline::new(new_srv.create(()).await.unwrap()).bind();
384 let res = srv.call(()).await;
385 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
386 assert!(res.is_ok());
387 assert_eq!(res.unwrap(), "srv");
388 let _ = format!("{:?}", srv);
389
390 let srv2 = Pipeline::new(new_srv.clone()).bind();
391 let res = srv2.call(()).await;
392 assert!(res.is_ok());
393 assert_eq!(res.unwrap(), "srv");
394 let _ = format!("{:?}", srv2);
395
396 assert_eq!(lazy(|cx| srv2.poll_shutdown(cx)).await, Poll::Ready(()));
397 }
398
399 #[ntex::test]
400 async fn test_fn_service_service() {
401 let srv = Pipeline::new(
402 fn_service(|()| async { Ok::<_, ()>("srv") })
403 .clone()
404 .create(&())
405 .await
406 .unwrap()
407 .clone(),
408 )
409 .bind();
410
411 let res = srv.call(()).await;
412 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
413 assert!(res.is_ok());
414 assert_eq!(res.unwrap(), "srv");
415 assert_eq!(lazy(|cx| srv.poll_shutdown(cx)).await, Poll::Ready(()));
416 }
417
418 #[ntex::test]
419 async fn test_fn_service_with_config() {
420 let new_srv = fn_factory_with_config(|cfg: &usize| {
421 let cfg = *cfg;
422 async move {
423 Ok::<_, ()>(fn_service(
424 move |()| async move { Ok::<_, ()>(("srv", cfg)) },
425 ))
426 }
427 })
428 .clone();
429
430 let srv = Pipeline::new(new_srv.create(&1).await.unwrap()).bind();
431 let res = srv.call(()).await;
432 assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
433 assert!(res.is_ok());
434 assert_eq!(res.unwrap(), ("srv", 1));
435 }
436}