use std::future::Future; use std::marker::PhantomData; use std::pin::Pin; use std::task::{Context, Poll}; use futures::ready; use pin_project::pin_project; use crate::cell::Cell; use crate::{IntoService, Service, ServiceFactory}; /// Convert `Fn(&Config, &mut Service) -> Future` fn to a NewService pub fn apply_cfg( srv: T, f: F, ) -> impl ServiceFactory< Config = C, Request = S::Request, Response = S::Response, Error = S::Error, Service = S, InitError = E, > + Clone where F: FnMut(&C, &mut T) -> R, T: Service, R: Future>, 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, ) -> impl ServiceFactory< Config = C, Request = S::Request, Response = S::Response, Error = S::Error, Service = S, InitError = T::InitError, > + Clone where C: Clone, F: FnMut(&C, &mut T::Service) -> R, T: ServiceFactory, T::InitError: From, R: Future>, S: Service, { ApplyConfigNewService { f: Cell::new(f), srv: Cell::new(srv), _t: PhantomData, } } /// Convert `Fn(&Config) -> Future` fn to NewService\ #[pin_project] struct ApplyConfigService where F: FnMut(&C, &mut T) -> R, T: Service, R: Future>, S: Service, { f: Cell, #[pin] 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, R: Future>, 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 = FnNewServiceConfigFut; fn new_service(&self, cfg: &C) -> Self::Future { FnNewServiceConfigFut { fut: unsafe { (self.f.get_mut_unsafe())(cfg, self.srv.get_mut_unsafe()) }, _t: PhantomData, } } } #[pin_project] struct FnNewServiceConfigFut where R: Future>, S: Service, { #[pin] fut: R, _t: PhantomData<(S,)>, } impl Future for FnNewServiceConfigFut where R: Future>, S: Service, { type Output = Result; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { Poll::Ready(Ok(ready!(self.project().fut.poll(cx))?.into_service())) } } /// Convert `Fn(&Config) -> Future` fn to NewService struct ApplyConfigNewService 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 ApplyConfigNewService where C: Clone, F: FnMut(&C, &mut T::Service) -> R, T: ServiceFactory, R: Future>, S: Service, { fn clone(&self) -> Self { ApplyConfigNewService { f: self.f.clone(), srv: self.srv.clone(), _t: PhantomData, } } } impl ServiceFactory for ApplyConfigNewService where C: Clone, F: FnMut(&C, &mut T::Service) -> R, T: ServiceFactory, T::InitError: From, R: Future>, 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 = ApplyConfigNewServiceFut; fn new_service(&self, cfg: &C) -> Self::Future { ApplyConfigNewServiceFut { f: self.f.clone(), cfg: cfg.clone(), fut: None, srv: None, srv_fut: Some(self.srv.get_ref().new_service(&())), _t: PhantomData, } } } #[pin_project] struct ApplyConfigNewServiceFut 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, #[pin] srv_fut: Option, #[pin] fut: Option, _t: PhantomData<(S,)>, } impl Future for ApplyConfigNewServiceFut where C: Clone, F: FnMut(&C, &mut T::Service) -> R, T: ServiceFactory, T::InitError: From, R: Future>, S: Service, { type Output = Result; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let mut this = self.project(); 'poll: loop { if let Some(fut) = this.srv_fut.as_mut().as_pin_mut() { match fut.poll(cx)? { Poll::Pending => return Poll::Pending, Poll::Ready(srv) => { this.srv_fut.set(None); *this.srv = Some(srv); continue 'poll; } } } if let Some(fut) = this.fut.as_mut().as_pin_mut() { return Poll::Ready(Ok(ready!(fut.poll(cx))?.into_service())); } else if let Some(ref mut srv) = this.srv { match srv.poll_ready(cx)? { Poll::Ready(_) => { this.fut.set(Some(this.f.get_mut()(&this.cfg, srv))); continue 'poll; } Poll::Pending => return Poll::Pending, } } else { return Poll::Pending; } } } }