actix_service/
fn_service.rs

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