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/// `Service` implementation for an `AsyncFn(Req) -> Result<Res, Err>` fn.
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/// `Service` implementation for an `AsyncFn(Req, &St) -> Result<Res, Err>` function.
15///
16/// This service accesses the pipeline state via the second `&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/// `Service` implementation for an `AsyncFn(Req) -> Result<Res, Err>` fn.
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/// `Service` implementation for an `AsyncFn(Req, &St) -> Result<Res, Err>` function.
94///
95/// This service accesses the pipeline state via the second `&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
163pub struct FnServiceFactory<F, Req, Res, Err>
164where
165    F: AsyncFn(Req) -> Result<Res, Err> + Clone,
166{
167    f: F,
168    _t: PhantomData<(Req,)>,
169}
170
171impl<F, Req, Res, Err> FnServiceFactory<F, Req, Res, Err>
172where
173    F: AsyncFn(Req) -> Result<Res, Err> + Clone,
174{
175    fn new(f: F) -> Self {
176        FnServiceFactory { f, _t: PhantomData }
177    }
178}
179
180impl<F, Req, Res, Err> Clone for FnServiceFactory<F, Req, Res, Err>
181where
182    F: AsyncFn(Req) -> Result<Res, Err> + Clone,
183{
184    #[inline]
185    fn clone(&self) -> Self {
186        Self {
187            f: self.f.clone(),
188            _t: PhantomData,
189        }
190    }
191}
192
193impl<F, Req, Res, Err> fmt::Debug for FnServiceFactory<F, Req, Res, Err>
194where
195    F: AsyncFn(Req) -> Result<Res, Err> + Clone,
196{
197    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198        f.debug_struct("FnServiceFactory")
199            .field("f", &std::any::type_name::<F>())
200            .finish()
201    }
202}
203
204impl<F, St, Req, Res, Err> ServiceFactory<St, Req> for FnServiceFactory<F, Req, Res, Err>
205where
206    F: AsyncFn(Req) -> Result<Res, Err> + Clone,
207{
208    type Res = Res;
209    type Error = Err;
210
211    type Service = FnService<F, Req, Res, Err>;
212    type InitError = Infallible;
213
214    #[inline]
215    async fn create(&self, _: &St) -> Result<Self::Service, Self::InitError> {
216        Ok(FnService {
217            f: self.f.clone(),
218            _t: PhantomData,
219        })
220    }
221}
222
223impl<St, F, Req, Res, Err> IntoServiceFactory<FnServiceFactory<F, Req, Res, Err>, St, Req> for F
224where
225    F: AsyncFn(Req) -> Result<Res, Err> + Clone,
226{
227    #[inline]
228    fn into_factory(self) -> FnServiceFactory<F, Req, Res, Err> {
229        FnServiceFactory::new(self)
230    }
231}
232
233// ========================= FnServiceStFactory =======================
234
235pub struct FnServiceStFactory<F, St, Req, Res, Err>
236where
237    F: AsyncFn(&St, Req) -> Result<Res, Err> + Clone,
238{
239    f: F,
240    ph: PhantomData<(St, Req, Res, Err)>,
241}
242
243impl<F, St, Req, Res, Err> FnServiceStFactory<F, St, Req, Res, Err>
244where
245    F: AsyncFn(&St, Req) -> Result<Res, Err> + Clone,
246{
247    fn new(f: F) -> Self {
248        FnServiceStFactory { f, ph: PhantomData }
249    }
250}
251
252impl<F, St, Req, Res, Err> Clone for FnServiceStFactory<F, St, Req, Res, Err>
253where
254    F: AsyncFn(&St, Req) -> Result<Res, Err> + Clone,
255{
256    #[inline]
257    fn clone(&self) -> Self {
258        Self {
259            f: self.f.clone(),
260            ph: PhantomData,
261        }
262    }
263}
264
265impl<F, St, Req, Res, Err> fmt::Debug for FnServiceStFactory<F, St, Req, Res, Err>
266where
267    F: AsyncFn(&St, Req) -> Result<Res, Err> + Clone,
268{
269    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
270        f.debug_struct("FnServiceStFactory")
271            .field("f", &std::any::type_name::<F>())
272            .finish()
273    }
274}
275
276impl<F, St, Req, Res, Err> ServiceFactory<St, Req> for FnServiceStFactory<F, St, Req, Res, Err>
277where
278    F: AsyncFn(&St, Req) -> Result<Res, Err> + Clone,
279{
280    type Res = Res;
281    type Error = Err;
282
283    type Service = FnServiceSt<F, St, Req, Res, Err>;
284    type InitError = Infallible;
285
286    #[inline]
287    async fn create(&self, _: &St) -> Result<Self::Service, Self::InitError> {
288        Ok(FnServiceSt {
289            f: self.f.clone(),
290            _t: PhantomData,
291        })
292    }
293}
294
295impl<F, St, Req, Res, Err> IntoServiceFactory<FnServiceStFactory<F, St, Req, Res, Err>, St, Req>
296    for F
297where
298    F: AsyncFn(&St, Req) -> Result<Res, Err> + Clone,
299{
300    #[inline]
301    fn into_factory(self) -> FnServiceStFactory<F, St, Req, Res, Err> {
302        FnServiceStFactory::new(self)
303    }
304}
305
306// ========================= FnFactory ==================================
307
308#[inline]
309/// Create `ServiceFactory` for function that accepts config argument and can produce services
310///
311/// Any function that has following form `AsyncFn(&Config) -> Result<Service, Error>` could
312/// act as a `ServiceFactory`.
313///
314/// # Example
315///
316/// ```rust
317/// use std::io;
318/// use ntex_service::{factory, fn_factory, fn_service, Pipeline, Service, ServiceFactory};
319///
320/// #[ntex::main]
321/// async fn main() -> io::Result<()> {
322///     // Create service factory. factory uses config argument for
323///     // services it generates.
324///     let fac = fn_factory(async |y: &usize| {
325///         let y = *y;
326///         Ok::<_, io::Error>(fn_service(move |x: usize| async move { Ok::<_, io::Error>(x * y) }))
327///     });
328///
329///     // construct new service with config argument
330///     let srv = Pipeline::new(12, factory(fac).create(&10).await?);
331///
332///     let result = srv.call(10).await?;
333///     assert_eq!(result, 100);
334///
335///     println!("10 * 10 = {}", result);
336///     Ok(())
337/// }
338/// ```
339pub fn fn_factory<F, S, St, Req, Err>(f: F) -> FnFactory<F, S, St, Req, Err>
340where
341    F: AsyncFn(&St) -> Result<S, Err>,
342    S: Service<St, Req>,
343{
344    FnFactory { f, _t: PhantomData }
345}
346
347/// `ServiceFactory` for a `AsyncFn(&St) -> Result<Srv, Err>` function
348pub struct FnFactory<F, S, St, Req, Err>
349where
350    F: AsyncFn(&St) -> Result<S, Err>,
351    S: Service<St, Req>,
352{
353    f: F,
354    _t: PhantomData<(S, St, Req, Err)>,
355}
356
357impl<F, S, St, Req, Err> ServiceFactory<St, Req> for FnFactory<F, S, St, Req, Err>
358where
359    F: AsyncFn(&St) -> Result<S, Err>,
360    S: Service<St, Req>,
361{
362    type Res = S::Res;
363    type Error = S::Error;
364
365    type Service = S;
366    type InitError = Err;
367
368    #[inline]
369    async fn create(&self, st: &St) -> Result<Self::Service, Self::InitError> {
370        (self.f)(st).await
371    }
372}
373
374impl<F, S, St, Req, Err> Clone for FnFactory<F, S, St, Req, Err>
375where
376    F: AsyncFn(&St) -> Result<S, Err> + Clone,
377    S: Service<St, Req>,
378{
379    #[inline]
380    fn clone(&self) -> Self {
381        FnFactory {
382            f: self.f.clone(),
383            _t: PhantomData,
384        }
385    }
386}
387
388impl<F, S, St, Req, Err> fmt::Debug for FnFactory<F, S, St, Req, Err>
389where
390    F: AsyncFn(&St) -> Result<S, Err>,
391    S: Service<St, Req>,
392{
393    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
394        f.debug_struct("FnFactory")
395            .field("f", &std::any::type_name::<F>())
396            .finish()
397    }
398}
399
400impl<F, S, St, Req, Err> IntoServiceFactory<FnFactory<F, S, St, Req, Err>, St, Req> for F
401where
402    F: AsyncFn(&St) -> Result<S, Err>,
403    S: Service<St, Req>,
404{
405    #[inline]
406    fn into_factory(self) -> FnFactory<F, S, St, Req, Err> {
407        FnFactory {
408            f: self,
409            _t: PhantomData,
410        }
411    }
412}
413
414#[cfg(test)]
415mod tests {
416    use ntex::util::lazy;
417    use std::task::Poll;
418
419    use super::*;
420    use crate::{Pipeline, factory};
421
422    #[ntex::test]
423    async fn test_fn_service() {
424        let new_srv = factory(fn_service(async |()| Ok::<_, ()>("srv")).clone());
425        let _ = format!("{new_srv:?}");
426
427        let srv = Pipeline::new((), new_srv.create(&()).await.unwrap());
428        let res = srv.call(()).await;
429        assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
430        assert!(res.is_ok());
431        assert_eq!(res.unwrap(), "srv");
432        let _ = format!("{srv:?}");
433
434        let new_srv = fn_service(async |()| Ok::<_, ()>("srv"));
435        let srv = Pipeline::new((), new_srv.clone());
436        let res = srv.call(()).await;
437        assert!(res.is_ok());
438        assert_eq!(res.unwrap(), "srv");
439        let _ = format!("{srv:?}");
440
441        assert_eq!(lazy(|cx| srv.poll_shutdown(cx)).await, Poll::Ready(()));
442    }
443
444    #[ntex::test]
445    async fn test_fn_service_comp() {
446        let new_srv = fn_service(async |()| Ok::<_, ()>("srv")).clone();
447        let _ = format!("{new_srv:?}");
448
449        let srv = Pipeline::new((), factory(new_srv).create(&()).await.unwrap());
450        let res = srv.call(()).await;
451        assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
452        assert!(res.is_ok());
453        assert_eq!(res.unwrap(), "srv");
454        let _ = format!("{srv:?}");
455
456        let new_srv = fn_service(async |()| Ok::<_, ()>("srv")).clone();
457        let srv = Pipeline::new((), new_srv.clone());
458        let res = srv.call(()).await;
459        assert!(res.is_ok());
460        assert_eq!(res.unwrap(), "srv");
461        let _ = format!("{srv:?}");
462
463        assert_eq!(lazy(|cx| srv.poll_shutdown(cx)).await, Poll::Ready(()));
464    }
465
466    #[ntex::test]
467    async fn test_fn_service_service() {
468        let srv = Pipeline::new(
469            (),
470            factory(fn_service(async |()| Ok::<_, ()>("srv")).clone())
471                .create(&())
472                .await
473                .unwrap()
474                .clone(),
475        );
476
477        let res = srv.call(()).await;
478        assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
479        assert!(res.is_ok());
480        assert_eq!(res.unwrap(), "srv");
481        assert_eq!(lazy(|cx| srv.poll_shutdown(cx)).await, Poll::Ready(()));
482    }
483
484    #[ntex::test]
485    async fn test_fn_service_with_config() {
486        let new_srv = factory(fn_factory(async move |cfg: &usize| {
487            let cfg = *cfg;
488            Ok::<_, ()>(fn_service(async move |()| Ok::<_, ()>(("srv", cfg))))
489        }))
490        .clone();
491
492        let srv = Pipeline::new(1, new_srv.create(&1).await.unwrap());
493        let res = srv.call(()).await;
494        assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
495        assert!(res.is_ok());
496        assert_eq!(res.unwrap(), ("srv", 1));
497    }
498}