1
0
mirror of https://github.com/fafhrd91/actix-net synced 2024-11-24 01:11:07 +01:00

optimize service combinators memory layout

This commit is contained in:
Nikolay Kim 2019-12-05 12:37:26 +06:00
parent c6eb318536
commit 6f41b80cb4
24 changed files with 366 additions and 399 deletions

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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

View File

@ -1,6 +1,6 @@
[package]
name = "actix-service"
version = "1.0.0-alpha.2"
version = "1.0.0-alpha.3"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
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"

View File

@ -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, B> {
a: A,
b: Cell<B>,
}
pub struct AndThenService<A, B>(Cell<(A, B)>);
impl<A, B> AndThenService<A, B> {
/// Create new `AndThen` combinator
@ -21,19 +18,13 @@ impl<A, B> AndThenService<A, B> {
A: Service,
B: Service<Request = A::Response, Error = A::Error>,
{
Self { a, b: Cell::new(b) }
Self(Cell::new((a, b)))
}
}
impl<A, B> Clone for AndThenService<A, B>
where
A: Clone,
{
impl<A, B> Clone for AndThenService<A, B> {
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<A, B>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
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! {
#[pin_project::pin_project]
pub struct AndThenServiceResponse<A, B>
where
A: Service,
B: Service<Request = A::Response, Error = A::Error>,
{
b: Cell<B>,
#[pin]
fut_b: Option<B::Future>,
#[pin]
fut_a: Option<A::Future>,
}
state: State<A, B>,
}
impl<A, B> AndThenServiceResponse<A, B>
#[pin_project::pin_project]
enum State<A, B>
where
A: Service,
B: Service<Request = A::Response, Error = A::Error>,
{
fn new(a: A::Future, b: Cell<B>) -> Self {
AndThenServiceResponse {
b,
fut_a: Some(a),
fut_b: None,
}
}
A(#[pin] A::Future, Cell<(A, B)>),
B(#[pin] B::Future),
}
impl<A, B> Future for AndThenServiceResponse<A, B>
@ -96,28 +83,21 @@ where
{
type Output = Result<B::Response, A::Error>;
#[pin_project::project]
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
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)));
}
Poll::Ready(Err(e)) => return Poll::Ready(Err(e)),
Poll::Pending => return Poll::Pending,
#[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::Pending => Poll::Pending,
},
State::B(fut) => fut.poll(cx),
}
}
}
@ -202,21 +182,20 @@ where
}
}
pin_project! {
#[pin_project::pin_project]
pub struct AndThenServiceFactoryResponse<A, B>
where
A: ServiceFactory,
B: ServiceFactory<Request = A::Response>,
{
#[pin]
fut_b: B::Future,
#[pin]
fut_a: A::Future,
#[pin]
fut_b: B::Future,
a: Option<A::Service>,
b: Option<B::Service>,
}
}
impl<A, B> AndThenServiceFactoryResponse<A, B>
where
@ -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};

View File

