use core::{ future::Future, marker::PhantomData, pin::Pin, task::{Context, Poll}, }; use alloc::rc::Rc; use futures_core::ready; use pin_project_lite::pin_project; use crate::{Service, ServiceFactory}; /// Convert `Fn(Config, &Service1) -> Future` fn to a service factory. pub fn apply_cfg( srv: S1, f: F, ) -> impl ServiceFactory< Req, Config = Cfg, Response = S2::Response, Error = S2::Error, Service = S2, InitError = Err, Future = Fut, > + Clone where S1: Service, F: Fn(Cfg, &S1) -> Fut, Fut: Future>, S2: Service, { ApplyConfigService { srv: Rc::new((srv, f)), _phantom: PhantomData, } } /// Convert `Fn(Config, &ServiceFactory1) -> Future` fn to a service factory. /// /// Service1 get constructed from `T` factory. pub fn apply_cfg_factory( factory: SF, f: F, ) -> impl ServiceFactory< Req, Config = Cfg, Response = S::Response, Error = S::Error, Service = S, InitError = SF::InitError, > + Clone where SF: ServiceFactory, F: Fn(Cfg, &SF::Service) -> Fut, SF::InitError: From, Fut: Future>, S: Service, { ApplyConfigServiceFactory { srv: Rc::new((factory, f)), _phantom: PhantomData, } } /// Convert `Fn(Config, &Server) -> Future` fn to NewService\ struct ApplyConfigService where S1: Service, F: Fn(Cfg, &S1) -> Fut, Fut: Future>, S2: Service, { srv: Rc<(S1, F)>, _phantom: PhantomData<(Cfg, Req, Fut, S2)>, } impl Clone for ApplyConfigService where S1: Service, F: Fn(Cfg, &S1) -> Fut, Fut: Future>, S2: Service, { fn clone(&self) -> Self { ApplyConfigService { srv: self.srv.clone(), _phantom: PhantomData, } } } impl ServiceFactory for ApplyConfigService where S1: Service, F: Fn(Cfg, &S1) -> Fut, Fut: Future>, S2: Service, { type Response = S2::Response; type Error = S2::Error; type Config = Cfg; type Service = S2; type InitError = Err; type Future = Fut; fn new_service(&self, cfg: Cfg) -> Self::Future { let (t, f) = &*self.srv; f(cfg, t) } } /// Convert `Fn(&Config) -> Future` fn to NewService struct ApplyConfigServiceFactory where SF: ServiceFactory, F: Fn(Cfg, &SF::Service) -> Fut, Fut: Future>, S: Service, { srv: Rc<(SF, F)>, _phantom: PhantomData<(Cfg, Req, Fut, S)>, } impl Clone for ApplyConfigServiceFactory where SF: ServiceFactory, F: Fn(Cfg, &SF::Service) -> Fut, Fut: Future>, S: Service, { fn clone(&self) -> Self { Self { srv: self.srv.clone(), _phantom: PhantomData, } } } impl ServiceFactory for ApplyConfigServiceFactory where SF: ServiceFactory, SF::InitError: From, F: Fn(Cfg, &SF::Service) -> Fut, Fut: Future>, S: Service, { type Response = S::Response; type Error = S::Error; type Config = Cfg; type Service = S; type InitError = SF::InitError; type Future = ApplyConfigServiceFactoryResponse; fn new_service(&self, cfg: Cfg) -> Self::Future { ApplyConfigServiceFactoryResponse { cfg: Some(cfg), store: self.srv.clone(), state: State::A { fut: self.srv.0.new_service(()), }, } } } pin_project! { struct ApplyConfigServiceFactoryResponse where SF: ServiceFactory, SF::InitError: From, F: Fn(Cfg, &SF::Service) -> Fut, Fut: Future>, S: Service, { cfg: Option, store: Rc<(SF, F)>, #[pin] state: State, } } pin_project! { #[project = StateProj] enum State where SF: ServiceFactory, SF::InitError: From, Fut: Future>, S: Service, { A { #[pin] fut: SF::Future }, B { svc: SF::Service }, C { #[pin] fut: Fut }, } } impl Future for ApplyConfigServiceFactoryResponse where SF: ServiceFactory, SF::InitError: From, F: Fn(Cfg, &SF::Service) -> Fut, Fut: Future>, S: Service, { type Output = Result; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let mut this = self.as_mut().project(); match this.state.as_mut().project() { StateProj::A { fut } => { let svc = ready!(fut.poll(cx))?; this.state.set(State::B { svc }); self.poll(cx) } StateProj::B { svc } => { ready!(svc.poll_ready(cx))?; { let (_, f) = &**this.store; let fut = f(this.cfg.take().unwrap(), svc); this.state.set(State::C { fut }); } self.poll(cx) } StateProj::C { fut } => fut.poll(cx), } } }