diff --git a/actix-connect/Cargo.toml b/actix-connect/Cargo.toml index 1d019e25..23219e7a 100644 --- a/actix-connect/Cargo.toml +++ b/actix-connect/Cargo.toml @@ -33,7 +33,7 @@ openssl = ["open-ssl", "tokio-openssl"] uri = ["http"] [dependencies] -actix-service = "1.0.0-alpha.2" +actix-service = "1.0.0-alpha.3" actix-codec = "0.2.0-alpha.2" actix-utils = "1.0.0-alpha.2" actix-rt = "1.0.0-alpha.2" diff --git a/actix-ioframe/Cargo.toml b/actix-ioframe/Cargo.toml index 696a8d33..c7f3f9a2 100644 --- a/actix-ioframe/Cargo.toml +++ b/actix-ioframe/Cargo.toml @@ -18,7 +18,7 @@ name = "actix_ioframe" path = "src/lib.rs" [dependencies] -actix-service = "1.0.0-alpha.2" +actix-service = "1.0.0-alpha.3" actix-codec = "0.2.0-alpha.2" actix-utils = "1.0.0-alpha.2" actix-rt = "1.0.0-alpha.2" diff --git a/actix-server/Cargo.toml b/actix-server/Cargo.toml index 9c7724d0..cb35c7c0 100644 --- a/actix-server/Cargo.toml +++ b/actix-server/Cargo.toml @@ -21,7 +21,7 @@ path = "src/lib.rs" default = [] [dependencies] -actix-service = "1.0.0-alpha.2" +actix-service = "1.0.0-alpha.3" actix-rt = "1.0.0-alpha.2" actix-codec = "0.2.0-alpha.2" actix-utils = "1.0.0-alpha.2" diff --git a/actix-service/CHANGES.md b/actix-service/CHANGES.md index 04d7b792..27cbbabb 100644 --- a/actix-service/CHANGES.md +++ b/actix-service/CHANGES.md @@ -2,17 +2,24 @@ ## [1.0.0-alpha.3] - 2019-12-xx -### Add missing Clone impls +### Changed -### Restore `Transform::map_init_err()` combinator +* Add missing Clone impls + +* Restore `Transform::map_init_err()` combinator + +* Restore `Service/Factory::apply_fn()` in form of `Pipeline/Factory::and_then_apply_fn()` + +* Optimize service combinators and futures memory layout -### Restore `Service/Factory::apply_fn()` in form of `Pipeline/Factory::and_then_apply_fn()` ## [1.0.0-alpha.2] - 2019-12-02 -### Use owned config value for service factory +### Changed -### Renamed BoxedNewService/BoxedService to BoxServiceFactory/BoxService +* Use owned config value for service factory + +* Renamed BoxedNewService/BoxedService to BoxServiceFactory/BoxService ## [1.0.0-alpha.1] - 2019-11-25 diff --git a/actix-service/Cargo.toml b/actix-service/Cargo.toml index 5f0a2b1b..14444def 100644 --- a/actix-service/Cargo.toml +++ b/actix-service/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-service" -version = "1.0.0-alpha.2" +version = "1.0.0-alpha.3" authors = ["Nikolay Kim "] description = "Actix Service" keywords = ["network", "framework", "async", "futures"] @@ -23,8 +23,8 @@ name = "actix_service" path = "src/lib.rs" [dependencies] -futures = "0.3.1" -pin-project-lite = "0.1.1" +futures-util = "0.3.1" +pin-project = "0.4.6" [dev-dependencies] actix-rt = "1.0.0-alpha.2" diff --git a/actix-service/src/and_then.rs b/actix-service/src/and_then.rs index 14bfcac7..1c7d52b4 100644 --- a/actix-service/src/and_then.rs +++ b/actix-service/src/and_then.rs @@ -9,10 +9,7 @@ use crate::cell::Cell; /// of another service which completes successfully. /// /// This is created by the `ServiceExt::and_then` method. -pub struct AndThenService { - a: A, - b: Cell, -} +pub struct AndThenService(Cell<(A, B)>); impl AndThenService { /// Create new `AndThen` combinator @@ -21,19 +18,13 @@ impl AndThenService { A: Service, B: Service, { - Self { a, b: Cell::new(b) } + Self(Cell::new((a, b))) } } -impl Clone for AndThenService -where - A: Clone, -{ +impl Clone for AndThenService { fn clone(&self) -> Self { - AndThenService { - a: self.a.clone(), - b: self.b.clone(), - } + AndThenService(self.0.clone()) } } @@ -48,8 +39,10 @@ where type Future = AndThenServiceResponse; fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - let not_ready = !self.a.poll_ready(cx)?.is_ready(); - if !self.b.get_mut().poll_ready(cx)?.is_ready() || not_ready { + let srv = self.0.get_mut(); + + let not_ready = !srv.0.poll_ready(cx)?.is_ready(); + if !srv.1.poll_ready(cx)?.is_ready() || not_ready { Poll::Pending } else { Poll::Ready(Ok(())) @@ -57,36 +50,30 @@ where } fn call(&mut self, req: A::Request) -> Self::Future { - AndThenServiceResponse::new(self.a.call(req), self.b.clone()) + AndThenServiceResponse { + state: State::A(self.0.get_mut().0.call(req), self.0.clone()), + } } } -pin_project! { - pub struct AndThenServiceResponse - where - A: Service, - B: Service, - { - b: Cell, - #[pin] - fut_b: Option, - #[pin] - fut_a: Option, - } -} - -impl AndThenServiceResponse +#[pin_project::pin_project] +pub struct AndThenServiceResponse where A: Service, B: Service, { - fn new(a: A::Future, b: Cell) -> Self { - AndThenServiceResponse { - b, - fut_a: Some(a), - fut_b: None, - } - } + #[pin] + state: State, +} + +#[pin_project::pin_project] +enum State +where + A: Service, + B: Service, +{ + A(#[pin] A::Future, Cell<(A, B)>), + B(#[pin] B::Future), } impl Future for AndThenServiceResponse @@ -96,28 +83,21 @@ where { type Output = Result; + #[pin_project::project] fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let mut this = self.as_mut().project(); - loop { - if let Some(fut) = this.fut_b.as_pin_mut() { - return fut.poll(cx); - } - - match this - .fut_a - .as_pin_mut() - .expect("Bug in actix-service") - .poll(cx) - { - Poll::Ready(Ok(resp)) => { - this = self.as_mut().project(); - this.fut_a.set(None); - this.fut_b.set(Some(this.b.get_mut().call(resp))); + #[project] + match this.state.as_mut().project() { + State::A(fut, b) => match fut.poll(cx)? { + Poll::Ready(res) => { + let fut = b.get_mut().1.call(res); + this.state.set(State::B(fut)); + self.poll(cx) } - Poll::Ready(Err(e)) => return Poll::Ready(Err(e)), - Poll::Pending => return Poll::Pending, - } + Poll::Pending => Poll::Pending, + }, + State::B(fut) => fut.poll(cx), } } } @@ -202,20 +182,19 @@ where } } -pin_project! { - pub struct AndThenServiceFactoryResponse - where - A: ServiceFactory, - B: ServiceFactory, - { - #[pin] - fut_b: B::Future, - #[pin] - fut_a: A::Future, +#[pin_project::pin_project] +pub struct AndThenServiceFactoryResponse +where + A: ServiceFactory, + B: ServiceFactory, +{ + #[pin] + fut_a: A::Future, + #[pin] + fut_b: B::Future, - a: Option, - b: Option, - } + a: Option, + b: Option, } impl AndThenServiceFactoryResponse @@ -270,7 +249,7 @@ mod tests { use std::rc::Rc; use std::task::{Context, Poll}; - use futures::future::{lazy, ok, ready, Ready}; + use futures_util::future::{lazy, ok, ready, Ready}; use crate::{factory_fn, pipeline, pipeline_factory, Service, ServiceFactory}; diff --git a/actix-service/src/and_then_apply_fn.rs b/actix-service/src/and_then_apply_fn.rs index a372a2f3..3ae7e59f 100644 --- a/actix-service/src/and_then_apply_fn.rs +++ b/actix-service/src/and_then_apply_fn.rs @@ -3,8 +3,6 @@ use std::marker::PhantomData; use std::pin::Pin; use std::task::{Context, Poll}; -use futures::ready; - use crate::cell::Cell; use crate::{Service, ServiceFactory}; @@ -18,8 +16,7 @@ where Err: From + From, { a: A, - b: Cell, - f: Cell, + b: Cell<(B, F)>, r: PhantomData<(Fut, Res, Err)>, } @@ -35,8 +32,7 @@ where pub(crate) fn new(a: A, b: B, f: F) -> Self { Self { a, - f: Cell::new(f), - b: Cell::new(b), + b: Cell::new((b, f)), r: PhantomData, } } @@ -54,7 +50,6 @@ where AndThenApplyFn { a: self.a.clone(), b: self.b.clone(), - f: self.f.clone(), r: PhantomData, } } @@ -75,7 +70,7 @@ where fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { let not_ready = self.a.poll_ready(cx)?.is_pending(); - if self.b.get_mut().poll_ready(cx)?.is_pending() || not_ready { + if self.b.get_mut().0.poll_ready(cx)?.is_pending() || not_ready { Poll::Pending } else { Poll::Ready(Ok(())) @@ -84,31 +79,37 @@ where fn call(&mut self, req: A::Request) -> Self::Future { AndThenApplyFnFuture { - b: self.b.clone(), - f: self.f.clone(), - fut_a: Some(self.a.call(req)), - fut_b: None, + state: State::A(self.a.call(req), self.b.clone()), } } } -pin_project! { - pub struct AndThenApplyFnFuture - where - A: Service, - B: Service, - F: FnMut(A::Response, &mut B) -> Fut, - Fut: Future>, - Err: From, - Err: From, - { - b: Cell, - f: Cell, - #[pin] - fut_a: Option, - #[pin] - fut_b: Option, - } +#[pin_project::pin_project] +pub struct AndThenApplyFnFuture +where + A: Service, + B: Service, + F: FnMut(A::Response, &mut B) -> Fut, + Fut: Future>, + Err: From, + Err: From, +{ + #[pin] + state: State, +} + +#[pin_project::pin_project] +enum State +where + A: Service, + B: Service, + F: FnMut(A::Response, &mut B) -> Fut, + Fut: Future>, + Err: From, + Err: From, +{ + A(#[pin] A::Future, Cell<(B, F)>), + B(#[pin] Fut), } impl Future for AndThenApplyFnFuture @@ -121,28 +122,22 @@ where { type Output = Result; + #[pin_project::project] fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let mut this = self.as_mut().project(); - if let Some(fut) = this.fut_b.as_pin_mut() { - return Poll::Ready(ready!(fut.poll(cx)).map_err(|e| e.into())); - } - - match this - .fut_a - .as_pin_mut() - .expect("Bug in actix-service") - .poll(cx) - { - Poll::Ready(Ok(resp)) => { - this = self.as_mut().project(); - this.fut_b - .set(Some((&mut *this.f.get_mut())(resp, this.b.get_mut()))); - this.fut_a.set(None); - self.poll(cx) - } - Poll::Pending => Poll::Pending, - Poll::Ready(Err(err)) => Poll::Ready(Err(err.into())), + #[project] + match this.state.as_mut().project() { + State::A(fut, b) => match fut.poll(cx)? { + Poll::Ready(res) => { + let b = b.get_mut(); + let fut = (&mut b.1)(res, &mut b.0); + this.state.set(State::B(fut)); + self.poll(cx) + } + Poll::Pending => Poll::Pending, + }, + State::B(fut) => fut.poll(cx), } } } @@ -151,7 +146,7 @@ where pub struct AndThenApplyFnFactory { a: A, b: B, - f: Cell, + f: F, r: PhantomData<(Fut, Res, Err)>, } @@ -159,7 +154,7 @@ impl AndThenApplyFnFactory where A: ServiceFactory, B: ServiceFactory, - F: FnMut(A::Response, &mut B::Service) -> Fut, + F: FnMut(A::Response, &mut B::Service) -> Fut + Clone, Fut: Future>, Err: From + From, { @@ -168,7 +163,7 @@ where Self { a: a, b: b, - f: Cell::new(f), + f: f, r: PhantomData, } } @@ -178,6 +173,7 @@ impl Clone for AndThenApplyFnFactory Self { Self { @@ -194,7 +190,7 @@ where A: ServiceFactory, A::Config: Clone, B: ServiceFactory, - F: FnMut(A::Response, &mut B::Service) -> Fut, + F: FnMut(A::Response, &mut B::Service) -> Fut + Clone, Fut: Future>, Err: From + From, { @@ -217,31 +213,30 @@ where } } -pin_project! { - pub struct AndThenApplyFnFactoryResponse - where - A: ServiceFactory, - B: ServiceFactory, - F: FnMut(A::Response, &mut B::Service) -> Fut, - Fut: Future>, - Err: From, - Err: From, - { - #[pin] - fut_b: B::Future, - #[pin] - fut_a: A::Future, - f: Cell, - a: Option, - b: Option, - } +#[pin_project::pin_project] +pub struct AndThenApplyFnFactoryResponse +where + A: ServiceFactory, + B: ServiceFactory, + F: FnMut(A::Response, &mut B::Service) -> Fut + Clone, + Fut: Future>, + Err: From, + Err: From, +{ + #[pin] + fut_b: B::Future, + #[pin] + fut_a: A::Future, + f: F, + a: Option, + b: Option, } impl Future for AndThenApplyFnFactoryResponse where A: ServiceFactory, B: ServiceFactory, - F: FnMut(A::Response, &mut B::Service) -> Fut, + F: FnMut(A::Response, &mut B::Service) -> Fut + Clone, Fut: Future>, Err: From + From, { @@ -265,9 +260,8 @@ where if this.a.is_some() && this.b.is_some() { Poll::Ready(Ok(AndThenApplyFn { - f: this.f.clone(), a: this.a.take().unwrap(), - b: Cell::new(this.b.take().unwrap()), + b: Cell::new((this.b.take().unwrap(), this.f.clone())), r: PhantomData, })) } else { @@ -280,7 +274,7 @@ where mod tests { use super::*; - use futures::future::{lazy, ok, Ready, TryFutureExt}; + use futures_util::future::{lazy, ok, Ready, TryFutureExt}; use crate::{pipeline, pipeline_factory, service_fn2, Service, ServiceFactory}; diff --git a/actix-service/src/apply.rs b/actix-service/src/apply.rs index ae498160..2438057c 100644 --- a/actix-service/src/apply.rs +++ b/actix-service/src/apply.rs @@ -67,8 +67,8 @@ where type Error = Err; type Future = R; - fn poll_ready(&mut self, ctx: &mut Context<'_>) -> Poll> { - Poll::Ready(futures::ready!(self.service.poll_ready(ctx))) + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + Poll::Ready(futures_util::ready!(self.service.poll_ready(cx))) } fn call(&mut self, req: In) -> Self::Future { @@ -139,24 +139,23 @@ where } } -pin_project! { - pub struct ApplyServiceFactoryResponse - where - T: ServiceFactory, - F: FnMut(In, &mut T::Service) -> R, - R: Future>, - { - #[pin] - fut: T::Future, - f: Option, - r: PhantomData<(In, Out)>, - } +#[pin_project::pin_project] +pub struct ApplyServiceFactoryResponse +where + T: ServiceFactory, + F: FnMut(In, &mut T::Service) -> R, + R: Future>, +{ + #[pin] + fut: T::Future, + f: Option, + r: PhantomData<(In, Out)>, } impl ApplyServiceFactoryResponse where T: ServiceFactory, - F: FnMut(In, &mut T::Service) -> R + Clone, + F: FnMut(In, &mut T::Service) -> R, R: Future>, { fn new(fut: T::Future, f: F) -> Self { @@ -171,7 +170,7 @@ where impl Future for ApplyServiceFactoryResponse where T: ServiceFactory, - F: FnMut(In, &mut T::Service) -> R + Clone, + F: FnMut(In, &mut T::Service) -> R, R: Future>, { type Output = Result, T::InitError>; @@ -191,7 +190,7 @@ where mod tests { use std::task::{Context, Poll}; - use futures::future::{lazy, ok, Ready}; + use futures_util::future::{lazy, ok, Ready}; use super::*; use crate::{pipeline, pipeline_factory, Service, ServiceFactory}; diff --git a/actix-service/src/apply_cfg.rs b/actix-service/src/apply_cfg.rs index 5a9a615d..e6045321 100644 --- a/actix-service/src/apply_cfg.rs +++ b/actix-service/src/apply_cfg.rs @@ -15,8 +15,7 @@ where S: Service, { ApplyConfigService { - f: Cell::new(f), - srv: Cell::new(srv), + srv: Cell::new((srv, f)), _t: PhantomData, } } @@ -35,8 +34,7 @@ where S: Service, { ApplyConfigServiceFactory { - f: Cell::new(f), - srv: Cell::new(srv), + srv: Cell::new((srv, f)), _t: PhantomData, } } @@ -49,8 +47,7 @@ where R: Future>, S: Service, { - f: Cell, - srv: Cell, + srv: Cell<(T, F)>, _t: PhantomData<(C, R, S)>, } @@ -63,7 +60,6 @@ where { fn clone(&self) -> Self { ApplyConfigService { - f: self.f.clone(), srv: self.srv.clone(), _t: PhantomData, } @@ -87,7 +83,10 @@ where type Future = R; fn new_service(&self, cfg: C) -> Self::Future { - unsafe { (self.f.get_mut_unsafe())(cfg, self.srv.get_mut_unsafe()) } + unsafe { + let srv = self.srv.get_mut_unsafe(); + (srv.1)(cfg, &mut srv.0) + } } } @@ -99,8 +98,7 @@ where R: Future>, S: Service, { - f: Cell, - srv: Cell, + srv: Cell<(T, F)>, _t: PhantomData<(C, R, S)>, } @@ -113,7 +111,6 @@ where { fn clone(&self) -> Self { Self { - f: self.f.clone(), srv: self.srv.clone(), _t: PhantomData, } @@ -139,34 +136,39 @@ where fn new_service(&self, cfg: C) -> Self::Future { ApplyConfigServiceFactoryResponse { - f: self.f.clone(), cfg: Some(cfg), - fut: None, - srv: None, - srv_fut: Some(self.srv.get_ref().new_service(())), - _t: PhantomData, + store: self.srv.clone(), + state: State::A(self.srv.get_ref().0.new_service(())), } } } -pin_project! { - pub struct ApplyConfigServiceFactoryResponse - where - F: FnMut(C, &mut T::Service) -> R, - T: ServiceFactory, - T::InitError: From, - R: Future>, - S: Service, - { - cfg: Option, - f: Cell, - srv: Option, - #[pin] - srv_fut: Option, - #[pin] - fut: Option, - _t: PhantomData<(S,)>, - } +#[pin_project::pin_project] +pub struct ApplyConfigServiceFactoryResponse +where + F: FnMut(C, &mut T::Service) -> R, + T: ServiceFactory, + T::InitError: From, + R: Future>, + S: Service, +{ + cfg: Option, + store: Cell<(T, F)>, + #[pin] + state: State, +} + +#[pin_project::pin_project] +enum State +where + T: ServiceFactory, + T::InitError: From, + R: Future>, + S: Service, +{ + A(#[pin] T::Future), + B(T::Service), + C(#[pin] R), } impl Future for ApplyConfigServiceFactoryResponse @@ -179,37 +181,28 @@ where { type Output = Result; + #[pin_project::project] fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let mut this = self.as_mut().project(); - loop { - if let Some(fut) = this.srv_fut.as_pin_mut() { - match fut.poll(cx)? { - Poll::Pending => return Poll::Pending, - Poll::Ready(srv) => { - this = self.as_mut().project(); - this.srv_fut.set(None); - *this.srv = Some(srv); - continue; - } + #[project] + match this.state.as_mut().project() { + State::A(fut) => match fut.poll(cx)? { + Poll::Pending => Poll::Pending, + Poll::Ready(srv) => { + this.state.set(State::B(srv)); + self.poll(cx) } - } - - if let Some(fut) = this.fut.as_pin_mut() { - return fut.poll(cx); - } else if let Some(srv) = this.srv { - match srv.poll_ready(cx)? { - Poll::Ready(_) => { - let fut = this.f.get_mut()(this.cfg.take().unwrap(), srv); - this = self.as_mut().project(); - this.fut.set(Some(fut)); - continue; - } - Poll::Pending => return Poll::Pending, + }, + State::B(srv) => match srv.poll_ready(cx)? { + Poll::Ready(_) => { + let fut = (this.store.get_mut().1)(this.cfg.take().unwrap(), srv); + this.state.set(State::C(fut)); + self.poll(cx) } - } else { - return Poll::Pending; - } + Poll::Pending => Poll::Pending, + }, + State::C(fut) => fut.poll(cx), } } } diff --git a/actix-service/src/boxed.rs b/actix-service/src/boxed.rs index b3df048b..8afc343c 100644 --- a/actix-service/src/boxed.rs +++ b/actix-service/src/boxed.rs @@ -2,7 +2,7 @@ use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; -use futures::future::FutureExt; +use futures_util::future::FutureExt; use crate::{Service, ServiceFactory}; diff --git a/actix-service/src/cell.rs b/actix-service/src/cell.rs index 76afce4e..3bcac0be 100644 --- a/actix-service/src/cell.rs +++ b/actix-service/src/cell.rs @@ -1,4 +1,5 @@ //! Custom cell impl, internal use only +use std::task::{Context, Poll}; use std::{cell::UnsafeCell, fmt, rc::Rc}; pub(crate) struct Cell { @@ -39,3 +40,18 @@ impl Cell { &mut *self.inner.as_ref().get() } } + +impl crate::Service for Cell { + type Request = T::Request; + type Response = T::Response; + type Error = T::Error; + type Future = T::Future; + + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + self.get_mut().poll_ready(cx) + } + + fn call(&mut self, req: Self::Request) -> Self::Future { + self.get_mut().call(req) + } +} diff --git a/actix-service/src/fn_service.rs b/actix-service/src/fn_service.rs index 32781f73..c3d47d00 100644 --- a/actix-service/src/fn_service.rs +++ b/actix-service/src/fn_service.rs @@ -2,7 +2,7 @@ use std::future::Future; use std::marker::PhantomData; use std::task::{Context, Poll}; -use futures::future::{ok, Ready}; +use futures_util::future::{ok, Ready}; use crate::{IntoService, IntoServiceFactory, Service, ServiceFactory}; diff --git a/actix-service/src/lib.rs b/actix-service/src/lib.rs index 5bf29d4b..bd127063 100644 --- a/actix-service/src/lib.rs +++ b/actix-service/src/lib.rs @@ -1,9 +1,6 @@ #![deny(rust_2018_idioms, warnings)] #![allow(clippy::type_complexity)] -#[macro_use] -extern crate pin_project_lite; - use std::cell::RefCell; use std::future::Future; use std::rc::Rc; diff --git a/actix-service/src/map.rs b/actix-service/src/map.rs index e4dfc102..ec3520a1 100644 --- a/actix-service/src/map.rs +++ b/actix-service/src/map.rs @@ -62,16 +62,15 @@ where } } -pin_project! { - pub struct MapFuture - where - A: Service, - F: FnMut(A::Response) -> Response, - { - f: F, - #[pin] - fut: A::Future, - } +#[pin_project::pin_project] +pub struct MapFuture +where + A: Service, + F: FnMut(A::Response) -> Response, +{ + f: F, + #[pin] + fut: A::Future, } impl MapFuture @@ -157,16 +156,15 @@ where } } -pin_project! { - pub struct MapServiceFuture - where - A: ServiceFactory, - F: FnMut(A::Response) -> Res, - { - #[pin] - fut: A::Future, - f: Option, - } +#[pin_project::pin_project] +pub struct MapServiceFuture +where + A: ServiceFactory, + F: FnMut(A::Response) -> Res, +{ + #[pin] + fut: A::Future, + f: Option, } impl MapServiceFuture @@ -199,7 +197,7 @@ where #[cfg(test)] mod tests { - use futures::future::{lazy, ok, Ready}; + use futures_util::future::{lazy, ok, Ready}; use super::*; use crate::{IntoServiceFactory, Service, ServiceFactory}; diff --git a/actix-service/src/map_err.rs b/actix-service/src/map_err.rs index 86013867..ee7145c3 100644 --- a/actix-service/src/map_err.rs +++ b/actix-service/src/map_err.rs @@ -63,16 +63,15 @@ where } } -pin_project! { - pub struct MapErrFuture - where - A: Service, - F: Fn(A::Error) -> E, - { - f: F, - #[pin] - fut: A::Future, - } +#[pin_project::pin_project] +pub struct MapErrFuture +where + A: Service, + F: Fn(A::Error) -> E, +{ + f: F, + #[pin] + fut: A::Future, } impl MapErrFuture @@ -160,16 +159,15 @@ where } } -pin_project! { - pub struct MapErrServiceFuture - where - A: ServiceFactory, - F: Fn(A::Error) -> E, - { - #[pin] - fut: A::Future, - f: F, - } +#[pin_project::pin_project] +pub struct MapErrServiceFuture +where + A: ServiceFactory, + F: Fn(A::Error) -> E, +{ + #[pin] + fut: A::Future, + f: F, } impl MapErrServiceFuture @@ -201,7 +199,7 @@ where #[cfg(test)] mod tests { - use futures::future::{err, lazy, ok, Ready}; + use futures_util::future::{err, lazy, ok, Ready}; use super::*; use crate::{IntoServiceFactory, Service, ServiceFactory}; diff --git a/actix-service/src/map_init_err.rs b/actix-service/src/map_init_err.rs index e13e6453..b1eec072 100644 --- a/actix-service/src/map_init_err.rs +++ b/actix-service/src/map_init_err.rs @@ -60,16 +60,15 @@ where } } -pin_project! { - pub struct MapInitErrFuture - where - A: ServiceFactory, - F: Fn(A::InitError) -> E, - { - f: F, - #[pin] - fut: A::Future, - } +#[pin_project::pin_project] +pub struct MapInitErrFuture +where + A: ServiceFactory, + F: Fn(A::InitError) -> E, +{ + f: F, + #[pin] + fut: A::Future, } impl MapInitErrFuture diff --git a/actix-service/src/pipeline.rs b/actix-service/src/pipeline.rs index b49a8fee..c04a284e 100644 --- a/actix-service/src/pipeline.rs +++ b/actix-service/src/pipeline.rs @@ -197,7 +197,7 @@ impl PipelineFactory { T::Config: Clone, I: IntoServiceFactory, U: ServiceFactory, - F: FnMut(T::Response, &mut U::Service) -> Fut, + F: FnMut(T::Response, &mut U::Service) -> Fut + Clone, Fut: Future>, Err: From + From, { diff --git a/actix-service/src/then.rs b/actix-service/src/then.rs index 7b661d80..9741ddfa 100644 --- a/actix-service/src/then.rs +++ b/actix-service/src/then.rs @@ -57,36 +57,30 @@ where } fn call(&mut self, req: A::Request) -> Self::Future { - ThenServiceResponse::new(self.a.call(req), self.b.clone()) + ThenServiceResponse { + state: ThenServiceResponseState::A(self.a.call(req), self.b.clone()), + } } } -pin_project! { - pub struct ThenServiceResponse - where - A: Service, - B: Service>, - { - b: Cell, - #[pin] - fut_b: Option, - #[pin] - fut_a: Option, - } -} - -impl ThenServiceResponse +#[pin_project::pin_project] +pub struct ThenServiceResponse where A: Service, B: Service>, { - fn new(a: A::Future, b: Cell) -> Self { - ThenServiceResponse { - b, - fut_a: Some(a), - fut_b: None, - } - } + #[pin] + state: ThenServiceResponseState, +} + +#[pin_project::pin_project] +enum ThenServiceResponseState +where + A: Service, + B: Service>, +{ + A(#[pin] A::Future, Cell), + B(#[pin] B::Future), } impl Future for ThenServiceResponse @@ -96,27 +90,21 @@ where { type Output = Result; + #[pin_project::project] fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let mut this = self.as_mut().project(); - loop { - if let Some(fut) = this.fut_b.as_pin_mut() { - return fut.poll(cx); - } - - match this - .fut_a - .as_pin_mut() - .expect("Bug in actix-service") - .poll(cx) - { - Poll::Ready(r) => { - this = self.as_mut().project(); - this.fut_b.set(Some(this.b.get_mut().call(r))); + #[project] + match this.state.as_mut().project() { + ThenServiceResponseState::A(fut, b) => match fut.poll(cx) { + Poll::Ready(res) => { + let fut = b.get_mut().call(res); + this.state.set(ThenServiceResponseState::B(fut)); + self.poll(cx) } - - Poll::Pending => return Poll::Pending, - } + Poll::Pending => Poll::Pending, + }, + ThenServiceResponseState::B(fut) => fut.poll(cx), } } } @@ -185,23 +173,23 @@ where } } -pin_project! { - pub struct ThenServiceFactoryResponse - where - A: ServiceFactory, - B: ServiceFactory< - Config = A::Config, - Request = Result, - Error = A::Error, - InitError = A::InitError> - { - #[pin] - fut_b: B::Future, - #[pin] - fut_a: A::Future, - a: Option, - b: Option, - } +#[pin_project::pin_project] +pub struct ThenServiceFactoryResponse +where + A: ServiceFactory, + B: ServiceFactory< + Config = A::Config, + Request = Result, + Error = A::Error, + InitError = A::InitError, + >, +{ + #[pin] + fut_b: B::Future, + #[pin] + fut_a: A::Future, + a: Option, + b: Option, } impl ThenServiceFactoryResponse @@ -266,7 +254,7 @@ mod tests { use std::rc::Rc; use std::task::{Context, Poll}; - use futures::future::{err, lazy, ok, ready, Ready}; + use futures_util::future::{err, lazy, ok, ready, Ready}; use crate::{pipeline, pipeline_factory, Service, ServiceFactory}; diff --git a/actix-service/src/transform.rs b/actix-service/src/transform.rs index 08d325d1..5f6730f5 100644 --- a/actix-service/src/transform.rs +++ b/actix-service/src/transform.rs @@ -94,10 +94,7 @@ where } /// `Apply` transform to new service -pub struct ApplyTransform { - s: Rc, - t: Rc, -} +pub struct ApplyTransform(Rc<(T, S)>); impl ApplyTransform where @@ -106,19 +103,13 @@ where { /// Create new `ApplyTransform` new service instance fn new(t: T, service: S) -> Self { - Self { - s: Rc::new(service), - t: Rc::new(t), - } + Self(Rc::new((t, service))) } } impl Clone for ApplyTransform { fn clone(&self) -> Self { - ApplyTransform { - s: self.s.clone(), - t: self.t.clone(), - } + ApplyTransform(self.0.clone()) } } @@ -138,25 +129,31 @@ where fn new_service(&self, cfg: S::Config) -> Self::Future { ApplyTransformFuture { - t_cell: self.t.clone(), - fut_a: self.s.new_service(cfg), - fut_t: None, + store: self.0.clone(), + state: ApplyTransformFutureState::A(self.0.as_ref().1.new_service(cfg)), } } } -pin_project! { - pub struct ApplyTransformFuture - where - S: ServiceFactory, - T: Transform, - { - #[pin] - fut_a: S::Future, - #[pin] - fut_t: Option, - t_cell: Rc, - } +#[pin_project::pin_project] +pub struct ApplyTransformFuture +where + S: ServiceFactory, + T: Transform, +{ + store: Rc<(T, S)>, + #[pin] + state: ApplyTransformFutureState, +} + +#[pin_project::pin_project] +pub enum ApplyTransformFutureState +where + S: ServiceFactory, + T: Transform, +{ + A(#[pin] S::Future), + B(#[pin] T::Future), } impl Future for ApplyTransformFuture @@ -166,20 +163,21 @@ where { type Output = Result; + #[pin_project::project] fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let mut this = self.as_mut().project(); - if let Some(fut) = this.fut_t.as_pin_mut() { - return fut.poll(cx); - } - - if let Poll::Ready(service) = this.fut_a.poll(cx)? { - let fut = this.t_cell.new_transform(service); - this = self.as_mut().project(); - this.fut_t.set(Some(fut)); - this.fut_t.as_pin_mut().unwrap().poll(cx) - } else { - Poll::Pending + #[project] + match this.state.as_mut().project() { + ApplyTransformFutureState::A(fut) => match fut.poll(cx)? { + Poll::Ready(srv) => { + let fut = this.store.0.new_transform(srv); + this.state.set(ApplyTransformFutureState::B(fut)); + self.poll(cx) + } + Poll::Pending => Poll::Pending, + }, + ApplyTransformFutureState::B(fut) => fut.poll(cx), } } } diff --git a/actix-service/src/transform_err.rs b/actix-service/src/transform_err.rs index c3a71ab6..9d306f0c 100644 --- a/actix-service/src/transform_err.rs +++ b/actix-service/src/transform_err.rs @@ -64,16 +64,15 @@ where } } -pin_project! { - pub struct TransformMapInitErrFuture - where - T: Transform, - F: Fn(T::InitError) -> E, - { - #[pin] - fut: T::Future, - f: F, - } +#[pin_project::pin_project] +pub struct TransformMapInitErrFuture +where + T: Transform, + F: Fn(T::InitError) -> E, +{ + #[pin] + fut: T::Future, + f: F, } impl Future for TransformMapInitErrFuture diff --git a/actix-testing/Cargo.toml b/actix-testing/Cargo.toml index e597b933..58e48014 100644 --- a/actix-testing/Cargo.toml +++ b/actix-testing/Cargo.toml @@ -20,7 +20,7 @@ path = "src/lib.rs" actix-rt = "1.0.0-alpha.2" actix-macros = "0.1.0-alpha.1" actix-server = "1.0.0-alpha.2" -actix-service = "1.0.0-alpha.2" +actix-service = "1.0.0-alpha.3" log = "0.4" net2 = "0.2" diff --git a/actix-tls/Cargo.toml b/actix-tls/Cargo.toml index b4243648..d70d16cf 100644 --- a/actix-tls/Cargo.toml +++ b/actix-tls/Cargo.toml @@ -29,7 +29,7 @@ openssl = ["open-ssl", "tokio-openssl"] rustls = ["rust-tls", "webpki"] [dependencies] -actix-service = "1.0.0-alpha.2" +actix-service = "1.0.0-alpha.3" actix-codec = "0.2.0-alpha.2" actix-utils = "1.0.0-alpha.2" actix-rt = "1.0.0-alpha.2" diff --git a/actix-utils/CHANGES.md b/actix-utils/CHANGES.md index c33c381b..91a197f9 100644 --- a/actix-utils/CHANGES.md +++ b/actix-utils/CHANGES.md @@ -1,5 +1,7 @@ # Changes +## [1.0.0-alpha.3] - 2019-12-xx + * Fix oneshot ## [1.0.0-alpha.2] - 2019-12-02 diff --git a/actix-utils/Cargo.toml b/actix-utils/Cargo.toml index 7740a83b..08e48df7 100644 --- a/actix-utils/Cargo.toml +++ b/actix-utils/Cargo.toml @@ -18,7 +18,7 @@ name = "actix_utils" path = "src/lib.rs" [dependencies] -actix-service = "1.0.0-alpha.2" +actix-service = "1.0.0-alpha.3" actix-rt = "1.0.0-alpha.2" actix-codec = "0.2.0-alpha.2" bytes = "0.4"