From f89a992daf4cf753ae3614b243711a200c9748f7 Mon Sep 17 00:00:00 2001 From: Max Gortman <maxim.hortman@gmail.com> Date: Thu, 5 Dec 2019 20:34:44 -0800 Subject: [PATCH] eager drop in then, and_then, and_then_apply_fn (#72) --- actix-service/src/and_then.rs | 13 ++++++++++--- actix-service/src/and_then_apply_fn.rs | 13 ++++++++++--- actix-service/src/then.rs | 21 ++++++++++++++------- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/actix-service/src/and_then.rs b/actix-service/src/and_then.rs index 1c7d52b4..690d0cb4 100644 --- a/actix-service/src/and_then.rs +++ b/actix-service/src/and_then.rs @@ -51,7 +51,7 @@ where fn call(&mut self, req: A::Request) -> Self::Future { AndThenServiceResponse { - state: State::A(self.0.get_mut().0.call(req), self.0.clone()), + state: State::A(self.0.get_mut().0.call(req), Some(self.0.clone())), } } } @@ -72,8 +72,9 @@ where A: Service, B: Service<Request = A::Response, Error = A::Error>, { - A(#[pin] A::Future, Cell<(A, B)>), + A(#[pin] A::Future, Option<Cell<(A, B)>>), B(#[pin] B::Future), + Empty, } impl<A, B> Future for AndThenServiceResponse<A, B> @@ -91,13 +92,19 @@ where match this.state.as_mut().project() { State::A(fut, b) => match fut.poll(cx)? { Poll::Ready(res) => { + let mut b = b.take().unwrap(); + this.state.set(State::Empty); // drop fut A let fut = b.get_mut().1.call(res); this.state.set(State::B(fut)); self.poll(cx) } Poll::Pending => Poll::Pending, }, - State::B(fut) => fut.poll(cx), + State::B(fut) => fut.poll(cx).map(|r| { + this.state.set(State::Empty); + r + }), + State::Empty => panic!("future must not be polled after it returned `Poll::Ready`"), } } } diff --git a/actix-service/src/and_then_apply_fn.rs b/actix-service/src/and_then_apply_fn.rs index 3ae7e59f..2ac7474d 100644 --- a/actix-service/src/and_then_apply_fn.rs +++ b/actix-service/src/and_then_apply_fn.rs @@ -79,7 +79,7 @@ where fn call(&mut self, req: A::Request) -> Self::Future { AndThenApplyFnFuture { - state: State::A(self.a.call(req), self.b.clone()), + state: State::A(self.a.call(req), Some(self.b.clone())), } } } @@ -108,8 +108,9 @@ where Err: From<A::Error>, Err: From<B::Error>, { - A(#[pin] A::Future, Cell<(B, F)>), + A(#[pin] A::Future, Option<Cell<(B, F)>>), B(#[pin] Fut), + Empty, } impl<A, B, F, Fut, Res, Err> Future for AndThenApplyFnFuture<A, B, F, Fut, Res, Err> @@ -130,6 +131,8 @@ where match this.state.as_mut().project() { State::A(fut, b) => match fut.poll(cx)? { Poll::Ready(res) => { + let mut b = b.take().unwrap(); + this.state.set(State::Empty); let b = b.get_mut(); let fut = (&mut b.1)(res, &mut b.0); this.state.set(State::B(fut)); @@ -137,7 +140,11 @@ where } Poll::Pending => Poll::Pending, }, - State::B(fut) => fut.poll(cx), + State::B(fut) => fut.poll(cx).map(|r| { + this.state.set(State::Empty); + r + }), + State::Empty => panic!("future must not be polled after it returned `Poll::Ready`"), } } } diff --git a/actix-service/src/then.rs b/actix-service/src/then.rs index 9741ddfa..eaf2da5e 100644 --- a/actix-service/src/then.rs +++ b/actix-service/src/then.rs @@ -58,7 +58,7 @@ where fn call(&mut self, req: A::Request) -> Self::Future { ThenServiceResponse { - state: ThenServiceResponseState::A(self.a.call(req), self.b.clone()), + state: State::A(self.a.call(req), Some(self.b.clone())), } } } @@ -70,17 +70,18 @@ where B: Service<Request = Result<A::Response, A::Error>>, { #[pin] - state: ThenServiceResponseState<A, B>, + state: State<A, B>, } #[pin_project::pin_project] -enum ThenServiceResponseState<A, B> +enum State<A, B> where A: Service, B: Service<Request = Result<A::Response, A::Error>>, { - A(#[pin] A::Future, Cell<B>), + A(#[pin] A::Future, Option<Cell<B>>), B(#[pin] B::Future), + Empty } impl<A, B> Future for ThenServiceResponse<A, B> @@ -96,15 +97,21 @@ where #[project] match this.state.as_mut().project() { - ThenServiceResponseState::A(fut, b) => match fut.poll(cx) { + State::A(fut, b) => match fut.poll(cx) { Poll::Ready(res) => { + let mut b = b.take().unwrap(); + this.state.set(State::Empty); // drop fut A let fut = b.get_mut().call(res); - this.state.set(ThenServiceResponseState::B(fut)); + this.state.set(State::B(fut)); self.poll(cx) } Poll::Pending => Poll::Pending, }, - ThenServiceResponseState::B(fut) => fut.poll(cx), + State::B(fut) => fut.poll(cx).map(|r| { + this.state.set(State::Empty); + r + }), + State::Empty => panic!("future must not be polled after it returned `Poll::Ready`") } } }