use std::cell::RefCell; use std::future::Future; use std::marker::PhantomData; use std::pin::Pin; use std::rc::Rc; use std::task::{Context, Poll}; use crate::{Service, ServiceFactory}; /// Convert `Fn(Config, &mut 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: FnMut(Cfg, &mut S1) -> Fut, Fut: Future>, S2: Service, { ApplyConfigService { srv: Rc::new(RefCell::new((srv, f))), _phantom: PhantomData, } } /// Convert `Fn(Config, &mut 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: FnMut(Cfg, &mut SF::Service) -> Fut, SF::InitError: From, Fut: Future>, S: Service, { ApplyConfigServiceFactory { srv: Rc::new(RefCell::new((factory, f))), _phantom: PhantomData, } } /// Convert `Fn(Config, &mut Server) -> Future` fn to NewService\ struct ApplyConfigService where S1: Service, F: FnMut(Cfg, &mut S1) -> Fut, Fut: Future>, S2: Service, { srv: Rc>, _phantom: PhantomData<(Cfg, Req, Fut, S2)>, } impl Clone for ApplyConfigService where S1: Service, F: FnMut(Cfg, &mut 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: FnMut(Cfg, &mut S1) -> Fut, Fut: Future>, S2: Service, { type Config = Cfg; type Response = S2::Response; type Error = S2::Error; type Service = S2; type InitError = Err; type Future = Fut; fn new_service(&self, cfg: Cfg) -> Self::Future { let (t, f) = &mut *self.srv.borrow_mut(); f(cfg, t) } } /// Convert `Fn(&Config) -> Future` fn to NewService struct ApplyConfigServiceFactory where SF: ServiceFactory, F: FnMut(Cfg, &mut SF::Service) -> Fut, Fut: Future>, S: Service, { srv: Rc>, _phantom: PhantomData<(Cfg, Req, Fut, S)>, } impl Clone for ApplyConfigServiceFactory where SF: ServiceFactory, F: FnMut(Cfg, &mut 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: FnMut(Cfg, &mut SF::Service) -> Fut, Fut: Future>, S: Service, { type Config = Cfg; type Response = S::Response; type Error = S::Error; 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(self.srv.borrow().0.new_service(())), } } } #[pin_project::pin_project] struct ApplyConfigServiceFactoryResponse where SF: ServiceFactory, SF::InitError: From, F: FnMut(Cfg, &mut SF::Service) -> Fut, Fut: Future>, S: Service, { cfg: Option, store: Rc>, #[pin] state: State, } #[pin_project::pin_project(project = StateProj)] enum State where SF: ServiceFactory, SF::InitError: From, Fut: Future>, S: Service, { A(#[pin] SF::Future), B(SF::Service), C(#[pin] Fut), } impl Future for ApplyConfigServiceFactoryResponse where SF: ServiceFactory, SF::InitError: From, F: FnMut(Cfg, &mut 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) => match fut.poll(cx)? { Poll::Pending => Poll::Pending, Poll::Ready(srv) => { this.state.set(State::B(srv)); self.poll(cx) } }, StateProj::B(srv) => match srv.poll_ready(cx)? { Poll::Ready(_) => { { let (_, f) = &mut *this.store.borrow_mut(); let fut = f(this.cfg.take().unwrap(), srv); this.state.set(State::C(fut)); } self.poll(cx) } Poll::Pending => Poll::Pending, }, StateProj::C(fut) => fut.poll(cx), } } }