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