ntex_service/
fn_service_async.rs

1use std::{fmt, marker::PhantomData};
2
3use crate::{IntoService, IntoServiceFactory, Service, ServiceCtx, ServiceFactory};
4
5#[inline]
6/// Create `ServiceFactory` for function that can act as a `Service`
7pub 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]
15/// Create `ServiceFactory` for function that can produce services
16///
17/// # Example
18///
19/// ```rust
20/// use std::io;
21/// use ntex_service::{fn_factory, fn_service, Service, ServiceFactory};
22///
23/// /// Service that divides two usize values.
24/// async fn div((x, y): (usize, usize)) -> Result<usize, io::Error> {
25///     if y == 0 {
26///         Err(io::Error::new(io::ErrorKind::Other, "divide by zdro"))
27///     } else {
28///         Ok(x / y)
29///     }
30/// }
31///
32/// #[ntex::main]
33/// async fn main() -> io::Result<()> {
34///     // Create service factory that produces `div` services
35///     let factory = fn_factory(|| {
36///         async {Ok::<_, io::Error>(fn_service(div))}
37///     });
38///
39///     // construct new service
40///     let srv = factory.pipeline(&()).await?;
41///
42///     // now we can use `div` service
43///     let result = srv.call((10, 20)).await?;
44///
45///     println!("10 / 20 = {}", result);
46///
47///     Ok(())
48/// }
49/// ```
50pub 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]
59/// Create `ServiceFactory` for function that accepts config argument and can produce services
60///
61/// Any function that has following form `AsyncFn(Config) -> Result<Service, Error>` could
62/// act as a `ServiceFactory`.
63///
64/// # Example
65///
66/// ```rust
67/// use std::io;
68/// use ntex_service::{fn_factory_with_config, fn_service, Service, ServiceFactory};
69///
70/// #[ntex::main]
71/// async fn main() -> io::Result<()> {
72///     // Create service factory. factory uses config argument for
73///     // services it generates.
74///     let factory = fn_factory_with_config(|y: &usize| {
75///         let y = *y;
76///         async move { Ok::<_, io::Error>(fn_service(move |x: usize| async move { Ok::<_, io::Error>(x * y) })) }
77///     });
78///
79///     // construct new service with config argument
80///     let srv = factory.pipeline(&10).await?;
81///
82///     let result = srv.call(10).await?;
83///     assert_eq!(result, 100);
84///
85///     println!("10 * 10 = {}", result);
86///     Ok(())
87/// }
88/// ```
89pub 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
235/// Convert `AsyncFn(Cfg) -> Result<Srv, Err>` fn to NewService
236pub 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
289/// Converter for `Fn() -> Future<Service>` fn
290pub 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}