@ -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<A::Error> + From<B::Error>,
{
a: A,
b: Cell<B>,
f: Cell<F>,
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<Result<(), Self::Error>> {
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,15 +79,12 @@ 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! {
#[pin_project::pin_project]
pub struct AndThenApplyFnFuture<A, B, F, Fut, Res, Err>
where
A: Service,
@ -102,13 +94,22 @@ pin_project! {
Err: From<A::Error>,
Err: From<B::Error>,
{
b: Cell<B>,
f: Cell<F>,
#[pin]
fut_a: Option<A::Future>,
#[pin]
fut_b: Option<Fut>,
state: State<A, B, F, Fut, Res, Err>,
}
#[pin_project::pin_project]
enum State<A, B, F, Fut, Res, Err>
where
A: Service,
B: Service,
F: FnMut(A::Response, &mut B) -> Fut,
Fut: Future<Output = Result<Res, Err>>,
Err: From<A::Error>,
Err: From<B::Error>,
{
A(#[pin] A::Future, Cell<(B, F)>),
B(#[pin] Fut),
}
impl<A, B, F, Fut, Res, Err> Future for AndThenApplyFnFuture<A, B, F, Fut, Res, Err>
@ -121,28 +122,22 @@ where
{
type Output = Result<Res, Err>;
#[pin_project::project]
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
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);
#[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,
Poll::Ready(Err(err)) => Poll::Ready(Err(err.into())),
},
State::B(fut) => fut.poll(cx),
}
}
}
@ -151,7 +146,7 @@ where
pub struct AndThenApplyFnFactory<A, B, F, Fut, Res, Err> {
a: A,
b: B,
f: Cell<F>,
f: F,
r: PhantomData<(Fut, Res, Err)>,
}
@ -159,7 +154,7 @@ impl<A, B, F, Fut, Res, Err> AndThenApplyFnFactory<A, B, F, Fut, Res, Err>
where
A: ServiceFactory,
B: ServiceFactory<Config = A::Config, InitError = A::InitError>,
F: FnMut(A::Response, &mut B::Service) -> Fut,
F: FnMut(A::Response, &mut B::Service) -> Fut + Clone,
Fut: Future<Output = Result<Res, Err>>,
Err: From<A::Error> + From<B::Error>,
{
@ -168,7 +163,7 @@ where
Self {
a: a,
b: b,
f: Cell::new(f),
f: f,
r: PhantomData,
}
}
@ -178,6 +173,7 @@ impl<A, B, F, Fut, Res, Err> Clone for AndThenApplyFnFactory<A, B, F, Fut, Res,
where
A: Clone,
B: Clone,
F: Clone,
{
fn clone(&self) -> Self {
Self {
@ -194,7 +190,7 @@ where
A: ServiceFactory,
A::Config: Clone,
B: ServiceFactory<Config = A::Config, InitError = A::InitError>,
F: FnMut(A::Response, &mut B::Service) -> Fut,
F: FnMut(A::Response, &mut B::Service) -> Fut + Clone,
Fut: Future<Output = Result<Res, Err>>,
Err: From<A::Error> + From<B::Error>,
{
@ -217,12 +213,12 @@ where
}
}
pin_project! {
#[pin_project::pin_project]
pub struct AndThenApplyFnFactoryResponse<A, B, F, Fut, Res, Err>
where
A: ServiceFactory,
B: ServiceFactory<Config = A::Config, InitError = A::InitError>,
F: FnMut(A::Response, &mut B::Service) -> Fut,
F: FnMut(A::Response, &mut B::Service) -> Fut + Clone,
Fut: Future<Output = Result<Res, Err>>,
Err: From<A::Error>,
Err: From<B::Error>,
@ -231,17 +227,16 @@ pin_project! {
fut_b: B::Future,
#[pin]
fut_a: A::Future,
f: Cell<F>,
f: F,
a: Option<A::Service>,
b: Option<B::Service>,
}
}
impl<A, B, F, Fut, Res, Err> Future for AndThenApplyFnFactoryResponse<A, B, F, Fut, Res, Err>
where
A: ServiceFactory,
B: ServiceFactory<Config = A::Config, InitError = A::InitError>,
F: FnMut(A::Response, &mut B::Service) -> Fut,
F: FnMut(A::Response, &mut B::Service) -> Fut + Clone,
Fut: Future<Output = Result<Res, Err>>,
Err: From<A::Error> + From<B::Error>,
{
@ -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};

View File

@ -67,8 +67,8 @@ where
type Error = Err;
type Future = R;
fn poll_ready(&mut self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(futures::ready!(self.service.poll_ready(ctx)))
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(futures_util::ready!(self.service.poll_ready(cx)))
}
fn call(&mut self, req: In) -> Self::Future {
@ -139,7 +139,7 @@ where
}
}
pin_project! {
#[pin_project::pin_project]
pub struct ApplyServiceFactoryResponse<T, F, R, In, Out, Err>
where
T: ServiceFactory<Error = Err>,
@ -151,12 +151,11 @@ pin_project! {
f: Option<F>,
r: PhantomData<(In, Out)>,
}
}
impl<T, F, R, In, Out, Err> ApplyServiceFactoryResponse<T, F, R, In, Out, Err>
where
T: ServiceFactory<Error = Err>,
F: FnMut(In, &mut T::Service) -> R + Clone,
F: FnMut(In, &mut T::Service) -> R,
R: Future<Output = Result<Out, Err>>,
{
fn new(fut: T::Future, f: F) -> Self {
@ -171,7 +170,7 @@ where
impl<T, F, R, In, Out, Err> Future for ApplyServiceFactoryResponse<T, F, R, In, Out, Err>
where
T: ServiceFactory<Error = Err>,
F: FnMut(In, &mut T::Service) -> R + Clone,
F: FnMut(In, &mut T::Service) -> R,
R: Future<Output = Result<Out, Err>>,
{
type Output = Result<Apply<T::Service, F, R, In, Out, Err>, 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};

View File

@ -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<Output = Result<S, E>>,
S: Service,
{
f: Cell<F>,
srv: Cell<T>,
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<Output = Result<S, T::InitError>>,
S: Service,
{
f: Cell<F>,
srv: Cell<T>,
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,17 +136,14 @@ 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! {
#[pin_project::pin_project]
pub struct ApplyConfigServiceFactoryResponse<F, C, T, R, S>
where
F: FnMut(C, &mut T::Service) -> R,
@ -159,14 +153,22 @@ pin_project! {
S: Service,
{
cfg: Option<C>,
f: Cell<F>,
srv: Option<T::Service>,
store: Cell<(T, F)>,
#[pin]
srv_fut: Option<T::Future>,
#[pin]
fut: Option<R>,
_t: PhantomData<(S,)>,
state: State<T, R, S>,
}
#[pin_project::pin_project]
enum State<T, R, S>
where
T: ServiceFactory<Config = ()>,
T::InitError: From<T::Error>,
R: Future<Output = Result<S, T::InitError>>,
S: Service,
{
A(#[pin] T::Future),
B(T::Service),
C(#[pin] R),
}
impl<F, C, T, R, S> Future for ApplyConfigServiceFactoryResponse<F, C, T, R, S>
@ -179,37 +181,28 @@ where
{
type Output = Result<S, T::InitError>;
#[pin_project::project]
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
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,
#[project]
match this.state.as_mut().project() {
State::A(fut) => match fut.poll(cx)? {
Poll::Pending => Poll::Pending,
Poll::Ready(srv) => {
this = self.as_mut().project();
this.srv_fut.set(None);
*this.srv = Some(srv);
continue;
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)? {
},
State::B(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,
}
} else {
return Poll::Pending;
let fut = (this.store.get_mut().1)(this.cfg.take().unwrap(), srv);
this.state.set(State::C(fut));
self.poll(cx)
}
Poll::Pending => Poll::Pending,
},
State::C(fut) => fut.poll(cx),
}
}
}

View File

@ -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};

View File

@ -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<T> {
@ -39,3 +40,18 @@ impl<T> Cell<T> {
&mut *self.inner.as_ref().get()
}
}
impl<T: crate::Service> crate::Service for Cell<T> {
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<Result<(), Self::Error>> {
self.get_mut().poll_ready(cx)
}
fn call(&mut self, req: Self::Request) -> Self::Future {
self.get_mut().call(req)
}
}

View File

@ -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};

View File

@ -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;

View File

@ -62,7 +62,7 @@ where
}
}
pin_project! {
#[pin_project::pin_project]
pub struct MapFuture<A, F, Response>
where
A: Service,
@ -72,7 +72,6 @@ pin_project! {
#[pin]
fut: A::Future,
}
}
impl<A, F, Response> MapFuture<A, F, Response>
where
@ -157,7 +156,7 @@ where
}
}
pin_project! {
#[pin_project::pin_project]
pub struct MapServiceFuture<A, F, Res>
where
A: ServiceFactory,
@ -167,7 +166,6 @@ pin_project! {
fut: A::Future,
f: Option<F>,
}
}
impl<A, F, Res> MapServiceFuture<A, F, Res>
where
@ -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};

View File

@ -63,7 +63,7 @@ where
}
}
pin_project! {
#[pin_project::pin_project]
pub struct MapErrFuture<A, F, E>
where
A: Service,
@ -73,7 +73,6 @@ pin_project! {
#[pin]
fut: A::Future,
}
}
impl<A, F, E> MapErrFuture<A, F, E>
where
@ -160,7 +159,7 @@ where
}
}
pin_project! {
#[pin_project::pin_project]
pub struct MapErrServiceFuture<A, F, E>
where
A: ServiceFactory,
@ -170,7 +169,6 @@ pin_project! {
fut: A::Future,
f: F,
}
}
impl<A, F, E> MapErrServiceFuture<A, F, E>
where
@ -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};

