diff --git a/actix-service/CHANGES.md b/actix-service/CHANGES.md index 57f37154..f28218e6 100644 --- a/actix-service/CHANGES.md +++ b/actix-service/CHANGES.md @@ -1,5 +1,12 @@ # Changes +## [0.3.2] - 2019-03-xx + +### Added + +* Add `ApplyTransform` new service for transform and new service. + + ## [0.3.2] - 2019-03-04 ### Changed diff --git a/actix-service/src/lib.rs b/actix-service/src/lib.rs index 7c14cf0a..4b58c231 100644 --- a/actix-service/src/lib.rs +++ b/actix-service/src/lib.rs @@ -23,7 +23,7 @@ mod transform; mod transform_map_init_err; pub use self::and_then::{AndThen, AndThenNewService}; -pub use self::and_then_apply::AndThenTransform; +use self::and_then_apply::AndThenTransform; use self::and_then_apply_fn::{AndThenApply, AndThenApplyNewService}; pub use self::apply::{Apply, ApplyNewService}; pub use self::fn_service::{fn_cfg_factory, fn_factory, fn_service, FnService}; @@ -33,7 +33,7 @@ pub use self::map::{Map, MapNewService}; pub use self::map_err::{MapErr, MapErrNewService}; pub use self::map_init_err::MapInitErr; pub use self::then::{Then, ThenNewService}; -pub use self::transform::{IntoTransform, Transform}; +pub use self::transform::{ApplyTransform, IntoTransform, Transform}; /// An asynchronous function from `Request` to a `Response`. pub trait Service { diff --git a/actix-service/src/transform.rs b/actix-service/src/transform.rs index 7e5ba920..741d91a6 100644 --- a/actix-service/src/transform.rs +++ b/actix-service/src/transform.rs @@ -1,10 +1,10 @@ use std::rc::Rc; use std::sync::Arc; -use futures::IntoFuture; +use futures::{Async, Future, IntoFuture, Poll}; use crate::transform_map_init_err::TransformMapInitErr; -use crate::Service; +use crate::{NewService, Service}; /// `Transform` service factory. /// @@ -96,3 +96,80 @@ where self } } + +/// `Apply` transform new service +#[derive(Clone)] +pub struct ApplyTransform<T, A, C> { + a: A, + t: Rc<T>, + _t: std::marker::PhantomData<C>, +} + +impl<T, A, C> ApplyTransform<T, A, C> +where + A: NewService<C>, + T: Transform<A::Service, Error = A::Error, InitError = A::InitError>, +{ + /// Create new `ApplyNewService` new service instance + pub fn new<F: IntoTransform<T, A::Service>>(t: F, a: A) -> Self { + Self { + a, + t: Rc::new(t.into_transform()), + _t: std::marker::PhantomData, + } + } +} + +impl<T, A, C> NewService<C> for ApplyTransform<T, A, C> +where + A: NewService<C>, + T: Transform<A::Service, Error = A::Error, InitError = A::InitError>, +{ + type Request = T::Request; + type Response = T::Response; + type Error = T::Error; + + type Service = T::Transform; + type InitError = T::InitError; + type Future = ApplyTransformFuture<T, A, C>; + + fn new_service(&self, cfg: &C) -> Self::Future { + ApplyTransformFuture { + t_cell: self.t.clone(), + fut_a: self.a.new_service(cfg).into_future(), + fut_t: None, + } + } +} + +pub struct ApplyTransformFuture<T, A, C> +where + A: NewService<C>, + T: Transform<A::Service, Error = A::Error, InitError = A::InitError>, +{ + fut_a: <A::Future as IntoFuture>::Future, + fut_t: Option<<T::Future as IntoFuture>::Future>, + t_cell: Rc<T>, +} + +impl<T, A, C> Future for ApplyTransformFuture<T, A, C> +where + A: NewService<C>, + T: Transform<A::Service, Error = A::Error, InitError = A::InitError>, +{ + type Item = T::Transform; + type Error = T::InitError; + + fn poll(&mut self) -> Poll<Self::Item, Self::Error> { + if self.fut_t.is_none() { + if let Async::Ready(service) = self.fut_a.poll()? { + self.fut_t = Some(self.t_cell.new_transform(service).into_future()); + } + } + if let Some(ref mut fut) = self.fut_t { + fut.poll() + } else { + Ok(Async::NotReady) + } + } +}