use std::future::Future; use std::marker::PhantomData; use std::pin::Pin; use std::task::{Context, Poll}; use crate::cell::Cell; use crate::{Service, ServiceFactory}; /// Convert `Fn(&Config, &mut Service) -> Future` fn to a NewService pub fn apply_cfg(srv: T, f: F) -> ApplyConfigService where F: FnMut(&C, &mut T) -> R, T: Service, R: Future> + Unpin, S: Service, { ApplyConfigService { f: Cell::new(f), srv: Cell::new(srv), _t: PhantomData, } } /// Convert `Fn(&Config, &mut Service) -> Future` fn to a NewService /// Service get constructor from NewService. pub fn apply_cfg_factory( srv: T, f: F, ) -> ApplyConfigServiceFactory where C: Clone, F: FnMut(&C, &mut T::Service) -> R, T: ServiceFactory, T::InitError: From, R: Future>, S: Service, { ApplyConfigServiceFactory { f: Cell::new(f), srv: Cell::new(srv), _t: PhantomData, } } /// Convert `Fn(&Config) -> Future` fn to NewService\ pub struct ApplyConfigService where F: FnMut(&C, &mut T) -> R, T: Service, R: Future>, S: Service, { f: Cell, srv: Cell, _t: PhantomData<(C, R, S)>, } impl Clone for ApplyConfigService where F: FnMut(&C, &mut T) -> R, T: Service, R: Future>, S: Service, { fn clone(&self) -> Self { ApplyConfigService { f: self.f.clone(), srv: self.srv.clone(), _t: PhantomData, } } } impl ServiceFactory for ApplyConfigService where F: FnMut(&C, &mut T) -> R, T: Service, T::Future: Unpin, R: Future> + Unpin, S: Service, { type Config = C; type Request = S::Request; type Response = S::Response; type Error = S::Error; type Service = S; type InitError = E; type Future = ApplyConfigServiceResponse; fn new_service(&self, cfg: &C) -> Self::Future { ApplyConfigServiceResponse { fut: unsafe { (self.f.get_mut_unsafe())(cfg, self.srv.get_mut_unsafe()) }, _t: PhantomData, } } } pub struct ApplyConfigServiceResponse where R: Future>, S: Service, { fut: R, _t: PhantomData<(S,)>, } impl Unpin for ApplyConfigServiceResponse where R: Future> + Unpin, S: Service, { } impl Future for ApplyConfigServiceResponse where R: Future> + Unpin, S: Service, { type Output = Result; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { Pin::new(&mut self.get_mut().fut).poll(cx) } } /// Convert `Fn(&Config) -> Future` fn to NewService pub struct ApplyConfigServiceFactory where C: Clone, F: FnMut(&C, &mut T::Service) -> R, T: ServiceFactory, R: Future>, S: Service, { f: Cell, srv: Cell, _t: PhantomData<(C, R, S)>, } impl Clone for ApplyConfigServiceFactory where C: Clone, F: FnMut(&C, &mut T::Service) -> R, T: ServiceFactory, R: Future>, S: Service, { fn clone(&self) -> Self { Self { f: self.f.clone(), srv: self.srv.clone(), _t: PhantomData, } } } impl ServiceFactory for ApplyConfigServiceFactory where C: Clone, F: FnMut(&C, &mut T::Service) -> R, T: ServiceFactory, T::Future: Unpin, T::InitError: From, R: Future> + Unpin, S: Service, { type Config = C; type Request = S::Request; type Response = S::Response; type Error = S::Error; type Service = S; type InitError = T::InitError; type Future = ApplyConfigServiceFactoryResponse; fn new_service(&self, cfg: &C) -> Self::Future { ApplyConfigServiceFactoryResponse { f: self.f.clone(), cfg: cfg.clone(), fut: None, srv: None, srv_fut: Some(self.srv.get_ref().new_service(&())), _t: PhantomData, } } } pub struct ApplyConfigServiceFactoryResponse where C: Clone, F: FnMut(&C, &mut T::Service) -> R, T: ServiceFactory, T::InitError: From, R: Future>, S: Service, { cfg: C, f: Cell, srv: Option, srv_fut: Option, fut: Option, _t: PhantomData<(S,)>, } impl Unpin for ApplyConfigServiceFactoryResponse where C: Clone, F: FnMut(&C, &mut T::Service) -> R, T: ServiceFactory, T::Future: Unpin, T::InitError: From, R: Future> + Unpin, S: Service, { } impl Future for ApplyConfigServiceFactoryResponse where C: Clone, F: FnMut(&C, &mut T::Service) -> R, T: ServiceFactory, T::Future: Unpin, T::InitError: From, R: Future> + Unpin, S: Service, { type Output = Result; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this = self.get_mut(); loop { if let Some(ref mut fut) = this.srv_fut { match Pin::new(fut).poll(cx)? { Poll::Pending => return Poll::Pending, Poll::Ready(srv) => { let _ = this.srv_fut.take(); this.srv = Some(srv); continue; } } } if let Some(ref mut fut) = this.fut { return Pin::new(fut).poll(cx); } else if let Some(ref mut srv) = this.srv { match srv.poll_ready(cx)? { Poll::Ready(_) => { this.fut = Some(this.f.get_mut()(&this.cfg, srv)); continue; } Poll::Pending => return Poll::Pending, } } else { return Poll::Pending; } } } }