View File

@ -60,7 +60,7 @@ where
}
}
pin_project! {
#[pin_project::pin_project]
pub struct MapInitErrFuture<A, F, E>
where
A: ServiceFactory,
@ -70,7 +70,6 @@ pin_project! {
#[pin]
fut: A::Future,
}
}
impl<A, F, E> MapInitErrFuture<A, F, E>
where

View File

@ -197,7 +197,7 @@ impl<T: ServiceFactory> PipelineFactory<T> {
T::Config: Clone,
I: IntoServiceFactory<U>,
U: ServiceFactory<Config = T::Config, InitError = T::InitError>,
F: FnMut(T::Response, &mut U::Service) -> Fut,
F: FnMut(T::Response, &mut U::Service) -> Fut + Clone,
Fut: Future<Output = Result<Res, Err>>,
Err: From<T::Error> + From<U::Error>,
{

View File

@ -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! {
#[pin_project::pin_project]
pub struct ThenServiceResponse<A, B>
where
A: Service,
B: Service<Request = Result<A::Response, A::Error>>,
{
b: Cell<B>,
#[pin]
fut_b: Option<B::Future>,
#[pin]
fut_a: Option<A::Future>,
}
state: ThenServiceResponseState<A, B>,
}
impl<A, B> ThenServiceResponse<A, B>
#[pin_project::pin_project]
enum ThenServiceResponseState<A, B>
where
A: Service,
B: Service<Request = Result<A::Response, A::Error>>,
{
fn new(a: A::Future, b: Cell<B>) -> Self {
ThenServiceResponse {
b,
fut_a: Some(a),
fut_b: None,
}
}
A(#[pin] A::Future, Cell<B>),
B(#[pin] B::Future),
}
impl<A, B> Future for ThenServiceResponse<A, B>
@ -96,27 +90,21 @@ where
{
type Output = Result<B::Response, B::Error>;
#[pin_project::project]
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
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)));
}
Poll::Pending => return Poll::Pending,
#[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 => Poll::Pending,
},
ThenServiceResponseState::B(fut) => fut.poll(cx),
}
}
}
@ -185,7 +173,7 @@ where
}
}
pin_project! {
#[pin_project::pin_project]
pub struct ThenServiceFactoryResponse<A, B>
where
A: ServiceFactory,
@ -193,7 +181,8 @@ pin_project! {
Config = A::Config,
Request = Result<A::Response, A::Error>,
Error = A::Error,
InitError = A::InitError>
InitError = A::InitError,
>,
{
#[pin]
fut_b: B::Future,
@ -202,7 +191,6 @@ pin_project! {
a: Option<A::Service>,
b: Option<B::Service>,
}
}
impl<A, B> ThenServiceFactoryResponse<A, B>
where
@ -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};

View File

@ -94,10 +94,7 @@ where
}
/// `Apply` transform to new service
pub struct ApplyTransform<T, S> {
s: Rc<S>,
t: Rc<T>,
}
pub struct ApplyTransform<T, S>(Rc<(T, S)>);
impl<T, S> ApplyTransform<T, S>
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<T, S> Clone for ApplyTransform<T, S> {
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! {
#[pin_project::pin_project]
pub struct ApplyTransformFuture<T, S>
where
S: ServiceFactory,
T: Transform<S::Service, InitError = S::InitError>,
{
store: Rc<(T, S)>,
#[pin]
fut_a: S::Future,
#[pin]
fut_t: Option<T::Future>,
t_cell: Rc<T>,
state: ApplyTransformFutureState<T, S>,
}
#[pin_project::pin_project]
pub enum ApplyTransformFutureState<T, S>
where
S: ServiceFactory,
T: Transform<S::Service, InitError = S::InitError>,
{
A(#[pin] S::Future),
B(#[pin] T::Future),
}
impl<T, S> Future for ApplyTransformFuture<T, S>
@ -166,20 +163,21 @@ where
{
type Output = Result<T::Transform, T::InitError>;
#[pin_project::project]
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut this = self.as_mut().project();
if let Some(fut) = this.fut_t.as_pin_mut() {
return fut.poll(cx);
#[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)
}
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
Poll::Pending => Poll::Pending,
},
ApplyTransformFutureState::B(fut) => fut.poll(cx),
}
}
}

View File

@ -64,7 +64,7 @@ where
}
}
pin_project! {
#[pin_project::pin_project]
pub struct TransformMapInitErrFuture<T, S, F, E>
where
T: Transform<S>,
@ -74,7 +74,6 @@ pin_project! {
fut: T::Future,
f: F,
}
}
impl<T, S, F, E> Future for TransformMapInitErrFuture<T, S, F, E>
where

View File

@ -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"

View File

@ -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"

View File

@ -1,5 +1,7 @@
# Changes
## [1.0.0-alpha.3] - 2019-12-xx
* Fix oneshot
## [1.0.0-alpha.2] - 2019-12-02

View File

@ -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"