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 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 and can produce services 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)); } }