ntex_service/
fn_service.rs

1use std::{fmt, future::Future, 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, Fut, Req, Res, Err, Cfg>(
8    f: F,
9) -> FnServiceFactory<F, Fut, Req, Res, Err, Cfg>
10where
11    F: Fn(Req) -> Fut + Clone,
12    Fut: Future<Output = Result<Res, Err>>,
13{
14    FnServiceFactory::new(f)
15}
16
17#[inline]
18/// Create `ServiceFactory` for function that can produce services
19///
20/// # Example
21///
22/// ```rust
23/// use std::io;
24/// use ntex_service::{fn_factory, fn_service, Service, ServiceFactory};
25///
26/// /// Service that divides two usize values.
27/// async fn div((x, y): (usize, usize)) -> Result<usize, io::Error> {
28///     if y == 0 {
29///         Err(io::Error::new(io::ErrorKind::Other, "divide by zdro"))
30///     } else {
31///         Ok(x / y)
32///     }
33/// }
34///
35/// #[ntex::main]
36/// async fn main() -> io::Result<()> {
37///     // Create service factory that produces `div` services
38///     let factory = fn_factory(|| {
39///         async {Ok::<_, io::Error>(fn_service(div))}
40///     });
41///
42///     // construct new service
43///     let srv = factory.pipeline(&()).await?;
44///
45///     // now we can use `div` service
46///     let result = srv.call((10, 20)).await?;
47///
48///     println!("10 / 20 = {}", result);
49///
50///     Ok(())
51/// }
52/// ```
53pub fn fn_factory<F, Srv, Fut, Req, Err>(f: F) -> FnServiceNoConfig<F, Srv, Fut, Req, Err>
54where
55    F: Fn() -> Fut,
56    Srv: Service<Req>,
57    Fut: Future<Output = Result<Srv, Err>>,
58{
59    FnServiceNoConfig::new(f)
60}
61
62#[inline]
63/// Create `ServiceFactory` for function that accepts config argument and can produce services
64///
65/// Any function that has following form `Fn(Config) -> Future<Output = Service>` could
66/// act as a `ServiceFactory`.
67///
68/// # Example
69///
70/// ```rust
71/// use std::io;
72/// use ntex_service::{fn_factory_with_config, fn_service, Service, ServiceFactory};
73///
74/// #[ntex::main]
75/// async fn main() -> io::Result<()> {
76///     // Create service factory. factory uses config argument for
77///     // services it generates.
78///     let factory = fn_factory_with_config(|y: &usize| {
79///         let y = *y;
80///         async move { Ok::<_, io::Error>(fn_service(move |x: usize| async move { Ok::<_, io::Error>(x * y) })) }
81///     });
82///
83///     // construct new service with config argument
84///     let srv = factory.pipeline(&10).await?;
85///
86///     let result = srv.call(10).await?;
87///     assert_eq!(result, 100);
88///
89///     println!("10 * 10 = {}", result);
90///     Ok(())
91/// }
92/// ```
93pub fn fn_factory_with_config<F, Fut, Cfg, Srv, Req, Err>(
94    f: F,
95) -> FnServiceConfig<F, Fut, Cfg, Srv, Req, Err>
96where
97    F: Fn(Cfg) -> Fut,
98    Fut: Future<Output = Result<Srv, Err>>,
99    Srv: Service<Req>,
100{
101    FnServiceConfig { f, _t: PhantomData }
102}
103
104pub struct FnService<F, Req> {
105    f: F,
106    _t: PhantomData<Req>,
107}
108
109impl<F, Req> Clone for FnService<F, Req>
110where
111    F: Clone,
112{
113    fn clone(&self) -> Self {
114        Self {
115            f: self.f.clone(),
116            _t: PhantomData,
117        }
118    }
119}
120
121impl<F, Req> fmt::Debug for FnService<F, Req> {
122    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123        f.debug_struct("FnService")
124            .field("f", &std::any::type_name::<F>())
125            .finish()
126    }
127}
128
129impl<F, Fut, Req, Res, Err> Service<Req> for FnService<F, Req>
130where
131    F: Fn(Req) -> Fut,
132    Fut: Future<Output = Result<Res, Err>>,
133{
134    type Response = Res;
135    type Error = Err;
136
137    #[inline]
138    async fn call(&self, req: Req, _: ServiceCtx<'_, Self>) -> Result<Res, Err> {
139        (self.f)(req).await
140    }
141}
142
143impl<F, Fut, Req, Res, Err> IntoService<FnService<F, Req>, Req> for F
144where
145    F: Fn(Req) -> Fut,
146    Fut: Future<Output = Result<Res, Err>>,
147{
148    #[inline]
149    fn into_service(self) -> FnService<F, Req> {
150        FnService {
151            f: self,
152            _t: PhantomData,
153        }
154    }
155}
156
157pub struct FnServiceFactory<F, Fut, Req, Res, Err, Cfg>
158where
159    F: Fn(Req) -> Fut,
160    Fut: Future<Output = Result<Res, Err>>,
161{
162    f: F,
163    _t: PhantomData<(Req, Cfg)>,
164}
165
166impl<F, Fut, Req, Res, Err, Cfg> FnServiceFactory<F, Fut, Req, Res, Err, Cfg>
167where
168    F: Fn(Req) -> Fut + Clone,
169    Fut: Future<Output = Result<Res, Err>>,
170{
171    fn new(f: F) -> Self {
172        FnServiceFactory { f, _t: PhantomData }
173    }
174}
175
176impl<F, Fut, Req, Res, Err, Cfg> Clone for FnServiceFactory<F, Fut, Req, Res, Err, Cfg>
177where
178    F: Fn(Req) -> Fut + Clone,
179    Fut: Future<Output = Result<Res, Err>>,
180{
181    #[inline]
182    fn clone(&self) -> Self {
183        Self {
184            f: self.f.clone(),
185            _t: PhantomData,
186        }
187    }
188}
189
190impl<F, Fut, Req, Res, Err, Cfg> fmt::Debug for FnServiceFactory<F, Fut, Req, Res, Err, Cfg>
191where
192    F: Fn(Req) -> Fut,
193    Fut: Future<Output = Result<Res, Err>>,
194{
195    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196        f.debug_struct("FnServiceFactory")
197            .field("f", &std::any::type_name::<F>())
198            .finish()
199    }
200}
201
202impl<F, Fut, Req, Res, Err> Service<Req> for FnServiceFactory<F, Fut, Req, Res, Err, ()>
203where
204    F: Fn(Req) -> Fut,
205    Fut: Future<Output = Result<Res, Err>>,
206{
207    type Response = Res;
208    type Error = Err;
209
210    #[inline]
211    async fn call(&self, req: Req, _: ServiceCtx<'_, Self>) -> Result<Res, Err> {
212        (self.f)(req).await
213    }
214}
215
216impl<F, Fut, Req, Res, Err, Cfg> ServiceFactory<Req, Cfg>
217    for FnServiceFactory<F, Fut, Req, Res, Err, Cfg>
218where
219    F: Fn(Req) -> Fut + Clone,
220    Fut: Future<Output = Result<Res, Err>>,
221{
222    type Response = Res;
223    type Error = Err;
224
225    type Service = FnService<F, Req>;
226    type InitError = ();
227
228    #[inline]
229    async fn create(&self, _: Cfg) -> Result<Self::Service, Self::InitError> {
230        Ok(FnService {
231            f: self.f.clone(),
232            _t: PhantomData,
233        })
234    }
235}
236
237impl<F, Fut, Req, Res, Err, Cfg>
238    IntoServiceFactory<FnServiceFactory<F, Fut, Req, Res, Err, Cfg>, Req, Cfg> for F
239where
240    F: Fn(Req) -> Fut + Clone,
241    Fut: Future<Output = Result<Res, Err>>,
242{
243    #[inline]
244    fn into_factory(self) -> FnServiceFactory<F, Fut, Req, Res, Err, Cfg> {
245        FnServiceFactory::new(self)
246    }
247}
248
249/// Convert `Fn(Config) -> Future<Service>` fn to NewService
250pub struct FnServiceConfig<F, Fut, Cfg, Srv, Req, Err>
251where
252    F: Fn(Cfg) -> Fut,
253    Fut: Future<Output = Result<Srv, Err>>,
254    Srv: Service<Req>,
255{
256    f: F,
257    _t: PhantomData<(Fut, Cfg, Srv, Req, Err)>,
258}
259
260impl<F, Fut, Cfg, Srv, Req, Err> Clone for FnServiceConfig<F, Fut, Cfg, Srv, Req, Err>
261where
262    F: Fn(Cfg) -> Fut + Clone,
263    Fut: Future<Output = Result<Srv, Err>>,
264    Srv: Service<Req>,
265{
266    #[inline]
267    fn clone(&self) -> Self {
268        FnServiceConfig {
269            f: self.f.clone(),
270            _t: PhantomData,
271        }
272    }
273}
274
275impl<F, Fut, Cfg, Srv, Req, Err> fmt::Debug for FnServiceConfig<F, Fut, Cfg, Srv, Req, Err>
276where
277    F: Fn(Cfg) -> Fut,
278    Fut: Future<Output = Result<Srv, Err>>,
279    Srv: Service<Req>,
280{
281    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
282        f.debug_struct("FnServiceConfig")
283            .field("f", &std::any::type_name::<F>())
284            .finish()
285    }
286}
287
288impl<F, Fut, Cfg, Srv, Req, Err> ServiceFactory<Req, Cfg>
289    for FnServiceConfig<F, Fut, Cfg, Srv, Req, Err>
290where
291    F: Fn(Cfg) -> Fut,
292    Fut: Future<Output = Result<Srv, Err>>,
293    Srv: Service<Req>,
294{
295    type Response = Srv::Response;
296    type Error = Srv::Error;
297
298    type Service = Srv;
299    type InitError = Err;
300
301    #[inline]
302    async fn create(&self, cfg: Cfg) -> Result<Self::Service, Self::InitError> {
303        (self.f)(cfg).await
304    }
305}
306
307/// Converter for `Fn() -> Future<Service>` fn
308pub struct FnServiceNoConfig<F, S, R, Req, E>
309where
310    F: Fn() -> R,
311    S: Service<Req>,
312    R: Future<Output = Result<S, E>>,
313{
314    f: F,
315    _t: PhantomData<Req>,
316}
317
318impl<F, S, R, Req, E> FnServiceNoConfig<F, S, R, Req, E>
319where
320    F: Fn() -> R,
321    R: Future<Output = Result<S, E>>,
322    S: Service<Req>,
323{
324    fn new(f: F) -> Self {
325        Self { f, _t: PhantomData }
326    }
327}
328
329impl<F, S, R, Req, E, C> ServiceFactory<Req, C> for FnServiceNoConfig<F, S, R, Req, E>
330where
331    F: Fn() -> R,
332    R: Future<Output = Result<S, E>>,
333    S: Service<Req>,
334    C: 'static,
335{
336    type Response = S::Response;
337    type Error = S::Error;
338    type Service = S;
339    type InitError = E;
340
341    #[inline]
342    async fn create(&self, _: C) -> Result<S, E> {
343        (self.f)().await
344    }
345}
346
347impl<F, S, R, Req, E> Clone for FnServiceNoConfig<F, S, R, Req, E>
348where
349    F: Fn() -> R + Clone,
350    R: Future<Output = Result<S, E>>,
351    S: Service<Req>,
352{
353    #[inline]
354    fn clone(&self) -> Self {
355        Self::new(self.f.clone())
356    }
357}
358
359impl<F, S, R, Req, E> fmt::Debug for FnServiceNoConfig<F, S, R, Req, E>
360where
361    F: Fn() -> R,
362    R: Future<Output = Result<S, E>>,
363    S: Service<Req>,
364{
365    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
366        f.debug_struct("FnServiceNoConfig")
367            .field("f", &std::any::type_name::<F>())
368            .finish()
369    }
370}
371
372#[cfg(test)]
373mod tests {
374    use ntex_util::future::lazy;
375    use std::task::Poll;
376
377    use super::*;
378    use crate::Pipeline;
379
380    #[ntex::test]
381    async fn test_fn_service() {
382        let new_srv = fn_service(|()| async { Ok::<_, ()>("srv") }).clone();
383        let _ = format!("{:?}", new_srv);
384
385        let srv = Pipeline::new(new_srv.create(()).await.unwrap()).bind();
386        let res = srv.call(()).await;
387        assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
388        assert!(res.is_ok());
389        assert_eq!(res.unwrap(), "srv");
390        let _ = format!("{:?}", srv);
391
392        let srv2 = Pipeline::new(new_srv.clone()).bind();
393        let res = srv2.call(()).await;
394        assert!(res.is_ok());
395        assert_eq!(res.unwrap(), "srv");
396        let _ = format!("{:?}", srv2);
397
398        assert_eq!(lazy(|cx| srv2.poll_shutdown(cx)).await, Poll::Ready(()));
399    }
400
401    #[ntex::test]
402    async fn test_fn_service_service() {
403        let srv = Pipeline::new(
404            fn_service(|()| async { Ok::<_, ()>("srv") })
405                .clone()
406                .create(&())
407                .await
408                .unwrap()
409                .clone(),
410        )
411        .bind();
412
413        let res = srv.call(()).await;
414        assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
415        assert!(res.is_ok());
416        assert_eq!(res.unwrap(), "srv");
417        assert_eq!(lazy(|cx| srv.poll_shutdown(cx)).await, Poll::Ready(()));
418    }
419
420    #[ntex::test]
421    async fn test_fn_service_with_config() {
422        let new_srv = fn_factory_with_config(|cfg: &usize| {
423            let cfg = *cfg;
424            async move {
425                Ok::<_, ()>(fn_service(
426                    move |()| async move { Ok::<_, ()>(("srv", cfg)) },
427                ))
428            }
429        })
430        .clone();
431
432        let srv = Pipeline::new(new_srv.create(&1).await.unwrap()).bind();
433        let res = srv.call(()).await;
434        assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
435        assert!(res.is_ok());
436        assert_eq!(res.unwrap(), ("srv", 1));
437    }
438}