use std::future::Future; use std::marker::PhantomData; use std::task::{Context, Poll}; use futures_util::future::{ok, Ready}; use crate::{IntoService, IntoServiceFactory, Service, ServiceFactory}; /// Create `ServiceFactory` for function that can act as a `Service` pub fn fn_service( f: F, ) -> FnServiceFactory where F: FnMut(Req) -> Fut + Clone, Fut: Future>, { FnServiceFactory::new(f) } /// Create `ServiceFactory` for function that can produce services /// /// # Example /// /// ```rust /// use std::io; /// use actix_service::{fn_factory, fn_service, Service, ServiceFactory}; /// use futures_util::future::ok; /// /// /// Service that divides two usize values. /// async fn div((x, y): (usize, usize)) -> Result { /// if y == 0 { /// Err(io::Error::new(io::ErrorKind::Other, "divide by zdro")) /// } else { /// Ok(x / y) /// } /// } /// /// #[actix_rt::main] /// async fn main() -> io::Result<()> { /// // Create service factory that produces `div` services /// let factory = fn_factory(|| { /// ok::<_, io::Error>(fn_service(div)) /// }); /// /// // construct new service /// let mut srv = factory.new_service(()).await?; /// /// // now we can use `div` service /// let result = srv.call((10, 20)).await?; /// /// println!("10 / 20 = {}", result); /// /// Ok(()) /// } /// ``` pub fn fn_factory(f: F) -> FnServiceNoConfig where Srv: Service, F: Fn() -> Fut, Fut: Future>, { FnServiceNoConfig::new(f) } /// Create `ServiceFactory` for function that accepts config argument and can produce services /// /// Any function that has following form `Fn(Config) -> Future` could /// act as a `ServiceFactory`. /// /// # Example /// /// ```rust /// use std::io; /// use actix_service::{fn_factory_with_config, fn_service, Service, ServiceFactory}; /// use futures_util::future::ok; /// /// #[actix_rt::main] /// async fn main() -> io::Result<()> { /// // Create service factory. factory uses config argument for /// // services it generates. /// let factory = fn_factory_with_config(|y: usize| { /// ok::<_, io::Error>(fn_service(move |x: usize| ok::<_, io::Error>(x * y))) /// }); /// /// // construct new service with config argument /// let mut srv = factory.new_service(10).await?; /// /// let result = srv.call(10).await?; /// assert_eq!(result, 100); /// /// println!("10 * 10 = {}", result); /// Ok(()) /// } /// ``` pub fn fn_factory_with_config( f: F, ) -> FnServiceConfig where F: Fn(Cfg) -> Fut, Fut: Future>, Srv: Service, { FnServiceConfig::new(f) } pub struct FnService where F: FnMut(Req) -> Fut, Fut: Future>, { f: F, _t: PhantomData, } impl FnService where F: FnMut(Req) -> Fut, Fut: Future>, { pub(crate) fn new(f: F) -> Self { Self { f, _t: PhantomData } } } impl Clone for FnService where F: FnMut(Req) -> Fut + Clone, Fut: Future>, { fn clone(&self) -> Self { Self::new(self.f.clone()) } } impl Service for FnService where F: FnMut(Req) -> Fut, Fut: Future>, { type Request = Req; type Response = Res; type Error = Err; type Future = Fut; fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) } fn call(&mut self, req: Req) -> Self::Future { (self.f)(req) } } impl IntoService> for F where F: FnMut(Req) -> Fut, Fut: Future>, { fn into_service(self) -> FnService { FnService::new(self) } } pub struct FnServiceFactory where F: FnMut(Req) -> Fut, Fut: Future>, { f: F, _t: PhantomData<(Req, Cfg)>, } impl FnServiceFactory where F: FnMut(Req) -> Fut + Clone, Fut: Future>, { fn new(f: F) -> Self { FnServiceFactory { f, _t: PhantomData } } } impl Clone for FnServiceFactory where F: FnMut(Req) -> Fut + Clone, Fut: Future>, { fn clone(&self) -> Self { Self::new(self.f.clone()) } } impl Service for FnServiceFactory where F: FnMut(Req) -> Fut + Clone, Fut: Future>, { type Request = Req; type Response = Res; type Error = Err; type Future = Fut; fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) } fn call(&mut self, req: Self::Request) -> Self::Future { (self.f)(req) } } impl ServiceFactory for FnServiceFactory where F: FnMut(Req) -> Fut + Clone, Fut: Future>, { type Request = Req; type Response = Res; type Error = Err; type Config = Cfg; type Service = FnService; type InitError = (); type Future = Ready>; fn new_service(&self, _: Cfg) -> Self::Future { ok(FnService::new(self.f.clone())) } } impl IntoServiceFactory> for F where F: Fn(Req) -> Fut + Clone, Fut: Future>, { fn into_factory(self) -> FnServiceFactory { FnServiceFactory::new(self) } } /// Convert `Fn(&Config) -> Future` fn to NewService pub struct FnServiceConfig where F: Fn(Cfg) -> Fut, Fut: Future>, Srv: Service, { f: F, _t: PhantomData<(Fut, Cfg, Srv, Err)>, } impl FnServiceConfig where F: Fn(Cfg) -> Fut, Fut: Future>, Srv: Service, { fn new(f: F) -> Self { FnServiceConfig { f, _t: PhantomData } } } impl Clone for FnServiceConfig where F: Fn(Cfg) -> Fut + Clone, Fut: Future>, Srv: Service, { fn clone(&self) -> Self { FnServiceConfig { f: self.f.clone(), _t: PhantomData, } } } impl ServiceFactory for FnServiceConfig where F: Fn(Cfg) -> Fut, Fut: Future>, Srv: Service, { type Request = Srv::Request; type Response = Srv::Response; type Error = Srv::Error; type Config = Cfg; type Service = Srv; type InitError = Err; type Future = Fut; fn new_service(&self, cfg: Cfg) -> Self::Future { (self.f)(cfg) } } /// Converter for `Fn() -> Future` fn pub struct FnServiceNoConfig where F: Fn() -> R, S: Service, R: Future>, { f: F, _t: PhantomData, } impl FnServiceNoConfig where F: Fn() -> R, R: Future>, S: Service, { fn new(f: F) -> Self { Self { f, _t: PhantomData } } } impl ServiceFactory for FnServiceNoConfig where F: Fn() -> R, R: Future>, S: Service, { type Request = S::Request; type Response = S::Response; type Error = S::Error; type Service = S; type Config = C; type InitError = E; type Future = R; fn new_service(&self, _: C) -> Self::Future { (self.f)() } } impl Clone for FnServiceNoConfig where F: Fn() -> R + Clone, R: Future>, S: Service, { fn clone(&self) -> Self { Self::new(self.f.clone()) } } impl IntoServiceFactory> for F where F: Fn() -> R, R: Future>, S: Service, { fn into_factory(self) -> FnServiceNoConfig { FnServiceNoConfig::new(self) } } #[cfg(test)] mod tests { use std::task::Poll; use futures_util::future::{lazy, ok}; use super::*; use crate::{Service, ServiceFactory}; #[actix_rt::test] async fn test_fn_service() { let new_srv = fn_service(|()| ok::<_, ()>("srv")); let mut srv = new_srv.new_service(()).await.unwrap(); let res = srv.call(()).await; assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(()))); assert!(res.is_ok()); assert_eq!(res.unwrap(), "srv"); } #[actix_rt::test] async fn test_fn_service_service() { let mut srv = fn_service(|()| ok::<_, ()>("srv")); let res = srv.call(()).await; assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(()))); assert!(res.is_ok()); assert_eq!(res.unwrap(), "srv"); } #[actix_rt::test] async fn test_fn_service_with_config() { let new_srv = fn_factory_with_config(|cfg: usize| { ok::<_, ()>(fn_service(move |()| ok::<_, ()>(("srv", cfg)))) }); let mut srv = new_srv.new_service(1).await.unwrap(); let res = srv.call(()).await; assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(()))); assert!(res.is_ok()); assert_eq!(res.unwrap(), ("srv", 1)); } }