use std::marker::PhantomData; use futures::future::Future; use futures::{try_ready, Async, IntoFuture, Poll}; use crate::cell::Cell; use crate::{IntoService, NewService, Service}; /// Convert `Fn(&Config, &mut Service) -> Future` fn to a NewService pub fn apply_cfg( srv: T, f: F, ) -> impl NewService< Config = C, Request = S::Request, Response = S::Response, Error = S::Error, Service = S, InitError = R::Error, > + Clone where F: FnMut(&C, &mut T) -> R, T: Service, R: IntoFuture, R::Item: IntoService, S: Service, { ApplyConfigService { f: Cell::new(f), srv: Cell::new(srv.into_service()), _t: PhantomData, } } /// Convert `Fn(&Config, &mut Service) -> Future` fn to a NewService /// Service get constructor from NewService. pub fn new_apply_cfg( srv: T, f: F, ) -> impl NewService< 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: NewService, R: IntoFuture, R::Item: IntoService, S: Service, { ApplyConfigNewService { f: Cell::new(f), srv: Cell::new(srv), _t: PhantomData, } } /// Convert `Fn(&Config) -> Future` fn to NewService struct ApplyConfigService where F: FnMut(&C, &mut T) -> R, T: Service, R: IntoFuture, R::Item: IntoService, 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: IntoFuture, R::Item: IntoService, S: Service, { fn clone(&self) -> Self { ApplyConfigService { f: self.f.clone(), srv: self.srv.clone(), _t: PhantomData, } } } impl NewService for ApplyConfigService where F: FnMut(&C, &mut T) -> R, T: Service, R: IntoFuture, R::Item: IntoService, S: Service, { type Config = C; type Request = S::Request; type Response = S::Response; type Error = S::Error; type Service = S; type InitError = R::Error; 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()) } .into_future(), _t: PhantomData, } } } struct FnNewServiceConfigFut where R: IntoFuture, R::Item: IntoService, S: Service, { fut: R::Future, _t: PhantomData<(S,)>, } impl Future for FnNewServiceConfigFut where R: IntoFuture, R::Item: IntoService, S: Service, { type Item = S; type Error = R::Error; fn poll(&mut self) -> Poll { Ok(Async::Ready(try_ready!(self.fut.poll()).into_service())) } } /// Convert `Fn(&Config) -> Future` fn to NewService struct ApplyConfigNewService where C: Clone, F: FnMut(&C, &mut T::Service) -> R, T: NewService, R: IntoFuture, R::Item: IntoService, 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: NewService, R: IntoFuture, R::Item: IntoService, S: Service, { fn clone(&self) -> Self { ApplyConfigNewService { f: self.f.clone(), srv: self.srv.clone(), _t: PhantomData, } } } impl NewService for ApplyConfigNewService where C: Clone, F: FnMut(&C, &mut T::Service) -> R, T: NewService, R: IntoFuture, R::Item: IntoService, S: Service, { type Config = C; type Request = S::Request; type Response = S::Response; type Error = S::Error; type Service = S; type InitError = R::Error; type Future = ApplyConfigNewServiceFut; fn new_service(&self, cfg: &C) -> Self::Future { ApplyConfigNewServiceFut { f: self.f.clone(), cfg: cfg.clone(), srv: Some(self.srv.get_ref().new_service(&())), fut: None, _t: PhantomData, } } } struct ApplyConfigNewServiceFut where C: Clone, F: FnMut(&C, &mut T::Service) -> R, T: NewService, R: IntoFuture, R::Item: IntoService, S: Service, { cfg: C, f: Cell, srv: Option, fut: Option, _t: PhantomData<(S,)>, } impl Future for ApplyConfigNewServiceFut where C: Clone, F: FnMut(&C, &mut T::Service) -> R, T: NewService, R: IntoFuture, R::Item: IntoService, S: Service, { type Item = S; type Error = R::Error; fn poll(&mut self) -> Poll { if let Some(ref mut fut) = self.srv { match fut.poll()? { Async::NotReady => return Ok(Async::NotReady), Async::Ready(mut srv) => { let _ = self.srv.take(); self.fut = Some(self.f.get_mut()(&self.cfg, &mut srv).into_future()); return self.poll(); } } } if let Some(ref mut fut) = self.fut { Ok(Async::Ready(try_ready!(fut.poll()).into_service())) } else { Ok(Async::NotReady) } } }