Skip to main content

ntex_service/
fn_service.rs

1use std::{convert::Infallible, fmt, marker::PhantomData};
2
3use crate::{Ctx, IntoService, IntoServiceFactory, Service, ServiceFactory};
4
5/// Converts an asynchronous function into a [`Service`].
6#[inline]
7pub fn fn_service<F, Req, Res, Err>(f: F) -> FnService<F, Req, Res, Err>
8where
9    F: AsyncFn(Req) -> Result<Res, Err>,
10{
11    FnService { f, _t: PhantomData }
12}
13
14/// Converts a state-aware asynchronous function into a [`Service`].
15///
16/// This service accesses the pipeline state via the first `&St` parameter.
17#[inline]
18pub fn fn_service_st<F, St, Req, Res, Err>(f: F) -> FnServiceSt<F, St, Req, Res, Err>
19where
20    F: AsyncFn(&St, Req) -> Result<Res, Err>,
21{
22    FnServiceSt { f, _t: PhantomData }
23}
24
25// ====================== FnService =======================
26
27/// A [`Service`] backed by an asynchronous function.
28pub struct FnService<F, Req, Res, Err> {
29    f: F,
30    _t: PhantomData<(Req, Res, Err)>,
31}
32
33impl<F, Req, Res, Err> Clone for FnService<F, Req, Res, Err>
34where
35    F: Clone,
36{
37    fn clone(&self) -> Self {
38        Self {
39            f: self.f.clone(),
40            _t: PhantomData,
41        }
42    }
43}
44
45impl<F, Req, Res, Err> fmt::Debug for FnService<F, Req, Res, Err> {
46    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47        f.debug_struct("FnService")
48            .field("f", &std::any::type_name::<F>())
49            .finish()
50    }
51}
52
53impl<F, St, Req, Res, Err> Service<St, Req> for FnService<F, Req, Res, Err>
54where
55    F: AsyncFn(Req) -> Result<Res, Err>,
56{
57    type Res = Res;
58    type Error = Err;
59
60    #[inline]
61    async fn call(&self, req: Req, _: Ctx<'_, Self, St>) -> Result<Res, Err> {
62        (self.f)(req).await
63    }
64}
65
66impl<F, St, Req, Res, Err> IntoServiceFactory<FnServiceFactory<F, Req, Res, Err>, St, Req>
67    for FnService<F, Req, Res, Err>
68where
69    F: AsyncFn(Req) -> Result<Res, Err> + Clone,
70{
71    #[inline]
72    fn into_factory(self) -> FnServiceFactory<F, Req, Res, Err> {
73        FnServiceFactory {
74            f: self.f,
75            _t: PhantomData,
76        }
77    }
78}
79
80impl<F, St, Req, Res, Err> IntoService<FnService<F, Req, Res, Err>, St, Req> for F
81where
82    F: AsyncFn(Req) -> Result<Res, Err>,
83{
84    #[inline]
85    fn into_service(self) -> FnService<F, Req, Res, Err> {
86        FnService {
87            f: self,
88            _t: PhantomData,
89        }
90    }
91}
92
93/// A state-aware [`Service`] backed by an asynchronous function.
94///
95/// This service accesses the pipeline state via the first `&St` parameter.
96pub struct FnServiceSt<F, St, Req, Res, Err> {
97    f: F,
98    _t: PhantomData<(St, Req, Res, Err)>,
99}
100
101impl<F, St, Req, Res, Err> Clone for FnServiceSt<F, St, Req, Res, Err>
102where
103    F: Clone,
104{
105    fn clone(&self) -> Self {
106        Self {
107            f: self.f.clone(),
108            _t: PhantomData,
109        }
110    }
111}
112
113impl<F, St, Req, Res, Err> fmt::Debug for FnServiceSt<F, St, Req, Res, Err> {
114    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115        f.debug_struct("FnServiceSt")
116            .field("f", &std::any::type_name::<F>())
117            .finish()
118    }
119}
120
121impl<F, St, Req, Res, Err> Service<St, Req> for FnServiceSt<F, St, Req, Res, Err>
122where
123    F: AsyncFn(&St, Req) -> Result<Res, Err>,
124{
125    type Res = Res;
126    type Error = Err;
127
128    #[inline]
129    async fn call(&self, req: Req, ctx: Ctx<'_, Self, St>) -> Result<Res, Err> {
130        (self.f)(ctx.st(), req).await
131    }
132}
133
134impl<F, St, Req, Res, Err> IntoServiceFactory<FnServiceStFactory<F, St, Req, Res, Err>, St, Req>
135    for FnServiceSt<F, St, Req, Res, Err>
136where
137    F: AsyncFn(&St, Req) -> Result<Res, Err> + Clone,
138{
139    #[inline]
140    fn into_factory(self) -> FnServiceStFactory<F, St, Req, Res, Err> {
141        FnServiceStFactory {
142            f: self.f,
143            ph: PhantomData,
144        }
145    }
146}
147
148impl<F, St, Req, Res, Err> IntoService<FnServiceSt<F, St, Req, Res, Err>, St, Req> for F
149where
150    F: AsyncFn(&St, Req) -> Result<Res, Err>,
151{
152    #[inline]
153    fn into_service(self) -> FnServiceSt<F, St, Req, Res, Err> {
154        FnServiceSt {
155            f: self,
156            _t: PhantomData,
157        }
158    }
159}
160
161// ---------------------------- FnServiceFactory ------------------------
162
163/// A service factory backed by a clonable asynchronous service function.
164pub struct FnServiceFactory<F, Req, Res, Err>
165where
166    F: AsyncFn(Req) -> Result<Res, Err> + Clone,
167{
168    f: F,
169    _t: PhantomData<(Req,)>,
170}
171
172impl<F, Req, Res, Err> FnServiceFactory<F, Req, Res, Err>
173where
174    F: AsyncFn(Req) -> Result<Res, Err> + Clone,
175{
176    fn new(f: F) -> Self {
177        FnServiceFactory { f, _t: PhantomData }
178    }
179}
180
181impl<F, Req, Res, Err> Clone for FnServiceFactory<F, Req, Res, Err>
182where
183    F: AsyncFn(Req) -> Result<Res, Err> + Clone,
184{
185    #[inline]
186    fn clone(&self) -> Self {
187        Self {
188            f: self.f.clone(),
189            _t: PhantomData,
190        }
191    }
192}
193
194impl<F, Req, Res, Err> fmt::Debug for FnServiceFactory<F, Req, Res, Err>
195where
196    F: AsyncFn(Req) -> Result<Res, Err> + Clone,
197{
198    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199        f.debug_struct("FnServiceFactory")
200            .field("f", &std::any::type_name::<F>())
201            .finish()
202    }
203}
204
205impl<F, St, Req, Res, Err> ServiceFactory<St, Req> for FnServiceFactory<F, Req, Res, Err>
206where
207    F: AsyncFn(Req) -> Result<Res, Err> + Clone,
208{
209    type Res = Res;
210    type Error = Err;
211
212    type Service = FnService<F, Req, Res, Err>;
213    type InitError = Infallible;
214
215    #[inline]
216    async fn create(&self, _: &St) -> Result<Self::Service, Self::InitError> {
217        Ok(FnService {
218            f: self.f.clone(),
219            _t: PhantomData,
220        })
221    }
222}
223
224impl<St, F, Req, Res, Err> IntoServiceFactory<FnServiceFactory<F, Req, Res, Err>, St, Req> for F
225where
226    F: AsyncFn(Req) -> Result<Res, Err> + Clone,
227{
228    #[inline]
229    fn into_factory(self) -> FnServiceFactory<F, Req, Res, Err> {
230        FnServiceFactory::new(self)
231    }
232}
233
234// ========================= FnServiceStFactory =======================
235
236/// A service factory backed by a clonable, state-aware asynchronous function.
237pub struct FnServiceStFactory<F, St, Req, Res, Err>
238where
239    F: AsyncFn(&St, Req) -> Result<Res, Err> + Clone,
240{
241    f: F,
242    ph: PhantomData<(St, Req, Res, Err)>,
243}
244
245impl<F, St, Req, Res, Err> Clone for FnServiceStFactory<F, St, Req, Res, Err>
246where
247    F: AsyncFn(&St, Req) -> Result<Res, Err> + Clone,
248{
249    #[inline]
250    fn clone(&self) -> Self {
251        Self {
252            f: self.f.clone(),
253            ph: PhantomData,
254        }
255    }
256}
257
258impl<F, St, Req, Res, Err> fmt::Debug for FnServiceStFactory<F, St, Req, Res, Err>
259where
260    F: AsyncFn(&St, Req) -> Result<Res, Err> + Clone,
261{
262    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
263        f.debug_struct("FnServiceStFactory")
264            .field("f", &std::any::type_name::<F>())
265            .finish()
266    }
267}
268
269impl<F, St, Req, Res, Err> ServiceFactory<St, Req> for FnServiceStFactory<F, St, Req, Res, Err>
270where
271    F: AsyncFn(&St, Req) -> Result<Res, Err> + Clone,
272{
273    type Res = Res;
274    type Error = Err;
275
276    type Service = FnServiceSt<F, St, Req, Res, Err>;
277    type InitError = Infallible;
278
279    #[inline]
280    async fn create(&self, _: &St) -> Result<Self::Service, Self::InitError> {
281        Ok(FnServiceSt {
282            f: self.f.clone(),
283            _t: PhantomData,
284        })
285    }
286}
287
288impl<F, St, Req, Res, Err> IntoServiceFactory<FnServiceStFactory<F, St, Req, Res, Err>, St, Req>
289    for F
290where
291    F: AsyncFn(&St, Req) -> Result<Res, Err> + Clone,
292{
293    #[inline]
294    fn into_factory(self) -> FnServiceStFactory<F, St, Req, Res, Err> {
295        FnServiceStFactory {
296            f: self,
297            ph: PhantomData,
298        }
299    }
300}
301
302// ========================= FnFactory ==================================
303
304#[inline]
305/// Converts an asynchronous constructor function into a [`ServiceFactory`].
306///
307/// Any function with the form
308/// `AsyncFn(&State) -> Result<Service, InitError>` can act as a factory.
309///
310/// # Example
311///
312/// ```rust
313/// use std::io;
314/// use ntex_service::{factory, fn_factory, fn_service, Pipeline, Service, ServiceFactory};
315///
316/// #[ntex::main]
317/// async fn main() -> io::Result<()> {
318///     // Create a factory that uses the state to configure each service.
319///     let fac = fn_factory(async |y: &usize| {
320///         let y = *y;
321///         Ok::<_, io::Error>(fn_service(move |x: usize| async move { Ok::<_, io::Error>(x * y) }))
322///     });
323///
324///     // Construct a service with the supplied state.
325///     let srv = Pipeline::new((), factory(fac).create(&10).await?);
326///
327///     let result = srv.call(10).await?;
328///     assert_eq!(result, 100);
329///
330///     println!("10 * 10 = {}", result);
331///     Ok(())
332/// }
333/// ```
334pub fn fn_factory<F, S, St, Req, Err>(f: F) -> FnFactory<F, S, St, Req, Err>
335where
336    F: AsyncFn(&St) -> Result<S, Err>,
337    S: Service<St, Req>,
338{
339    FnFactory { f, _t: PhantomData }
340}
341
342/// A [`ServiceFactory`] backed by an asynchronous constructor function.
343pub struct FnFactory<F, S, St, Req, Err>
344where
345    F: AsyncFn(&St) -> Result<S, Err>,
346    S: Service<St, Req>,
347{
348    f: F,
349    _t: PhantomData<(S, St, Req, Err)>,
350}
351
352impl<F, S, St, Req, Err> ServiceFactory<St, Req> for FnFactory<F, S, St, Req, Err>
353where
354    F: AsyncFn(&St) -> Result<S, Err>,
355    S: Service<St, Req>,
356{
357    type Res = S::Res;
358    type Error = S::Error;
359
360    type Service = S;
361    type InitError = Err;
362
363    #[inline]
364    async fn create(&self, st: &St) -> Result<Self::Service, Self::InitError> {
365        (self.f)(st).await
366    }
367}
368
369impl<F, S, St, Req, Err> Clone for FnFactory<F, S, St, Req, Err>
370where
371    F: AsyncFn(&St) -> Result<S, Err> + Clone,
372    S: Service<St, Req>,
373{
374    #[inline]
375    fn clone(&self) -> Self {
376        FnFactory {
377            f: self.f.clone(),
378            _t: PhantomData,
379        }
380    }
381}
382
383impl<F, S, St, Req, Err> fmt::Debug for FnFactory<F, S, St, Req, Err>
384where
385    F: AsyncFn(&St) -> Result<S, Err>,
386    S: Service<St, Req>,
387{
388    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
389        f.debug_struct("FnFactory")
390            .field("f", &std::any::type_name::<F>())
391            .finish()
392    }
393}
394
395impl<F, S, St, Req, Err> IntoServiceFactory<FnFactory<F, S, St, Req, Err>, St, Req> for F
396where
397    F: AsyncFn(&St) -> Result<S, Err>,
398    S: Service<St, Req>,
399{
400    #[inline]
401    fn into_factory(self) -> FnFactory<F, S, St, Req, Err> {
402        FnFactory {
403            f: self,
404            _t: PhantomData,
405        }
406    }
407}
408
409#[cfg(test)]
410mod tests {
411    use ntex::util::lazy;
412    use std::task::Poll;
413
414    use super::*;
415    use crate::{Pipeline, factory};
416
417    #[ntex::test]
418    async fn test_fn_service() {
419        let new_srv = factory(fn_service(async |()| Ok::<_, ()>("srv")).clone());
420        let _ = format!("{new_srv:?}");
421
422        let srv = Pipeline::new((), new_srv.create(&()).await.unwrap());
423        let res = srv.call(()).await;
424        assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
425        assert!(res.is_ok());
426        assert_eq!(res.unwrap(), "srv");
427        let _ = format!("{srv:?}");
428
429        let new_srv = fn_service(async |()| Ok::<_, ()>("srv"));
430        let srv = Pipeline::new((), new_srv.clone());
431        let res = srv.call(()).await;
432        assert!(res.is_ok());
433        assert_eq!(res.unwrap(), "srv");
434        let _ = format!("{srv:?}");
435
436        assert_eq!(lazy(|cx| srv.poll_shutdown(cx)).await, Poll::Ready(()));
437    }
438
439    #[ntex::test]
440    async fn test_fn_service_comp() {
441        let new_srv = fn_service(async |()| Ok::<_, ()>("srv")).clone();
442        let _ = format!("{new_srv:?}");
443
444        let srv = Pipeline::new((), factory(new_srv).create(&()).await.unwrap());
445        let res = srv.call(()).await;
446        assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
447        assert!(res.is_ok());
448        assert_eq!(res.unwrap(), "srv");
449        let _ = format!("{srv:?}");
450
451        let new_srv = fn_service(async |()| Ok::<_, ()>("srv")).clone();
452        let srv = Pipeline::new((), new_srv.clone());
453        let res = srv.call(()).await;
454        assert!(res.is_ok());
455        assert_eq!(res.unwrap(), "srv");
456        let _ = format!("{srv:?}");
457
458        assert_eq!(lazy(|cx| srv.poll_shutdown(cx)).await, Poll::Ready(()));
459    }
460
461    #[ntex::test]
462    async fn test_fn_service_service() {
463        let srv = Pipeline::new(
464            (),
465            factory(fn_service(async |()| Ok::<_, ()>("srv")).clone())
466                .create(&())
467                .await
468                .unwrap()
469                .clone(),
470        );
471
472        let res = srv.call(()).await;
473        assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
474        assert!(res.is_ok());
475        assert_eq!(res.unwrap(), "srv");
476        assert_eq!(lazy(|cx| srv.poll_shutdown(cx)).await, Poll::Ready(()));
477    }
478
479    #[ntex::test]
480    async fn test_fn_factory() {
481        let new_srv = factory(fn_factory(async move |cfg: &usize| {
482            let cfg = *cfg;
483            Ok::<_, ()>(fn_service(async move |()| Ok::<_, ()>(("srv", cfg))))
484        }))
485        .clone();
486
487        let srv = Pipeline::new(1, new_srv.create(&1).await.unwrap());
488        let res = srv.call(()).await;
489        assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
490        assert!(res.is_ok());
491        assert_eq!(res.unwrap(), ("srv", 1));
492    }
493
494    #[ntex::test]
495    async fn test_fn_service_st() {
496        let new_srv = factory(async |(): &(), ()| Ok::<_, ()>("srv")).clone();
497        let _ = format!("{new_srv:?}");
498
499        let srv = Pipeline::new((), new_srv.create(&()).await.unwrap());
500        let res = srv.call(()).await;
501        assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
502        assert!(res.is_ok());
503        assert_eq!(res.unwrap(), "srv");
504        let _ = format!("{srv:?}");
505
506        let new_srv = fn_service(async |()| Ok::<_, ()>("srv"));
507        let srv = Pipeline::new((), new_srv.clone());
508        let res = srv.call(()).await;
509        assert!(res.is_ok());
510        assert_eq!(res.unwrap(), "srv");
511        let _ = format!("{srv:?}");
512
513        assert_eq!(lazy(|cx| srv.poll_shutdown(cx)).await, Poll::Ready(()));
514    }
515}