Merge branch 'std-future' into std-future-rt

This commit is contained in:
Nikolay Kim 2019-11-10 23:51:07 +06:00 committed by GitHub
commit 67ca79af4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
57 changed files with 1167 additions and 695 deletions

2
.gitignore vendored
View File

@ -12,3 +12,5 @@ guide/build/
# These are backup files generated by rustfmt # These are backup files generated by rustfmt
**/*.rs.bk **/*.rs.bk
.idea

View File

@ -10,7 +10,7 @@ matrix:
include: include:
- rust: stable - rust: stable
- rust: beta - rust: beta
- rust: 1.36.0 - rust: 1.37.0
- rust: nightly-2019-06-15 - rust: nightly-2019-06-15
allow_failures: allow_failures:
- rust: nightly-2019-06-15 - rust: nightly-2019-06-15

View File

@ -1,18 +1,3 @@
[package]
name = "actix-net"
version = "0.3.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix net - framework for the composable network services for Rust"
readme = "README.md"
keywords = ["network", "framework", "async", "futures"]
homepage = "https://actix.rs"
repository = "https://github.com/actix/actix-net.git"
documentation = "https://docs.rs/actix-net/"
categories = ["network-programming", "asynchronous"]
license = "MIT/Apache-2.0"
exclude = [".gitignore", ".travis.yml", ".cargo/config", "appveyor.yml"]
edition = "2018"
[workspace] [workspace]
members = [ members = [
"actix-codec", "actix-codec",
@ -28,17 +13,6 @@ members = [
"router", "router",
] ]
[dev-dependencies]
actix-service = "0.4.0"
actix-codec = "0.1.1"
actix-rt = "0.2.0"
actix-server = { version="0.5.0", features=["ssl"] }
env_logger = "0.6"
futures = "0.1.25"
openssl = "0.10"
tokio-tcp = "0.1"
tokio-openssl = "0.3"
[patch.crates-io] [patch.crates-io]
actix-codec = { path = "actix-codec" } actix-codec = { path = "actix-codec" }
actix-connect = { path = "actix-connect" } actix-connect = { path = "actix-connect" }

View File

@ -7,7 +7,7 @@ Actix net - framework for composable network services
* [API Documentation (Development)](https://actix.rs/actix-net/actix_net/) * [API Documentation (Development)](https://actix.rs/actix-net/actix_net/)
* [Chat on gitter](https://gitter.im/actix/actix) * [Chat on gitter](https://gitter.im/actix/actix)
* Cargo package: [actix-net](https://crates.io/crates/actix-net) * Cargo package: [actix-net](https://crates.io/crates/actix-net)
* Minimum supported Rust version: 1.36 or later * Minimum supported Rust version: 1.37 or later
## Example ## Example

View File

@ -19,7 +19,8 @@ path = "src/lib.rs"
[dependencies] [dependencies]
bytes = "0.4.12" bytes = "0.4.12"
futures = "0.1.24" pin-utils = "0.1.0-alpha.4"
tokio-io = "0.1.12" futures = "0.3.1"
tokio-codec = "0.1.1" tokio-io = "0.2.0-alpha.5"
tokio-codec = "0.2.0-alpha.5"
log = "0.4" log = "0.4"

View File

@ -4,12 +4,14 @@ use std::fmt;
use std::io::{self, Read, Write}; use std::io::{self, Read, Write};
use bytes::BytesMut; use bytes::BytesMut;
use futures::{Poll, Sink, StartSend, Stream}; use futures::{Poll, Sink, Stream};
use tokio_codec::{Decoder, Encoder}; use tokio_codec::{Decoder, Encoder};
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
use super::framed_read::{framed_read2, framed_read2_with_buffer, FramedRead2}; use super::framed_read::{framed_read2, framed_read2_with_buffer, FramedRead2};
use super::framed_write::{framed_write2, framed_write2_with_buffer, FramedWrite2}; use super::framed_write::{framed_write2, framed_write2_with_buffer, FramedWrite2};
use std::pin::Pin;
use std::task::Context;
const LW: usize = 1024; const LW: usize = 1024;
const HW: usize = 8 * 1024; const HW: usize = 8 * 1024;
@ -221,41 +223,43 @@ impl<T, U> Framed<T, U> {
} }
} }
impl<T, U> Stream for Framed<T, U> impl<T, U> Stream for Framed<T, U>
where where
T: AsyncRead, T: AsyncRead,
U: Decoder, U: Decoder,
{ {
type Item = U::Item; type Item = Result<U::Item,U::Error>;
type Error = U::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> { fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.inner.poll() unsafe { self.map_unchecked_mut(|s| &mut s.inner).poll_next(cx )}
} }
} }
impl<T, U> Sink for Framed<T, U> impl<T, U> Sink<U::Item> for Framed<T, U>
where where
T: AsyncWrite, T: AsyncWrite,
U: Encoder, U: Encoder,
U::Error: From<io::Error>, U::Error: From<io::Error>,
{ {
type SinkItem = U::Item; type Error = U::Error;
type SinkError = U::Error;
fn start_send( fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
&mut self, unsafe { self.map_unchecked_mut(|s| s.inner.get_mut()).poll_ready(cx)}
item: Self::SinkItem,
) -> StartSend<Self::SinkItem, Self::SinkError> {
self.inner.get_mut().start_send(item)
} }
fn poll_complete(&mut self) -> Poll<(), Self::SinkError> { fn start_send(self: Pin<&mut Self>, item: <U as Encoder>::Item) -> Result<(), Self::Error> {
self.inner.get_mut().poll_complete() unsafe { self.map_unchecked_mut(|s| s.inner.get_mut()).start_send(item)}
} }
fn close(&mut self) -> Poll<(), Self::SinkError> { fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.inner.get_mut().close() unsafe { self.map_unchecked_mut(|s| s.inner.get_mut()).poll_flush(cx)}
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
unsafe { self.map_unchecked_mut(|s| s.inner.get_mut()).poll_close(cx)}
} }
} }
@ -280,10 +284,16 @@ impl<T: Read, U> Read for Fuse<T, U> {
} }
} }
impl<T: AsyncRead, U> AsyncRead for Fuse<T, U> { impl<T: AsyncRead, U> AsyncRead for Fuse<T, U> {
unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
self.0.prepare_uninitialized_buffer(buf) self.0.prepare_uninitialized_buffer(buf)
} }
fn poll_read(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> {
unsafe { self.map_unchecked_mut(|s| &mut s.0).poll_read(cx, buf)}
}
} }
impl<T: Write, U> Write for Fuse<T, U> { impl<T: Write, U> Write for Fuse<T, U> {
@ -296,12 +306,23 @@ impl<T: Write, U> Write for Fuse<T, U> {
} }
} }
impl<T: AsyncWrite, U> AsyncWrite for Fuse<T, U> { impl<T: AsyncWrite, U> AsyncWrite for Fuse<T, U> {
fn shutdown(&mut self) -> Poll<(), io::Error> {
self.0.shutdown() fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
unsafe { self.map_unchecked_mut(|s| &mut s.0).poll_write(cx, buf)}
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
unsafe { self.map_unchecked_mut(|s| &mut s.0).poll_flush(cx)}
}
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
unsafe { self.map_unchecked_mut(|s| &mut s.0).poll_shutdown(cx)}
} }
} }
impl<T, U: Decoder> Decoder for Fuse<T, U> { impl<T, U: Decoder> Decoder for Fuse<T, U> {
type Item = U::Item; type Item = U::Item;
type Error = U::Error; type Error = U::Error;

View File

@ -1,12 +1,14 @@
use std::fmt; use std::fmt;
use bytes::BytesMut; use bytes::BytesMut;
use futures::{try_ready, Async, Poll, Sink, StartSend, Stream}; use futures::{Poll, Sink, Stream};
use log::trace; use log::trace;
use tokio_codec::Decoder; use tokio_codec::Decoder;
use tokio_io::AsyncRead; use tokio_io::AsyncRead;
use super::framed::Fuse; use super::framed::Fuse;
use std::pin::Pin;
use std::task::Context;
/// A `Stream` of messages decoded from an `AsyncRead`. /// A `Stream` of messages decoded from an `AsyncRead`.
pub struct FramedRead<T, D> { pub struct FramedRead<T, D> {
@ -83,35 +85,35 @@ where
T: AsyncRead, T: AsyncRead,
D: Decoder, D: Decoder,
{ {
type Item = D::Item; type Item = Result<D::Item,D::Error>;
type Error = D::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> { fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.inner.poll() unsafe { self.map_unchecked_mut(|s| &mut s.inner).poll_next(cx )}
} }
} }
impl<T, D> Sink for FramedRead<T, D> impl<I, T, D> Sink<I> for FramedRead<T, D>
where where
T: Sink, T: Sink<I>,
{ {
type SinkItem = T::SinkItem; type Error = T::Error;
type SinkError = T::SinkError;
fn start_send( fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
&mut self, unsafe { self.map_unchecked_mut(|s| &mut s.inner.inner.0).poll_ready(cx)}
item: Self::SinkItem,
) -> StartSend<Self::SinkItem, Self::SinkError> {
self.inner.inner.0.start_send(item)
} }
fn poll_complete(&mut self) -> Poll<(), Self::SinkError> { fn start_send(self: Pin<&mut Self>, item: I) -> Result<(), Self::Error> {
self.inner.inner.0.poll_complete() unsafe { self.map_unchecked_mut(|s| &mut s.inner.inner.0).start_send(item)}
} }
fn close(&mut self) -> Poll<(), Self::SinkError> { fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.inner.inner.0.close() unsafe { self.map_unchecked_mut(|s| &mut s.inner.inner.0).poll_flush(cx)}
} }
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
unsafe { self.map_unchecked_mut(|s| &mut s.inner.inner.0).poll_close(cx)}
}
} }
impl<T, D> fmt::Debug for FramedRead<T, D> impl<T, D> fmt::Debug for FramedRead<T, D>
@ -174,45 +176,66 @@ impl<T> FramedRead2<T> {
impl<T> Stream for FramedRead2<T> impl<T> Stream for FramedRead2<T>
where where
T: AsyncRead + Decoder, T: tokio_io::AsyncRead + Decoder,
{ {
type Item = T::Item; type Item = Result<T::Item,T::Error>;
type Error = T::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> { fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let mut this = unsafe { self.get_unchecked_mut() };
loop { loop {
// Repeatedly call `decode` or `decode_eof` as long as it is // Repeatedly call `decode` or `decode_eof` as long as it is
// "readable". Readable is defined as not having returned `None`. If // "readable". Readable is defined as not having returned `None`. If
// the upstream has returned EOF, and the decoder is no longer // the upstream has returned EOF, and the decoder is no longer
// readable, it can be assumed that the decoder will never become // readable, it can be assumed that the decoder will never become
// readable again, at which point the stream is terminated. // readable again, at which point the stream is terminated.
if self.is_readable {
if self.eof { if this.is_readable {
let frame = self.inner.decode_eof(&mut self.buffer)?; if this.eof {
return Ok(Async::Ready(frame)); match this.inner.decode_eof(&mut this.buffer) {
Ok(Some(frame)) => return Poll::Ready(Some(Ok(frame))),
Ok(None) => return Poll::Ready(None),
Err(e) => return Poll::Ready(Some(Err(e))),
}
} }
trace!("attempting to decode a frame"); trace!("attempting to decode a frame");
if let Some(frame) = self.inner.decode(&mut self.buffer)? { match this.inner.decode(&mut this.buffer) {
trace!("frame decoded from buffer"); Ok(Some(frame)) => {
return Ok(Async::Ready(Some(frame))); trace!("frame decoded from buffer");
return Poll::Ready(Some(Ok(frame)));
}
Err(e) => {
return Poll::Ready(Some(Err(e)))
}
_ => {
// Need more data
}
} }
self.is_readable = false;
this.is_readable = false;
} }
assert!(!self.eof); assert!(!this.eof);
// Otherwise, try to read more data and try again. Make sure we've // Otherwise, try to read more data and try again. Make sure we've
// got room for at least one byte to read to ensure that we don't // got room for at least one byte to read to ensure that we don't
// get a spurious 0 that looks like EOF // get a spurious 0 that looks like EOF
self.buffer.reserve(1); this.buffer.reserve(1);
if 0 == try_ready!(self.inner.read_buf(&mut self.buffer)) { unsafe {
self.eof = true;
}
self.is_readable = true; match Pin::new_unchecked(&mut this.inner).poll_read(cx, &mut this.buffer) {
Poll::Pending => return Poll::Pending,
Poll::Ready(Err(e)) => return Poll::Ready(Some(Err(e.into()))),
Poll::Ready(Ok(0)) => {
this.eof = true;
}
Poll::Ready(Ok(_cnt)) => {}
}
}
this.is_readable = true;
} }
} }
} }

View File

@ -2,12 +2,14 @@ use std::fmt;
use std::io::{self, Read}; use std::io::{self, Read};
use bytes::BytesMut; use bytes::BytesMut;
use futures::{try_ready, Async, AsyncSink, Poll, Sink, StartSend, Stream}; use futures::{ready,Poll, Sink, Stream};
use log::trace; use log::trace;
use tokio_codec::{Decoder, Encoder}; use tokio_codec::{Decoder, Encoder};
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
use super::framed::Fuse; use super::framed::Fuse;
use std::task::Context;
use std::pin::Pin;
/// A `Sink` of frames encoded to an `AsyncWrite`. /// A `Sink` of frames encoded to an `AsyncWrite`.
pub struct FramedWrite<T, E> { pub struct FramedWrite<T, E> {
@ -95,24 +97,27 @@ where
} }
} }
impl<T, E> Sink for FramedWrite<T, E> impl<T, E> Sink<E::Item> for FramedWrite<T, E>
where where
T: AsyncWrite, T: AsyncWrite,
E: Encoder, E: Encoder,
{ {
type SinkItem = E::Item; type Error = E::Error;
type SinkError = E::Error;
fn start_send(&mut self, item: E::Item) -> StartSend<E::Item, E::Error> { fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.inner.start_send(item) unsafe { self.map_unchecked_mut(|s| &mut s.inner).poll_ready(cx)}
} }
fn poll_complete(&mut self) -> Poll<(), Self::SinkError> { fn start_send(self: Pin<&mut Self>, item: <E as Encoder>::Item) -> Result<(), Self::Error> {
self.inner.poll_complete() unsafe { self.map_unchecked_mut(|s| &mut s.inner).start_send(item)}
} }
fn close(&mut self) -> Poll<(), Self::SinkError> { fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Ok(self.inner.close()?) unsafe { self.map_unchecked_mut(|s| &mut s.inner).poll_flush(cx)}
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
unsafe { self.map_unchecked_mut(|s| &mut s.inner).poll_close(cx)}
} }
} }
@ -121,10 +126,9 @@ where
T: Stream, T: Stream,
{ {
type Item = T::Item; type Item = T::Item;
type Error = T::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> { fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.inner.inner.0.poll() unsafe { self.map_unchecked_mut(|s| &mut s.inner.inner.0).poll_next(cx)}
} }
} }
@ -220,13 +224,75 @@ where
} }
} }
impl<T> Sink for FramedWrite2<T> impl<T> Sink<T::Item> for FramedWrite2<T>
where where
T: AsyncWrite + Encoder, T: AsyncWrite + Encoder,
{ {
type SinkItem = T::Item; type Error = T::Error;
type SinkError = T::Error;
fn poll_ready(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
let len = self.buffer.len();
if len >= self.high_watermark {
return Poll::Pending;
} else {
return Poll::Ready(Ok(()));
}
}
fn start_send(self: Pin<&mut Self>, item: <T as Encoder>::Item) -> Result<(), Self::Error> {
let this = unsafe { self.get_unchecked_mut() };
// Check the buffer capacity
let len = this.buffer.len();
if len < this.low_watermark {
this.buffer.reserve(this.high_watermark - len)
}
this.inner.encode(item, &mut this.buffer)?;
Ok(())
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
let this = unsafe { self.get_unchecked_mut() };
trace!("flushing framed transport");
while !this.buffer.is_empty() {
trace!("writing; remaining={}", this.buffer.len());
let n = ready!(unsafe {Pin::new_unchecked(&mut this.inner)}.poll_write(cx, &this.buffer))?;
if n == 0 {
return Poll::Ready(Err(io::Error::new(
io::ErrorKind::WriteZero,
"failed to \
write frame to transport",
)
.into()))
}
// TODO: Add a way to `bytes` to do this w/o returning the drained
// data.
let _ = this.buffer.split_to(n);
}
// Try flushing the underlying IO
ready!(unsafe {Pin::new_unchecked(&mut this.inner)}.poll_flush(cx))?;
trace!("framed transport flushed");
Poll::Ready(Ok(()))
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
let mut this = unsafe { self.get_unchecked_mut() };
ready!(unsafe {Pin::new_unchecked(&mut this).map_unchecked_mut(|s|*s)}.poll_flush(cx))?;
ready!(unsafe {Pin::new_unchecked(&mut this.inner)}.poll_shutdown(cx))?;
Poll::Ready(Ok(()))
}
/*
fn start_send(&mut self, item: T::Item) -> StartSend<T::Item, T::Error> { fn start_send(&mut self, item: T::Item) -> StartSend<T::Item, T::Error> {
// Check the buffer capacity // Check the buffer capacity
let len = self.buffer.len(); let len = self.buffer.len();
@ -275,6 +341,7 @@ where
try_ready!(self.poll_complete()); try_ready!(self.poll_complete());
Ok(self.inner.shutdown()?) Ok(self.inner.shutdown()?)
} }
*/
} }
impl<T: Decoder> Decoder for FramedWrite2<T> { impl<T: Decoder> Decoder for FramedWrite2<T> {
@ -300,4 +367,8 @@ impl<T: AsyncRead> AsyncRead for FramedWrite2<T> {
unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
self.inner.prepare_uninitialized_buffer(buf) self.inner.prepare_uninitialized_buffer(buf)
} }
fn poll_read(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> {
unsafe { self.map_unchecked_mut(|s| &mut s.inner).poll_read(cx, buf)}
}
} }

View File

@ -21,4 +21,5 @@ pub use self::framed_read::FramedRead;
pub use self::framed_write::FramedWrite; pub use self::framed_write::FramedWrite;
pub use tokio_codec::{Decoder, Encoder}; pub use tokio_codec::{Decoder, Encoder};
// TODO: Migrate to futures asyncRead
pub use tokio_io::{AsyncRead, AsyncWrite}; pub use tokio_io::{AsyncRead, AsyncWrite};

View File

@ -1,5 +1,12 @@
# Changes # Changes
## [0.3.0] - 2019-10-03
### Changed
* Update `rustls` to 0.16
* Minimum required Rust version upped to 1.37.0
## [0.2.5] - 2019-09-05 ## [0.2.5] - 2019-09-05
* Add `TcpConnectService` * Add `TcpConnectService`

View File

@ -1,6 +1,6 @@
[package] [package]
name = "actix-connect" name = "actix-connect"
version = "0.2.5" version = "0.3.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"] authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix Connector - tcp connector service" description = "Actix Connector - tcp connector service"
keywords = ["network", "framework", "async", "futures"] keywords = ["network", "framework", "async", "futures"]
@ -51,11 +51,11 @@ openssl = { version="0.10", optional = true }
tokio-openssl = { version="0.3", optional = true } tokio-openssl = { version="0.3", optional = true }
#rustls #rustls
rustls = { version = "0.15.2", optional = true } rustls = { version = "0.16.0", optional = true }
tokio-rustls = { version = "0.9.1", optional = true } tokio-rustls = { version = "0.10.0", optional = true }
webpki = { version = "0.19", optional = true } webpki = { version = "0.21", optional = true }
[dev-dependencies] [dev-dependencies]
bytes = "0.4" bytes = "0.4"
actix-testing = { version="0.1.0" } actix-testing = { version="0.2.0" }
actix-server-config = "0.1.0" actix-server-config = "0.2.0"

View File

@ -5,10 +5,7 @@ use actix_codec::{AsyncRead, AsyncWrite};
use actix_service::{NewService, Service}; use actix_service::{NewService, Service};
use futures::{future::ok, future::FutureResult, Async, Future, Poll}; use futures::{future::ok, future::FutureResult, Async, Future, Poll};
use std::sync::Arc; use std::sync::Arc;
use tokio_rustls::{ use tokio_rustls::{client::TlsStream, rustls::ClientConfig, Connect, TlsConnector};
rustls::{ClientConfig, ClientSession},
Connect, TlsConnector, TlsStream,
};
use webpki::DNSNameRef; use webpki::DNSNameRef;
use crate::{Address, Connection}; use crate::{Address, Connection};
@ -37,7 +34,7 @@ where
connector: Arc<ClientConfig>, connector: Arc<ClientConfig>,
) -> impl Service< ) -> impl Service<
Request = Connection<T, U>, Request = Connection<T, U>,
Response = Connection<T, TlsStream<U, ClientSession>>, Response = Connection<T, TlsStream<U>>,
Error = std::io::Error, Error = std::io::Error,
> { > {
RustlsConnectorService { RustlsConnectorService {
@ -61,7 +58,7 @@ where
U: AsyncRead + AsyncWrite + fmt::Debug, U: AsyncRead + AsyncWrite + fmt::Debug,
{ {
type Request = Connection<T, U>; type Request = Connection<T, U>;
type Response = Connection<T, TlsStream<U, ClientSession>>; type Response = Connection<T, TlsStream<U>>;
type Error = std::io::Error; type Error = std::io::Error;
type Config = (); type Config = ();
type Service = RustlsConnectorService<T, U>; type Service = RustlsConnectorService<T, U>;
@ -86,7 +83,7 @@ where
U: AsyncRead + AsyncWrite + fmt::Debug, U: AsyncRead + AsyncWrite + fmt::Debug,
{ {
type Request = Connection<T, U>; type Request = Connection<T, U>;
type Response = Connection<T, TlsStream<U, ClientSession>>; type Response = Connection<T, TlsStream<U>>;
type Error = std::io::Error; type Error = std::io::Error;
type Future = ConnectAsyncExt<T, U>; type Future = ConnectAsyncExt<T, U>;
@ -97,7 +94,8 @@ where
fn call(&mut self, stream: Connection<T, U>) -> Self::Future { fn call(&mut self, stream: Connection<T, U>) -> Self::Future {
trace!("SSL Handshake start for: {:?}", stream.host()); trace!("SSL Handshake start for: {:?}", stream.host());
let (io, stream) = stream.replace(()); let (io, stream) = stream.replace(());
let host = DNSNameRef::try_from_ascii_str(stream.host()).unwrap(); let host = DNSNameRef::try_from_ascii_str(stream.host())
.expect("rustls currently only handles hostname-based connections. See https://github.com/briansmith/webpki/issues/54");
ConnectAsyncExt { ConnectAsyncExt {
fut: TlsConnector::from(self.connector.clone()).connect(host, io), fut: TlsConnector::from(self.connector.clone()).connect(host, io),
stream: Some(stream), stream: Some(stream),
@ -114,7 +112,7 @@ impl<T: Address, U> Future for ConnectAsyncExt<T, U>
where where
U: AsyncRead + AsyncWrite + fmt::Debug, U: AsyncRead + AsyncWrite + fmt::Debug,
{ {
type Item = Connection<T, TlsStream<U, ClientSession>>; type Item = Connection<T, TlsStream<U>>;
type Error = std::io::Error; type Error = std::io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(&mut self) -> Poll<Self::Item, Self::Error> {

View File

@ -42,6 +42,7 @@ fn test_rustls_string() {
let con = test::call_service(&mut conn, addr.into()); let con = test::call_service(&mut conn, addr.into());
assert_eq!(con.peer_addr().unwrap(), srv.addr()); assert_eq!(con.peer_addr().unwrap(), srv.addr());
} }
#[test] #[test]
fn test_static_str() { fn test_static_str() {
let srv = TestServer::with(|| { let srv = TestServer::with(|| {

View File

@ -1,5 +1,11 @@
# Changes # Changes
## [0.1.1] - 2019-10-14
* Re-register task on every dispatcher poll.
## [0.1.0] - 2019-09-25 ## [0.1.0] - 2019-09-25
* Initial release * Initial release

View File

@ -1,6 +1,6 @@
[package] [package]
name = "actix-ioframe" name = "actix-ioframe"
version = "0.1.0" version = "0.1.1"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"] authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix framed service" description = "Actix framed service"
keywords = ["network", "framework", "async", "futures"] keywords = ["network", "framework", "async", "futures"]
@ -28,8 +28,8 @@ log = "0.4"
[dev-dependencies] [dev-dependencies]
actix-rt = "0.2.2" actix-rt = "0.2.2"
actix-connect = "0.2.0" actix-connect = "0.3.0"
actix-testing = "0.1.0" actix-testing = "0.2.0"
actix-server-config = "0.1.1" actix-server-config = "0.2.0"
tokio-tcp = "0.1" tokio-tcp = "0.1"
tokio-timer = "0.2" tokio-timer = "0.2"

View File

@ -29,6 +29,10 @@ impl<T> Cell<T> {
} }
} }
pub(crate) unsafe fn get_ref(&mut self) -> &T {
&*self.inner.as_ref().get()
}
pub(crate) unsafe fn get_mut(&mut self) -> &mut T { pub(crate) unsafe fn get_mut(&mut self) -> &mut T {
&mut *self.inner.as_ref().get() &mut *self.inner.as_ref().get()
} }

View File

@ -147,13 +147,13 @@ where
} }
Ok(Async::NotReady) => return false, Ok(Async::NotReady) => return false,
Ok(Async::Ready(None)) => { Ok(Async::Ready(None)) => {
log::trace!("Client disconnected");
self.dispatch_state = FramedState::Stopping; self.dispatch_state = FramedState::Stopping;
return true; return true;
} }
}; };
let mut cell = self.inner.clone(); let mut cell = self.inner.clone();
unsafe { cell.get_mut().task.register() };
tokio_current_thread::spawn( tokio_current_thread::spawn(
self.service self.service
.call(Item::new(self.state.clone(), self.sink.clone(), item)) .call(Item::new(self.state.clone(), self.sink.clone(), item))
@ -274,6 +274,8 @@ where
type Error = ServiceError<S::Error, U>; type Error = ServiceError<S::Error, U>;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
unsafe { self.inner.get_ref().task.register() };
match mem::replace(&mut self.dispatch_state, FramedState::Processing) { match mem::replace(&mut self.dispatch_state, FramedState::Processing) {
FramedState::Processing => { FramedState::Processing => {
if self.poll_read() || self.poll_write() { if self.poll_read() || self.poll_write() {

View File

@ -1,5 +1,12 @@
# Changes # Changes
## [0.2.6] - Unreleased
### Fixed
* Fix arbiter's thread panic message.
## [0.2.5] - 2019-09-02 ## [0.2.5] - 2019-09-02
### Added ### Added

View File

@ -18,14 +18,13 @@ name = "actix_rt"
path = "src/lib.rs" path = "src/lib.rs"
[dependencies] [dependencies]
actix-threadpool = "0.1.1" actix-threadpool = "0.2"
futures = { package = "futures-preview", version = "0.3.0-alpha.18" } futures = "0.3.1"
# TODO: Replace this with dependency on tokio-runtime once it is ready # TODO: Replace this with dependency on tokio-runtime once it is ready
tokio = { version = "0.2.0-alpha.4" } tokio = { version = "0.2.0-alpha.5" }
tokio-timer = "=0.3.0-alpha.4" tokio-timer = "=0.3.0-alpha.5"
tokio-executor = "=0.2.0-alpha.4" tokio-executor = "=0.2.0-alpha.5"
tokio-net = "=0.2.0-alpha.4" tokio-net = "=0.2.0-alpha.5"
copyless = "0.1.4" copyless = "0.1.4"

View File

@ -4,11 +4,11 @@ use std::collections::HashMap;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::{fmt, thread}; use std::{fmt, thread};
use std::pin::Pin; use std::pin::Pin;
use std::task::Context; use std::task::{Context, Poll};
use futures::channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender}; use futures::channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender};
use futures::channel::oneshot::{channel, Canceled, Sender}; use futures::channel::oneshot::{channel, Canceled, Sender};
use futures::{future, Future, Poll, FutureExt, Stream}; use futures::{future, Future, FutureExt, Stream};
use tokio::runtime::current_thread::spawn; use tokio::runtime::current_thread::spawn;
use crate::builder::Builder; use crate::builder::Builder;
@ -269,9 +269,11 @@ struct ArbiterController {
impl Drop for ArbiterController { impl Drop for ArbiterController {
fn drop(&mut self) { fn drop(&mut self) {
if thread::panicking() { if thread::panicking() {
eprintln!("Panic in Arbiter thread, shutting down system.");
if System::current().stop_on_panic() { if System::current().stop_on_panic() {
eprintln!("Panic in Arbiter thread, shutting down system.");
System::current().stop_with_code(1) System::current().stop_with_code(1)
} else {
eprintln!("Panic in Arbiter thread.");
} }
} }
} }
@ -282,7 +284,6 @@ impl Future for ArbiterController {
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
loop { loop {
match Pin::new(&mut self.rx).poll_next(cx) { match Pin::new(&mut self.rx).poll_next(cx) {
Poll::Ready(None) => { Poll::Ready(None) => {
return Poll::Ready(()) return Poll::Ready(())

View File

@ -149,7 +149,6 @@ impl Runtime {
// WARN: We do not enter the executor here, since in tokio 0.2 the executor is entered // WARN: We do not enter the executor here, since in tokio 0.2 the executor is entered
// automatically inside its `block_on` and `run` methods // automatically inside its `block_on` and `run` methods
tokio_executor::with_default(&mut current_thread::TaskExecutor::current(),|| { tokio_executor::with_default(&mut current_thread::TaskExecutor::current(),|| {
tokio_timer::clock::with_default(clock, || { tokio_timer::clock::with_default(clock, || {
let _reactor_guard = tokio_net::driver::set_default(reactor_handle); let _reactor_guard = tokio_net::driver::set_default(reactor_handle);

View File

@ -1,6 +1,6 @@
[package] [package]
name = "actix-server-config" name = "actix-server-config"
version = "0.1.2" version = "0.2.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"] authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix server config utils" description = "Actix server config utils"
homepage = "https://actix.rs" homepage = "https://actix.rs"
@ -33,6 +33,6 @@ futures = "0.1.25"
tokio-io = "0.1.12" tokio-io = "0.1.12"
tokio-tcp = "0.1" tokio-tcp = "0.1"
tokio-openssl = { version="0.3.0", optional = true } tokio-openssl = { version="0.3.0", optional = true }
rustls = { version = "0.15.2", optional = true } rustls = { version = "0.16.0", optional = true }
tokio-rustls = { version = "0.9.1", optional = true } tokio-rustls = { version = "0.10.0", optional = true }
tokio-uds = { version="0.2.5", optional = true } tokio-uds = { version="0.2.5", optional = true }

View File

@ -1,5 +1,12 @@
# Changes # Changes
## [0.2.0] - 2019-10-03
### Changed
* Update `rustls` to 0.16
* Minimum required Rust version upped to 1.37.0
## [0.1.2] - 2019-07-18 ## [0.1.2] - 2019-07-18
### Added ### Added

View File

@ -195,7 +195,7 @@ impl<T: IoStream> IoStream for tokio_openssl::SslStream<T> {
} }
#[cfg(any(feature = "rust-tls"))] #[cfg(any(feature = "rust-tls"))]
impl<T: IoStream> IoStream for tokio_rustls::TlsStream<T, rustls::ServerSession> { impl<T: IoStream> IoStream for tokio_rustls::server::TlsStream<T> {
#[inline] #[inline]
fn peer_addr(&self) -> Option<net::SocketAddr> { fn peer_addr(&self) -> Option<net::SocketAddr> {
self.get_ref().0.peer_addr() self.get_ref().0.peer_addr()

View File

@ -1,5 +1,12 @@
# Changes # Changes
## [0.7.0] - 2019-10-04
### Changed
* Update `rustls` to 0.16
* Minimum required Rust version upped to 1.37.0
## [0.6.1] - 2019-09-25 ## [0.6.1] - 2019-09-25
### Added ### Added

View File

@ -1,6 +1,6 @@
[package] [package]
name = "actix-server" name = "actix-server"
version = "0.6.1" version = "0.7.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"] authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix server - General purpose tcp server" description = "Actix server - General purpose tcp server"
keywords = ["network", "framework", "async", "futures"] keywords = ["network", "framework", "async", "futures"]
@ -38,7 +38,7 @@ uds = ["mio-uds", "tokio-uds", "actix-server-config/uds"]
[dependencies] [dependencies]
actix-rt = "0.2.2" actix-rt = "0.2.2"
actix-service = "0.4.1" actix-service = "0.4.1"
actix-server-config = "0.1.2" actix-server-config = "0.2.0"
log = "0.4" log = "0.4"
num_cpus = "1.0" num_cpus = "1.0"
@ -65,10 +65,10 @@ openssl = { version="0.10", optional = true }
tokio-openssl = { version="0.3", optional = true } tokio-openssl = { version="0.3", optional = true }
# rustls # rustls
rustls = { version = "0.15.2", optional = true } rustls = { version = "0.16.0", optional = true }
tokio-rustls = { version = "0.9.1", optional = true } tokio-rustls = { version = "0.10.0", optional = true }
webpki = { version = "0.19", optional = true } webpki = { version = "0.21", optional = true }
webpki-roots = { version = "0.16", optional = true } webpki-roots = { version = "0.17", optional = true }
[dev-dependencies] [dev-dependencies]
bytes = "0.4" bytes = "0.4"

View File

@ -4,9 +4,9 @@ use std::sync::Arc;
use actix_service::{NewService, Service}; use actix_service::{NewService, Service};
use futures::{future::ok, future::FutureResult, Async, Future, Poll}; use futures::{future::ok, future::FutureResult, Async, Future, Poll};
use rustls::{ServerConfig, ServerSession}; use rustls::ServerConfig;
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
use tokio_rustls::{Accept, TlsAcceptor, TlsStream}; use tokio_rustls::{server::TlsStream, Accept, TlsAcceptor};
use crate::counter::{Counter, CounterGuard}; use crate::counter::{Counter, CounterGuard};
use crate::ssl::MAX_CONN_COUNTER; use crate::ssl::MAX_CONN_COUNTER;
@ -41,7 +41,7 @@ impl<T, P> Clone for RustlsAcceptor<T, P> {
impl<T: AsyncRead + AsyncWrite, P> NewService for RustlsAcceptor<T, P> { impl<T: AsyncRead + AsyncWrite, P> NewService for RustlsAcceptor<T, P> {
type Request = Io<T, P>; type Request = Io<T, P>;
type Response = Io<TlsStream<T, ServerSession>, P>; type Response = Io<TlsStream<T>, P>;
type Error = io::Error; type Error = io::Error;
type Config = SrvConfig; type Config = SrvConfig;
@ -70,7 +70,7 @@ pub struct RustlsAcceptorService<T, P> {
impl<T: AsyncRead + AsyncWrite, P> Service for RustlsAcceptorService<T, P> { impl<T: AsyncRead + AsyncWrite, P> Service for RustlsAcceptorService<T, P> {
type Request = Io<T, P>; type Request = Io<T, P>;
type Response = Io<TlsStream<T, ServerSession>, P>; type Response = Io<TlsStream<T>, P>;
type Error = io::Error; type Error = io::Error;
type Future = RustlsAcceptorServiceFut<T, P>; type Future = RustlsAcceptorServiceFut<T, P>;
@ -102,7 +102,7 @@ where
} }
impl<T: AsyncRead + AsyncWrite, P> Future for RustlsAcceptorServiceFut<T, P> { impl<T: AsyncRead + AsyncWrite, P> Future for RustlsAcceptorServiceFut<T, P> {
type Item = Io<TlsStream<T, ServerSession>, P>; type Item = Io<TlsStream<T>, P>;
type Error = io::Error; type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(&mut self) -> Poll<Self::Item, Self::Error> {

View File

@ -23,7 +23,9 @@ name = "actix_service"
path = "src/lib.rs" path = "src/lib.rs"
[dependencies] [dependencies]
futures = "0.1.25" futures = "0.3.1"
pin-project = "0.4.0-alpha.11"
[dev-dependencies] [dev-dependencies]
tokio = "0.2.0-alpha.5"
actix-rt = "0.2" actix-rt = "0.2"

View File

@ -1,14 +1,21 @@
use futures::{Async, Future, Poll}; use futures::{Future, Poll};
use super::{IntoNewService, NewService, Service}; use super::{IntoNewService, NewService, Service};
use crate::cell::Cell; use crate::cell::Cell;
use pin_project::pin_project;
use std::pin::Pin;
use std::task::Context;
/// Service for the `and_then` combinator, chaining a computation onto the end /// Service for the `and_then` combinator, chaining a computation onto the end
/// of another service which completes successfully. /// of another service which completes successfully.
/// ///
/// This is created by the `ServiceExt::and_then` method. /// This is created by the `ServiceExt::and_then` method.
#[pin_project]
pub struct AndThen<A, B> { pub struct AndThen<A, B> {
#[pin]
a: A, a: A,
#[pin]
b: Cell<B>, b: Cell<B>,
} }
@ -45,12 +52,16 @@ where
type Error = A::Error; type Error = A::Error;
type Future = AndThenFuture<A, B>; type Future = AndThenFuture<A, B>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(
let not_ready = self.a.poll_ready()?.is_not_ready(); mut self: Pin<&mut Self>,
if self.b.get_mut().poll_ready()?.is_not_ready() || not_ready { cx: &mut Context<'_>,
Ok(Async::NotReady) ) -> Poll<Result<(), Self::Error>> {
let this = self.project();
let not_ready = !this.a.poll_ready(cx)?.is_ready();
if !this.b.get_pin().poll_ready(cx)?.is_ready() || not_ready {
Poll::Pending
} else { } else {
Ok(Async::Ready(())) Poll::Ready(Ok(()))
} }
} }
@ -59,13 +70,16 @@ where
} }
} }
#[pin_project]
pub struct AndThenFuture<A, B> pub struct AndThenFuture<A, B>
where where
A: Service, A: Service,
B: Service<Request = A::Response, Error = A::Error>, B: Service<Request = A::Response, Error = A::Error>,
{ {
b: Cell<B>, b: Cell<B>,
#[pin]
fut_b: Option<B::Future>, fut_b: Option<B::Future>,
#[pin]
fut_a: Option<A::Future>, fut_a: Option<A::Future>,
} }
@ -88,22 +102,33 @@ where
A: Service, A: Service,
B: Service<Request = A::Response, Error = A::Error>, B: Service<Request = A::Response, Error = A::Error>,
{ {
type Item = B::Response; type Output = Result<B::Response, A::Error>;
type Error = A::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if let Some(ref mut fut) = self.fut_b { let mut this = self.project();
return fut.poll();
}
match self.fut_a.as_mut().expect("Bug in actix-service").poll() { loop {
Ok(Async::Ready(resp)) => { let mut fut_a = this.fut_a.as_mut();
let _ = self.fut_a.take(); let mut fut_b = this.fut_b.as_mut();
self.fut_b = Some(self.b.get_mut().call(resp));
self.poll() if let Some(fut) = fut_b.as_mut().as_pin_mut() {
return fut.poll(cx);
}
match fut_a
.as_mut()
.as_pin_mut()
.expect("Bug in actix-service")
.poll(cx)
{
Poll::Ready(Ok(resp)) => {
fut_a.set(None);
let new_fut = this.b.get_mut().call(resp);
fut_b.set(Some(new_fut));
}
Poll::Ready(Err(e)) => return Poll::Ready(Err(e)),
Poll::Pending => return Poll::Pending,
} }
Ok(Async::NotReady) => Ok(Async::NotReady),
Err(err) => Err(err),
} }
} }
} }
@ -174,13 +199,17 @@ where
} }
} }
#[pin_project]
pub struct AndThenNewServiceFuture<A, B> pub struct AndThenNewServiceFuture<A, B>
where where
A: NewService, A: NewService,
B: NewService<Request = A::Response>, B: NewService<Request = A::Response>,
{ {
#[pin]
fut_b: B::Future, fut_b: B::Future,
#[pin]
fut_a: A::Future, fut_a: A::Future,
a: Option<A::Service>, a: Option<A::Service>,
b: Option<B::Service>, b: Option<B::Service>,
} }
@ -205,37 +234,35 @@ where
A: NewService, A: NewService,
B: NewService<Request = A::Response, Error = A::Error, InitError = A::InitError>, B: NewService<Request = A::Response, Error = A::Error, InitError = A::InitError>,
{ {
type Item = AndThen<A::Service, B::Service>; type Output = Result<AndThen<A::Service, B::Service>, A::InitError>;
type Error = A::InitError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.a.is_none() { let this = self.project();
if let Async::Ready(service) = self.fut_a.poll()? { if this.a.is_none() {
self.a = Some(service); if let Poll::Ready(service) = this.fut_a.poll(cx)? {
*this.a = Some(service);
} }
} }
if this.b.is_none() {
if self.b.is_none() { if let Poll::Ready(service) = this.fut_b.poll(cx)? {
if let Async::Ready(service) = self.fut_b.poll()? { *this.b = Some(service);
self.b = Some(service);
} }
} }
if this.a.is_some() && this.b.is_some() {
if self.a.is_some() && self.b.is_some() { Poll::Ready(Ok(AndThen::new(
Ok(Async::Ready(AndThen::new( this.a.take().unwrap(),
self.a.take().unwrap(), this.b.take().unwrap(),
self.b.take().unwrap(),
))) )))
} else { } else {
Ok(Async::NotReady) Poll::Pending
} }
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use futures::future::{ok, FutureResult}; use futures::future::{ok, poll_fn, ready, Ready};
use futures::{Async, Poll}; use futures::Poll;
use std::cell::Cell; use std::cell::Cell;
use std::rc::Rc; use std::rc::Rc;
@ -243,15 +270,19 @@ mod tests {
use crate::{NewService, Service, ServiceExt}; use crate::{NewService, Service, ServiceExt};
struct Srv1(Rc<Cell<usize>>); struct Srv1(Rc<Cell<usize>>);
impl Service for Srv1 { impl Service for Srv1 {
type Request = &'static str; type Request = &'static str;
type Response = &'static str; type Response = &'static str;
type Error = (); type Error = ();
type Future = FutureResult<Self::Response, ()>; type Future = Ready<Result<Self::Response, ()>>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>> {
self.0.set(self.0.get() + 1); self.0.set(self.0.get() + 1);
Ok(Async::Ready(())) Poll::Ready(Ok(()))
} }
fn call(&mut self, req: &'static str) -> Self::Future { fn call(&mut self, req: &'static str) -> Self::Future {
@ -266,11 +297,14 @@ mod tests {
type Request = &'static str; type Request = &'static str;
type Response = (&'static str, &'static str); type Response = (&'static str, &'static str);
type Error = (); type Error = ();
type Future = FutureResult<Self::Response, ()>; type Future = Ready<Result<Self::Response, ()>>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>> {
self.0.set(self.0.get() + 1); self.0.set(self.0.get() + 1);
Ok(Async::Ready(())) Poll::Ready(Ok(()))
} }
fn call(&mut self, req: &'static str) -> Self::Future { fn call(&mut self, req: &'static str) -> Self::Future {
@ -278,39 +312,35 @@ mod tests {
} }
} }
#[test] #[tokio::test]
fn test_poll_ready() { async fn test_poll_ready() {
let cnt = Rc::new(Cell::new(0)); let cnt = Rc::new(Cell::new(0));
let mut srv = Srv1(cnt.clone()).and_then(Srv2(cnt.clone())); let mut srv = Srv1(cnt.clone()).and_then(Srv2(cnt.clone()));
let res = srv.poll_ready(); let res = srv.poll_once().await;
assert!(res.is_ok()); assert_eq!(res, Poll::Ready(Ok(())));
assert_eq!(res.unwrap(), Async::Ready(()));
assert_eq!(cnt.get(), 2); assert_eq!(cnt.get(), 2);
} }
#[test] #[tokio::test]
fn test_call() { async fn test_call() {
let cnt = Rc::new(Cell::new(0)); let cnt = Rc::new(Cell::new(0));
let mut srv = Srv1(cnt.clone()).and_then(Srv2(cnt)); let mut srv = Srv1(cnt.clone()).and_then(Srv2(cnt));
let res = srv.call("srv1").poll(); let res = srv.call("srv1").await;
assert!(res.is_ok()); assert!(res.is_ok());
assert_eq!(res.unwrap(), Async::Ready(("srv1", "srv2"))); assert_eq!(res.unwrap(), (("srv1", "srv2")));
} }
#[test] #[tokio::test]
fn test_new_service() { async fn test_new_service() {
let cnt = Rc::new(Cell::new(0)); let cnt = Rc::new(Cell::new(0));
let cnt2 = cnt.clone(); let cnt2 = cnt.clone();
let blank = move || Ok::<_, ()>(Srv1(cnt2.clone())); let blank = move || ready(Ok::<_, ()>(Srv1(cnt2.clone())));
let new_srv = blank let new_srv = blank
.into_new_service() .into_new_service()
.and_then(move || Ok(Srv2(cnt.clone()))); .and_then(move || ready(Ok(Srv2(cnt.clone()))));
if let Async::Ready(mut srv) = new_srv.new_service(&()).poll().unwrap() { let mut srv = new_srv.new_service(&()).await.unwrap();
let res = srv.call("srv1").poll(); let res = srv.call("srv1").await;
assert!(res.is_ok()); assert!(res.is_ok());
assert_eq!(res.unwrap(), Async::Ready(("srv1", "srv2"))); assert_eq!(res.unwrap(), ("srv1", "srv2"));
} else {
panic!()
}
} }
} }

View File

@ -1,11 +1,15 @@
use std::rc::Rc; use std::rc::Rc;
use futures::{Async, Future, Poll}; use futures::{Future, Poll};
use crate::and_then::AndThen; use crate::and_then::AndThen;
use crate::from_err::FromErr; use crate::from_err::FromErr;
use crate::{NewService, Transform}; use crate::{NewService, Transform};
use pin_project::pin_project;
use std::pin::Pin;
use std::task::Context;
/// `Apply` new service combinator /// `Apply` new service combinator
pub struct AndThenTransform<T, A, B> { pub struct AndThenTransform<T, A, B> {
a: A, a: A,
@ -72,6 +76,7 @@ where
} }
} }
#[pin_project]
pub struct AndThenTransformFuture<T, A, B> pub struct AndThenTransformFuture<T, A, B>
where where
A: NewService, A: NewService,
@ -79,8 +84,11 @@ where
T: Transform<B::Service, Request = A::Response, InitError = A::InitError>, T: Transform<B::Service, Request = A::Response, InitError = A::InitError>,
T::Error: From<A::Error>, T::Error: From<A::Error>,
{ {
#[pin]
fut_a: A::Future, fut_a: A::Future,
#[pin]
fut_b: B::Future, fut_b: B::Future,
#[pin]
fut_t: Option<T::Future>, fut_t: Option<T::Future>,
a: Option<A::Service>, a: Option<A::Service>,
t: Option<T::Transform>, t: Option<T::Transform>,
@ -94,56 +102,63 @@ where
T: Transform<B::Service, Request = A::Response, InitError = A::InitError>, T: Transform<B::Service, Request = A::Response, InitError = A::InitError>,
T::Error: From<A::Error>, T::Error: From<A::Error>,
{ {
type Item = AndThen<FromErr<A::Service, T::Error>, T::Transform>; type Output = Result<AndThen<FromErr<A::Service, T::Error>, T::Transform>, T::InitError>;
type Error = T::InitError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.fut_t.is_none() { let mut this = self.project();
if let Async::Ready(service) = self.fut_b.poll()? {
self.fut_t = Some(self.t_cell.new_transform(service)); if this.fut_t.is_none() {
if let Poll::Ready(svc) = this.fut_b.poll(cx)? {
this.fut_t.set(Some(this.t_cell.new_transform(svc)))
} }
} }
if self.a.is_none() { if this.a.is_none() {
if let Async::Ready(service) = self.fut_a.poll()? { if let Poll::Ready(svc) = this.fut_a.poll(cx)? {
self.a = Some(service); *this.a = Some(svc)
} }
} }
if let Some(ref mut fut) = self.fut_t { if let Some(fut) = this.fut_t.as_pin_mut() {
if let Async::Ready(transform) = fut.poll()? { if let Poll::Ready(transform) = fut.poll(cx)? {
self.t = Some(transform); *this.t = Some(transform)
} }
} }
if self.a.is_some() && self.t.is_some() { if this.a.is_some() && this.t.is_some() {
Ok(Async::Ready(AndThen::new( Poll::Ready(Ok(AndThen::new(
FromErr::new(self.a.take().unwrap()), FromErr::new(this.a.take().unwrap()),
self.t.take().unwrap(), this.t.take().unwrap(),
))) )))
} else { } else {
Ok(Async::NotReady) Poll::Pending
} }
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use futures::future::{ok, FutureResult}; use futures::future::{ok, ready, Ready};
use futures::{Async, Future, Poll}; use futures::{Future, FutureExt, Poll, TryFutureExt};
use crate::{IntoNewService, IntoService, NewService, Service, ServiceExt}; use crate::{IntoNewService, IntoService, NewService, Service, ServiceExt};
use std::pin::Pin;
use std::task::Context;
#[derive(Clone)] #[derive(Clone)]
struct Srv; struct Srv;
impl Service for Srv { impl Service for Srv {
type Request = (); type Request = ();
type Response = (); type Response = ();
type Error = (); type Error = ();
type Future = FutureResult<(), ()>; type Future = Ready<Result<(), ()>>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(
Ok(Async::Ready(())) self: Pin<&mut Self>,
ctx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Err(()))
} }
fn call(&mut self, _: ()) -> Self::Future { fn call(&mut self, _: ()) -> Self::Future {
@ -151,36 +166,32 @@ mod tests {
} }
} }
#[test] #[tokio::test]
fn test_apply() { async fn test_apply() {
let blank = |req| Ok(req); let blank = |req| ready(Ok(req));
let mut srv = blank let mut srv = blank
.into_service() .into_service()
.apply_fn(Srv, |req: &'static str, srv: &mut Srv| { .apply_fn(Srv, |req: &'static str, srv: &mut Srv| {
srv.call(()).map(move |res| (req, res)) srv.call(()).map_ok(move |res| (req, res))
}); });
assert!(srv.poll_ready().is_ok()); let res = srv.call("srv").await;
let res = srv.call("srv").poll();
assert!(res.is_ok()); assert!(res.is_ok());
assert_eq!(res.unwrap(), Async::Ready(("srv", ()))); assert_eq!(res.unwrap(), (("srv", ())));
} }
#[test] #[tokio::test]
fn test_new_service() { async fn test_new_service() {
let blank = || Ok::<_, ()>((|req| Ok(req)).into_service()); let blank = move || ok::<_, ()>((|req| ok(req)).into_service());
let new_srv = blank.into_new_service().apply( let new_srv = blank.into_new_service().apply(
|req: &'static str, srv: &mut Srv| srv.call(()).map(move |res| (req, res)), |req: &'static str, srv: &mut Srv| srv.call(()).map_ok(move |res| (req, res)),
|| Ok(Srv), || ok(Srv),
); );
if let Async::Ready(mut srv) = new_srv.new_service(&()).poll().unwrap() { let mut srv = new_srv.new_service(&()).await.unwrap();
assert!(srv.poll_ready().is_ok());
let res = srv.call("srv").poll(); let res = srv.call("srv").await;
assert!(res.is_ok()); assert!(res.is_ok());
assert_eq!(res.unwrap(), Async::Ready(("srv", ()))); assert_eq!(res.unwrap(), (("srv", ())));
} else {
panic!()
}
} }
} }

View File

@ -1,11 +1,16 @@
use futures::{Future, Poll};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::pin::Pin;
use futures::{Async, Future, IntoFuture, Poll}; use std::task::Context;
use super::{IntoNewService, IntoService, NewService, Service}; use super::{IntoNewService, IntoService, NewService, Service};
use crate::cell::Cell; use crate::cell::Cell;
use crate::IntoFuture;
use pin_project::pin_project;
/// `Apply` service combinator /// `Apply` service combinator
#[pin_project]
pub struct AndThenApply<A, B, F, Out> pub struct AndThenApply<A, B, F, Out>
where where
A: Service, A: Service,
@ -14,8 +19,11 @@ where
Out: IntoFuture, Out: IntoFuture,
Out::Error: Into<A::Error>, Out::Error: Into<A::Error>,
{ {
#[pin]
a: A, a: A,
#[pin]
b: Cell<B>, b: Cell<B>,
#[pin]
f: Cell<F>, f: Cell<F>,
r: PhantomData<(Out,)>, r: PhantomData<(Out,)>,
} }
@ -70,12 +78,16 @@ where
type Error = A::Error; type Error = A::Error;
type Future = AndThenApplyFuture<A, B, F, Out>; type Future = AndThenApplyFuture<A, B, F, Out>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(
let not_ready = self.a.poll_ready()?.is_not_ready(); mut self: Pin<&mut Self>,
if self.b.get_mut().poll_ready()?.is_not_ready() || not_ready { ctx: &mut Context<'_>,
Ok(Async::NotReady) ) -> Poll<Result<(), Self::Error>> {
let this = self.project();
let not_ready = !this.a.poll_ready(ctx)?.is_ready();
if !this.b.get_pin().poll_ready(ctx).is_ready() || not_ready {
Poll::Pending
} else { } else {
Ok(Async::Ready(())) Poll::Ready(Ok(()))
} }
} }
@ -89,6 +101,7 @@ where
} }
} }
#[pin_project]
pub struct AndThenApplyFuture<A, B, F, Out> pub struct AndThenApplyFuture<A, B, F, Out>
where where
A: Service, A: Service,
@ -99,7 +112,9 @@ where
{ {
b: Cell<B>, b: Cell<B>,
f: Cell<F>, f: Cell<F>,
#[pin]
fut_a: Option<A::Future>, fut_a: Option<A::Future>,
#[pin]
fut_b: Option<Out::Future>, fut_b: Option<Out::Future>,
} }
@ -111,23 +126,30 @@ where
Out: IntoFuture, Out: IntoFuture,
Out::Error: Into<A::Error>, Out::Error: Into<A::Error>,
{ {
type Item = Out::Item; type Output = Result<Out::Item, A::Error>;
type Error = A::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if let Some(ref mut fut) = self.fut_b { let mut this = self.project();
return fut.poll().map_err(|e| e.into()); loop {
} if let Some(fut) = this.fut_b.as_mut().as_pin_mut() {
return fut.poll(cx).map_err(|e| e.into());
match self.fut_a.as_mut().expect("Bug in actix-service").poll() { }
Ok(Async::Ready(resp)) => {
let _ = self.fut_a.take(); match this
self.fut_b = .fut_a
Some((&mut *self.f.get_mut())(resp, self.b.get_mut()).into_future()); .as_mut()
self.poll() .as_pin_mut()
.expect("Bug in actix-service")
.poll(cx)?
{
Poll::Ready(resp) => {
this.fut_a.set(None);
this.fut_b.set(Some(
(&mut *this.f.get_mut())(resp, this.b.get_mut()).into_future(),
));
}
Poll::Pending => return Poll::Pending,
} }
Ok(Async::NotReady) => Ok(Async::NotReady),
Err(err) => Err(err),
} }
} }
} }
@ -195,12 +217,13 @@ where
a: None, a: None,
b: None, b: None,
f: self.f.clone(), f: self.f.clone(),
fut_a: self.a.new_service(cfg).into_future(), fut_a: self.a.new_service(cfg),
fut_b: self.b.new_service(cfg).into_future(), fut_b: self.b.new_service(cfg),
} }
} }
} }
#[pin_project]
pub struct AndThenApplyNewServiceFuture<A, B, F, Out> pub struct AndThenApplyNewServiceFuture<A, B, F, Out>
where where
A: NewService, A: NewService,
@ -209,7 +232,9 @@ where
Out: IntoFuture, Out: IntoFuture,
Out::Error: Into<A::Error>, Out::Error: Into<A::Error>,
{ {
#[pin]
fut_b: B::Future, fut_b: B::Future,
#[pin]
fut_a: A::Future, fut_a: A::Future,
f: Cell<F>, f: Cell<F>,
a: Option<A::Service>, a: Option<A::Service>,
@ -224,53 +249,60 @@ where
Out: IntoFuture, Out: IntoFuture,
Out::Error: Into<A::Error>, Out::Error: Into<A::Error>,
{ {
type Item = AndThenApply<A::Service, B::Service, F, Out>; type Output = Result<AndThenApply<A::Service, B::Service, F, Out>, A::InitError>;
type Error = A::InitError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.a.is_none() { let this = self.project();
if let Async::Ready(service) = self.fut_a.poll()? {
self.a = Some(service); if this.a.is_none() {
if let Poll::Ready(service) = this.fut_a.poll(cx)? {
*this.a = Some(service);
} }
} }
if self.b.is_none() { if this.b.is_none() {
if let Async::Ready(service) = self.fut_b.poll()? { if let Poll::Ready(service) = this.fut_b.poll(cx)? {
self.b = Some(service); *this.b = Some(service);
} }
} }
if self.a.is_some() && self.b.is_some() { if this.a.is_some() && this.b.is_some() {
Ok(Async::Ready(AndThenApply { Poll::Ready(Ok(AndThenApply {
f: self.f.clone(), f: this.f.clone(),
a: self.a.take().unwrap(), a: this.a.take().unwrap(),
b: Cell::new(self.b.take().unwrap()), b: Cell::new(this.b.take().unwrap()),
r: PhantomData, r: PhantomData,
})) }))
} else { } else {
Ok(Async::NotReady) Poll::Pending
} }
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use futures::future::{ok, FutureResult}; use futures::future::{ok, Ready};
use futures::{Async, Future, Poll}; use futures::{Future, Poll, TryFutureExt};
use crate::blank::{Blank, BlankNewService}; use crate::blank::{Blank, BlankNewService};
use crate::{NewService, Service, ServiceExt}; use crate::{NewService, Service, ServiceExt};
use std::pin::Pin;
use std::task::Context;
#[derive(Clone)] #[derive(Clone)]
struct Srv; struct Srv;
impl Service for Srv { impl Service for Srv {
type Request = (); type Request = ();
type Response = (); type Response = ();
type Error = (); type Error = ();
type Future = FutureResult<(), ()>; type Future = Ready<Result<(), ()>>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(
Ok(Async::Ready(())) self: Pin<&mut Self>,
ctx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
} }
fn call(&mut self, _: ()) -> Self::Future { fn call(&mut self, _: ()) -> Self::Future {
@ -278,30 +310,27 @@ mod tests {
} }
} }
#[test] #[tokio::test]
fn test_call() { async fn test_call() {
let mut srv = Blank::new().apply_fn(Srv, |req: &'static str, srv| { let mut srv = Blank::new().apply_fn(Srv, |req: &'static str, srv| {
srv.call(()).map(move |res| (req, res)) srv.call(()).map_ok(move |res| (req, res))
}); });
assert!(srv.poll_ready().is_ok()); assert_eq!(srv.poll_once().await, Poll::Ready(Ok(())));
let res = srv.call("srv").poll(); let res = srv.call("srv").await;
assert!(res.is_ok()); assert!(res.is_ok());
assert_eq!(res.unwrap(), Async::Ready(("srv", ()))); assert_eq!(res.unwrap(), (("srv", ())));
} }
#[test] #[tokio::test]
fn test_new_service() { async fn test_new_service() {
let new_srv = BlankNewService::new_unit().apply_fn( let new_srv = BlankNewService::new_unit().apply_fn(
|| Ok(Srv), || ok(Srv),
|req: &'static str, srv| srv.call(()).map(move |res| (req, res)), |req: &'static str, srv| srv.call(()).map_ok(move |res| (req, res)),
); );
if let Async::Ready(mut srv) = new_srv.new_service(&()).poll().unwrap() { let mut srv = new_srv.new_service(&()).await.unwrap();
assert!(srv.poll_ready().is_ok()); assert_eq!(srv.poll_once().await, Poll::Ready(Ok(())));
let res = srv.call("srv").poll(); let res = srv.call("srv").await;
assert!(res.is_ok()); assert!(res.is_ok());
assert_eq!(res.unwrap(), Async::Ready(("srv", ()))); assert_eq!(res.unwrap(), (("srv", ())));
} else {
panic!()
}
} }
} }

View File

@ -1,9 +1,14 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use futures::{Async, Future, IntoFuture, Poll}; use futures::{ready, Future, Poll};
use super::{IntoNewService, IntoService, NewService, Service}; use super::{IntoNewService, IntoService, NewService, Service};
use crate::IntoFuture;
use pin_project::pin_project;
use std::pin::Pin;
use std::task::Context;
/// Apply tranform function to a service /// Apply tranform function to a service
pub fn apply_fn<T, F, In, Out, U>(service: U, f: F) -> Apply<T, F, In, Out> pub fn apply_fn<T, F, In, Out, U>(service: U, f: F) -> Apply<T, F, In, Out>
where where
@ -30,10 +35,12 @@ where
#[doc(hidden)] #[doc(hidden)]
/// `Apply` service combinator /// `Apply` service combinator
#[pin_project]
pub struct Apply<T, F, In, Out> pub struct Apply<T, F, In, Out>
where where
T: Service, T: Service,
{ {
#[pin]
service: T, service: T,
f: F, f: F,
r: PhantomData<(In, Out)>, r: PhantomData<(In, Out)>,
@ -82,8 +89,11 @@ where
type Error = Out::Error; type Error = Out::Error;
type Future = Out::Future; type Future = Out::Future;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(
self.service.poll_ready().map_err(|e| e.into()) mut self: Pin<&mut Self>,
ctx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>> {
Poll::Ready(ready!(self.project().service.poll_ready(ctx)).map_err(|e| e.into()))
} }
fn call(&mut self, req: In) -> Self::Future { fn call(&mut self, req: In) -> Self::Future {
@ -154,12 +164,14 @@ where
} }
} }
#[pin_project]
pub struct ApplyNewServiceFuture<T, F, In, Out> pub struct ApplyNewServiceFuture<T, F, In, Out>
where where
T: NewService, T: NewService,
F: FnMut(In, &mut T::Service) -> Out + Clone, F: FnMut(In, &mut T::Service) -> Out + Clone,
Out: IntoFuture, Out: IntoFuture,
{ {
#[pin]
fut: T::Future, fut: T::Future,
f: Option<F>, f: Option<F>,
r: PhantomData<(In, Out)>, r: PhantomData<(In, Out)>,
@ -187,36 +199,40 @@ where
Out: IntoFuture, Out: IntoFuture,
Out::Error: From<T::Error>, Out::Error: From<T::Error>,
{ {
type Item = Apply<T::Service, F, In, Out>; type Output = Result<Apply<T::Service, F, In, Out>, T::InitError>;
type Error = T::InitError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if let Async::Ready(service) = self.fut.poll()? { let this = self.project();
Ok(Async::Ready(Apply::new(service, self.f.take().unwrap()))) if let Poll::Ready(svc) = this.fut.poll(cx)? {
Poll::Ready(Ok(Apply::new(svc, this.f.take().unwrap())))
} else { } else {
Ok(Async::NotReady) Poll::Pending
} }
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use futures::future::{ok, FutureResult}; use futures::future::{ok, Ready};
use futures::{Async, Future, Poll}; use futures::{Future, Poll, TryFutureExt};
use super::*; use super::*;
use crate::{IntoService, NewService, Service, ServiceExt}; use crate::{IntoService, NewService, Service, ServiceExt};
#[derive(Clone)] #[derive(Clone)]
struct Srv; struct Srv;
impl Service for Srv { impl Service for Srv {
type Request = (); type Request = ();
type Response = (); type Response = ();
type Error = (); type Error = ();
type Future = FutureResult<(), ()>; type Future = Ready<Result<(), ()>>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(
Ok(Async::Ready(())) self: Pin<&mut Self>,
ctx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
} }
fn call(&mut self, _: ()) -> Self::Future { fn call(&mut self, _: ()) -> Self::Future {
@ -224,34 +240,33 @@ mod tests {
} }
} }
#[test] #[tokio::test]
fn test_call() { async fn test_call() {
let blank = |req| Ok(req); let blank = |req| ok(req);
let mut srv = blank let mut srv = blank
.into_service() .into_service()
.apply_fn(Srv, |req: &'static str, srv| { .apply_fn(Srv, |req: &'static str, srv| {
srv.call(()).map(move |res| (req, res)) srv.call(()).map_ok(move |res| (req, res))
}); });
assert!(srv.poll_ready().is_ok()); assert_eq!(srv.poll_once().await, Poll::Ready(Ok(())));
let res = srv.call("srv").poll(); let res = srv.call("srv").await;
assert!(res.is_ok()); assert!(res.is_ok());
assert_eq!(res.unwrap(), Async::Ready(("srv", ()))); assert_eq!(res.unwrap(), (("srv", ())));
} }
#[test] #[tokio::test]
fn test_new_service() { async fn test_new_service() {
let new_srv = ApplyNewService::new( let new_srv = ApplyNewService::new(
|| Ok::<_, ()>(Srv), || ok::<_, ()>(Srv),
|req: &'static str, srv| srv.call(()).map(move |res| (req, res)), |req: &'static str, srv| srv.call(()).map_ok(move |res| (req, res)),
); );
if let Async::Ready(mut srv) = new_srv.new_service(&()).poll().unwrap() {
assert!(srv.poll_ready().is_ok()); let mut srv = new_srv.new_service(&()).await.unwrap();
let res = srv.call("srv").poll();
assert!(res.is_ok()); assert_eq!(srv.poll_once().await, Poll::Ready(Ok(())));
assert_eq!(res.unwrap(), Async::Ready(("srv", ()))); let res = srv.call("srv").await;
} else { assert!(res.is_ok());
panic!() assert_eq!(res.unwrap(), (("srv", ())));
}
} }
} }

View File

@ -1,10 +1,14 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use futures::future::Future; use futures::future::Future;
use futures::{try_ready, Async, IntoFuture, Poll}; use futures::{ready, Poll};
use crate::cell::Cell; use crate::cell::Cell;
use crate::{IntoService, NewService, Service}; use crate::{IntoFuture, IntoService, NewService, Service};
use std::pin::Pin;
use std::task::Context;
use pin_project::pin_project;
/// Convert `Fn(&Config, &mut Service) -> Future<Service>` fn to a NewService /// Convert `Fn(&Config, &mut Service) -> Future<Service>` fn to a NewService
pub fn apply_cfg<F, C, T, R, S>( pub fn apply_cfg<F, C, T, R, S>(
@ -61,7 +65,8 @@ where
} }
} }
/// Convert `Fn(&Config) -> Future<Service>` fn to NewService /// Convert `Fn(&Config) -> Future<Service>` fn to NewService\
#[pin_project]
struct ApplyConfigService<F, C, T, R, S> struct ApplyConfigService<F, C, T, R, S>
where where
F: FnMut(&C, &mut T) -> R, F: FnMut(&C, &mut T) -> R,
@ -71,6 +76,7 @@ where
S: Service, S: Service,
{ {
f: Cell<F>, f: Cell<F>,
#[pin]
srv: Cell<T>, srv: Cell<T>,
_t: PhantomData<(C, R, S)>, _t: PhantomData<(C, R, S)>,
} }
@ -118,12 +124,14 @@ where
} }
} }
#[pin_project]
struct FnNewServiceConfigFut<R, S> struct FnNewServiceConfigFut<R, S>
where where
R: IntoFuture, R: IntoFuture,
R::Item: IntoService<S>, R::Item: IntoService<S>,
S: Service, S: Service,
{ {
#[pin]
fut: R::Future, fut: R::Future,
_t: PhantomData<(S,)>, _t: PhantomData<(S,)>,
} }
@ -134,11 +142,10 @@ where
R::Item: IntoService<S>, R::Item: IntoService<S>,
S: Service, S: Service,
{ {
type Item = S; type Output = Result<S, R::Error>;
type Error = R::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
Ok(Async::Ready(try_ready!(self.fut.poll()).into_service())) Poll::Ready(Ok(ready!(self.project().fut.poll(cx))?.into_service()))
} }
} }
@ -206,6 +213,7 @@ where
} }
} }
#[pin_project]
struct ApplyConfigNewServiceFut<F, C, T, R, S> struct ApplyConfigNewServiceFut<F, C, T, R, S>
where where
C: Clone, C: Clone,
@ -218,8 +226,11 @@ where
{ {
cfg: C, cfg: C,
f: Cell<F>, f: Cell<F>,
#[pin]
srv: Option<T::Service>, srv: Option<T::Service>,
#[pin]
srv_fut: Option<T::Future>, srv_fut: Option<T::Future>,
#[pin]
fut: Option<R::Future>, fut: Option<R::Future>,
_t: PhantomData<(S,)>, _t: PhantomData<(S,)>,
} }
@ -234,33 +245,38 @@ where
R::Item: IntoService<S>, R::Item: IntoService<S>,
S: Service, S: Service,
{ {
type Item = S; type Output = Result<S, R::Error>;
type Error = R::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if let Some(ref mut fut) = self.srv_fut { let mut this = self.project();
match fut.poll()? { 'poll: loop {
Async::NotReady => return Ok(Async::NotReady), if let Some(fut) = this.srv_fut.as_mut().as_pin_mut() {
Async::Ready(srv) => { match fut.poll(cx)? {
let _ = self.srv_fut.take(); Poll::Pending => return Poll::Pending,
self.srv = Some(srv); Poll::Ready(srv) => {
return self.poll(); this.srv_fut.set(None);
this.srv.set(Some(srv));
continue 'poll;
}
} }
} }
}
if let Some(ref mut fut) = self.fut { if let Some(fut) = this.fut.as_mut().as_pin_mut() {
Ok(Async::Ready(try_ready!(fut.poll()).into_service())) return Poll::Ready(Ok(ready!(fut.poll(cx))?.into_service()));
} else if let Some(ref mut srv) = self.srv { } else if let Some(mut srv) = this.srv.as_mut().as_pin_mut() {
match srv.poll_ready()? { match srv.as_mut().poll_ready(cx)? {
Async::NotReady => Ok(Async::NotReady), Poll::Ready(_) => {
Async::Ready(_) => { this.fut.set(Some(
self.fut = Some(self.f.get_mut()(&self.cfg, srv).into_future()); this.f.get_mut()(&this.cfg, unsafe { Pin::get_unchecked_mut(srv) })
return self.poll(); .into_future(),
));
continue 'poll;
}
Poll::Pending => return Poll::Pending,
} }
} else {
return Poll::Pending;
} }
} else {
Ok(Async::NotReady)
} }
} }
} }

View File

@ -1,9 +1,11 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use futures::future::{ok, FutureResult}; use futures::future::{ok, Ready};
use futures::{Async, Poll}; use futures::Poll;
use super::{NewService, Service}; use super::{NewService, Service};
use std::pin::Pin;
use std::task::Context;
/// Empty service /// Empty service
#[derive(Clone)] #[derive(Clone)]
@ -34,10 +36,13 @@ impl<R, E> Service for Blank<R, E> {
type Request = R; type Request = R;
type Response = R; type Response = R;
type Error = E; type Error = E;
type Future = FutureResult<R, E>; type Future = Ready<Result<R, E>>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(
Ok(Async::Ready(())) self: Pin<&mut Self>,
_ctx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
} }
fn call(&mut self, req: R) -> Self::Future { fn call(&mut self, req: R) -> Self::Future {
@ -76,7 +81,7 @@ impl<R, E1, E2> NewService for BlankNewService<R, E1, E2> {
type Config = (); type Config = ();
type Service = Blank<R, E1>; type Service = Blank<R, E1>;
type InitError = E2; type InitError = E2;
type Future = FutureResult<Self::Service, Self::InitError>; type Future = Ready<Result<Self::Service, Self::InitError>>;
fn new_service(&self, _: &()) -> Self::Future { fn new_service(&self, _: &()) -> Self::Future {
ok(Blank::default()) ok(Blank::default())

View File

@ -1,7 +1,11 @@
use futures::future::{err, ok, Either, FutureResult}; use std::pin::Pin;
use futures::{Async, Future, IntoFuture, Poll};
use crate::{NewService, Service}; use crate::{IntoFuture, NewService, Service, ServiceExt};
use futures::future::FutureExt;
use futures::future::LocalBoxFuture;
use futures::future::{err, ok, Either, Ready};
use futures::{Future, Poll};
use std::task::Context;
pub type BoxedService<Req, Res, Err> = Box< pub type BoxedService<Req, Res, Err> = Box<
dyn Service< dyn Service<
@ -13,7 +17,7 @@ pub type BoxedService<Req, Res, Err> = Box<
>; >;
pub type BoxedServiceResponse<Res, Err> = pub type BoxedServiceResponse<Res, Err> =
Either<FutureResult<Res, Err>, Box<dyn Future<Item = Res, Error = Err>>>; Either<Ready<Result<Res, Err>>, LocalBoxFuture<'static, Result<Res, Err>>>;
pub struct BoxedNewService<C, Req, Res, Err, InitErr>(Inner<C, Req, Res, Err, InitErr>); pub struct BoxedNewService<C, Req, Res, Err, InitErr>(Inner<C, Req, Res, Err, InitErr>);
@ -53,7 +57,7 @@ type Inner<C, Req, Res, Err, InitErr> = Box<
Error = Err, Error = Err,
InitError = InitErr, InitError = InitErr,
Service = BoxedService<Req, Res, Err>, Service = BoxedService<Req, Res, Err>,
Future = Box<dyn Future<Item = BoxedService<Req, Res, Err>, Error = InitErr>>, Future = LocalBoxFuture<'static, Result<BoxedService<Req, Res, Err>, InitErr>>,
>, >,
>; >;
@ -70,7 +74,8 @@ where
type InitError = InitErr; type InitError = InitErr;
type Config = C; type Config = C;
type Service = BoxedService<Req, Res, Err>; type Service = BoxedService<Req, Res, Err>;
type Future = Box<dyn Future<Item = Self::Service, Error = Self::InitError>>;
type Future = LocalBoxFuture<'static, Result<Self::Service, InitErr>>;
fn new_service(&self, cfg: &C) -> Self::Future { fn new_service(&self, cfg: &C) -> Self::Future {
self.0.new_service(cfg) self.0.new_service(cfg)
@ -99,15 +104,18 @@ where
type InitError = InitErr; type InitError = InitErr;
type Config = C; type Config = C;
type Service = BoxedService<Req, Res, Err>; type Service = BoxedService<Req, Res, Err>;
type Future = Box<dyn Future<Item = Self::Service, Error = Self::InitError>>; type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;
fn new_service(&self, cfg: &C) -> Self::Future { fn new_service(&self, cfg: &C) -> Self::Future {
Box::new( /* TODO: Figure out what the hell is hapenning here
Box::new(
self.service self.service
.new_service(cfg) .new_service(cfg)
.into_future() .into_future()
.map(ServiceWrapper::boxed), .map(ServiceWrapper::boxed),
) )
*/
unimplemented!()
} }
} }
@ -132,10 +140,22 @@ where
type Response = Res; type Response = Res;
type Error = Err; type Error = Err;
type Future = Either< type Future = Either<
FutureResult<Self::Response, Self::Error>, Ready<Result<Self::Response, Self::Error>>,
Box<dyn Future<Item = Self::Response, Error = Self::Error>>, LocalBoxFuture<'static, Result<Res, Err>>,
>; >;
fn poll_ready(
self: Pin<&mut Self>,
ctx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>> {
unimplemented!()
}
fn call(&mut self, req: Self::Request) -> Self::Future {
unimplemented!()
}
/*
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.0.poll_ready() self.0.poll_ready()
} }
@ -148,4 +168,5 @@ where
Ok(Async::NotReady) => Either::B(Box::new(fut)), Ok(Async::NotReady) => Either::B(Box::new(fut)),
} }
} }
*/
} }

View File

@ -1,4 +1,5 @@
//! Custom cell impl //! Custom cell impl
use std::pin::Pin;
use std::{cell::UnsafeCell, fmt, rc::Rc}; use std::{cell::UnsafeCell, fmt, rc::Rc};
pub(crate) struct Cell<T> { pub(crate) struct Cell<T> {
@ -33,6 +34,9 @@ impl<T> Cell<T> {
pub(crate) fn get_mut(&mut self) -> &mut T { pub(crate) fn get_mut(&mut self) -> &mut T {
unsafe { &mut *self.inner.as_ref().get() } unsafe { &mut *self.inner.as_ref().get() }
} }
pub(crate) fn get_pin(self: Pin<&mut Self>) -> Pin<&mut T> {
unsafe { Pin::new_unchecked(&mut *Pin::get_unchecked_mut(self).inner.as_ref().get()) }
}
#[allow(clippy::mut_from_ref)] #[allow(clippy::mut_from_ref)]
pub(crate) unsafe fn get_mut_unsafe(&self) -> &mut T { pub(crate) unsafe fn get_mut_unsafe(&self) -> &mut T {

View File

@ -1,9 +1,14 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use futures::future::{ok, Future, FutureResult}; use crate::IntoFuture;
use futures::{try_ready, Async, IntoFuture, Poll}; use futures::future::{ok, Future, Ready};
use futures::{ready, Poll};
use crate::{IntoNewService, IntoService, NewService, Service}; use crate::{IntoNewService, IntoService, NewService, Service};
use std::pin::Pin;
use std::task::Context;
use pin_project::pin_project;
/// Create `NewService` for function that can act as a Service /// Create `NewService` for function that can act as a Service
pub fn service_fn<F, Req, Out, Cfg>(f: F) -> NewServiceFn<F, Req, Out, Cfg> pub fn service_fn<F, Req, Out, Cfg>(f: F) -> NewServiceFn<F, Req, Out, Cfg>
@ -75,8 +80,11 @@ where
type Error = Out::Error; type Error = Out::Error;
type Future = Out::Future; type Future = Out::Future;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(
Ok(Async::Ready(())) self: Pin<&mut Self>,
_ctx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
} }
fn call(&mut self, req: Req) -> Self::Future { fn call(&mut self, req: Req) -> Self::Future {
@ -135,7 +143,7 @@ where
type Config = Cfg; type Config = Cfg;
type Service = ServiceFn<F, Req, Out>; type Service = ServiceFn<F, Req, Out>;
type InitError = (); type InitError = ();
type Future = FutureResult<Self::Service, Self::InitError>; type Future = Ready<Result<Self::Service, Self::InitError>>;
fn new_service(&self, _: &Cfg) -> Self::Future { fn new_service(&self, _: &Cfg) -> Self::Future {
ok(ServiceFn::new(self.f.clone())) ok(ServiceFn::new(self.f.clone()))
@ -210,12 +218,14 @@ where
} }
} }
#[pin_project]
pub struct FnNewServiceConfigFut<R, S, E> pub struct FnNewServiceConfigFut<R, S, E>
where where
R: IntoFuture<Error = E>, R: IntoFuture<Error = E>,
R::Item: IntoService<S>, R::Item: IntoService<S>,
S: Service, S: Service,
{ {
#[pin]
fut: R::Future, fut: R::Future,
_t: PhantomData<(S,)>, _t: PhantomData<(S,)>,
} }
@ -226,11 +236,10 @@ where
R::Item: IntoService<S>, R::Item: IntoService<S>,
S: Service, S: Service,
{ {
type Item = S; type Output = Result<S, R::Error>;
type Error = R::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
Ok(Async::Ready(try_ready!(self.fut.poll()).into_service())) Poll::Ready(Ok(ready!(self.project().fut.poll(cx))?.into_service()))
} }
} }

View File

@ -1,10 +1,9 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use futures::future::{ok, FutureResult}; use futures::future::{ok, Ready};
use futures::IntoFuture;
use crate::apply::Apply; use crate::apply::Apply;
use crate::{IntoTransform, Service, Transform}; use crate::{IntoFuture, IntoTransform, Service, Transform};
/// Use function as transform service /// Use function as transform service
pub fn transform_fn<F, S, In, Out, Err>( pub fn transform_fn<F, S, In, Out, Err>(
@ -50,7 +49,7 @@ where
type Error = Out::Error; type Error = Out::Error;
type Transform = Apply<S, F, In, Out>; type Transform = Apply<S, F, In, Out>;
type InitError = Err; type InitError = Err;
type Future = FutureResult<Self::Transform, Self::InitError>; type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future { fn new_transform(&self, service: S) -> Self::Future {
ok(Apply::new(service, self.f.clone())) ok(Apply::new(service, self.f.clone()))

View File

@ -1,13 +1,19 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use futures::{Async, Future, Poll}; use futures::{Future, Poll};
use super::{NewService, Service}; use super::{NewService, Service};
use std::pin::Pin;
use std::task::Context;
use pin_project::pin_project;
/// Service for the `from_err` combinator, changing the error type of a service. /// Service for the `from_err` combinator, changing the error type of a service.
/// ///
/// This is created by the `ServiceExt::from_err` method. /// This is created by the `ServiceExt::from_err` method.
#[pin_project]
pub struct FromErr<A, E> { pub struct FromErr<A, E> {
#[pin]
service: A, service: A,
f: PhantomData<E>, f: PhantomData<E>,
} }
@ -47,8 +53,11 @@ where
type Error = E; type Error = E;
type Future = FromErrFuture<A, E>; type Future = FromErrFuture<A, E>;
fn poll_ready(&mut self) -> Poll<(), E> { fn poll_ready(
self.service.poll_ready().map_err(E::from) self: Pin<&mut Self>,
ctx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>> {
self.project().service.poll_ready(ctx).map_err(E::from)
} }
fn call(&mut self, req: A::Request) -> Self::Future { fn call(&mut self, req: A::Request) -> Self::Future {
@ -59,7 +68,9 @@ where
} }
} }
#[pin_project]
pub struct FromErrFuture<A: Service, E> { pub struct FromErrFuture<A: Service, E> {
#[pin]
fut: A::Future, fut: A::Future,
f: PhantomData<E>, f: PhantomData<E>,
} }
@ -69,11 +80,10 @@ where
A: Service, A: Service,
E: From<A::Error>, E: From<A::Error>,
{ {
type Item = A::Response; type Output = Result<A::Response, E>;
type Error = E;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.fut.poll().map_err(E::from) self.project().fut.poll(cx).map_err(E::from)
} }
} }
@ -131,11 +141,13 @@ where
} }
} }
#[pin_project]
pub struct FromErrNewServiceFuture<A, E> pub struct FromErrNewServiceFuture<A, E>
where where
A: NewService, A: NewService,
E: From<A::Error>, E: From<A::Error>,
{ {
#[pin]
fut: A::Future, fut: A::Future,
e: PhantomData<E>, e: PhantomData<E>,
} }
@ -145,34 +157,48 @@ where
A: NewService, A: NewService,
E: From<A::Error>, E: From<A::Error>,
{ {
type Item = FromErr<A::Service, E>; type Output = Result<FromErr<A::Service, E>, A::InitError>;
type Error = A::InitError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if let Async::Ready(service) = self.fut.poll()? { if let Poll::Ready(svc) = self.project().fut.poll(cx)? {
Ok(Async::Ready(FromErr::new(service))) Poll::Ready(Ok(FromErr::new(svc)))
} else { } else {
Ok(Async::NotReady) Poll::Pending
} }
} }
/*
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
if let Poll::Ready(service) = self.fut.poll()? {
Ok(Poll::Ready(FromErr::new(service)))
} else {
Ok(Poll::Pending)
}
}
*/
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use futures::future::{err, FutureResult}; use futures::future::{err, Ready};
use super::*; use super::*;
use crate::{IntoNewService, NewService, Service, ServiceExt}; use crate::{IntoNewService, NewService, Service, ServiceExt};
use tokio::future::ok;
struct Srv; struct Srv;
impl Service for Srv { impl Service for Srv {
type Request = (); type Request = ();
type Response = (); type Response = ();
type Error = (); type Error = ();
type Future = FutureResult<(), ()>; type Future = Ready<Result<(), ()>>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(
Err(()) self: Pin<&mut Self>,
ctx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Err(()))
} }
fn call(&mut self, _: ()) -> Self::Future { fn call(&mut self, _: ()) -> Self::Future {
@ -189,32 +215,29 @@ mod tests {
} }
} }
#[test] #[tokio::test]
fn test_poll_ready() { async fn test_poll_ready() {
let mut srv = Srv.from_err::<Error>(); let mut srv = Srv.from_err::<Error>();
let res = srv.poll_ready(); let res = srv.poll_once().await;
assert_eq!(res, Poll::Ready(Err(Error)));
}
#[tokio::test]
async fn test_call() {
let mut srv = Srv.from_err::<Error>();
let res = srv.call(()).await;
assert!(res.is_err()); assert!(res.is_err());
assert_eq!(res.err().unwrap(), Error); assert_eq!(res.err().unwrap(), Error);
} }
#[test] #[tokio::test]
fn test_call() { async fn test_new_service() {
let mut srv = Srv.from_err::<Error>(); let blank = || ok::<_, ()>(Srv);
let res = srv.call(()).poll();
assert!(res.is_err());
assert_eq!(res.err().unwrap(), Error);
}
#[test]
fn test_new_service() {
let blank = || Ok::<_, ()>(Srv);
let new_srv = blank.into_new_service().from_err::<Error>(); let new_srv = blank.into_new_service().from_err::<Error>();
if let Async::Ready(mut srv) = new_srv.new_service(&()).poll().unwrap() { let mut srv = new_srv.new_service(&()).await.unwrap();
let res = srv.call(()).poll(); let res = srv.call(()).await;
assert!(res.is_err()); assert!(res.is_err());
assert_eq!(res.err().unwrap(), Error); assert_eq!(res.err().unwrap(), Error);
} else {
panic!()
}
} }
} }

View File

@ -1,8 +1,13 @@
use futures::future::{ready, LocalBoxFuture, Ready};
use futures::{Future, Poll};
use std::cell::RefCell; use std::cell::RefCell;
use std::pin::Pin;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use std::task;
use std::task::Context;
use futures::{Future, IntoFuture, Poll}; mod cell;
mod and_then; mod and_then;
mod and_then_apply; mod and_then_apply;
@ -11,7 +16,6 @@ mod apply;
mod apply_cfg; mod apply_cfg;
pub mod blank; pub mod blank;
pub mod boxed; pub mod boxed;
mod cell;
mod fn_service; mod fn_service;
mod fn_transform; mod fn_transform;
mod from_err; mod from_err;
@ -24,6 +28,9 @@ mod transform;
mod transform_err; mod transform_err;
pub use self::and_then::{AndThen, AndThenNewService}; pub use self::and_then::{AndThen, AndThenNewService};
use self::and_then_apply::AndThenTransform;
use self::and_then_apply_fn::{AndThenApply, AndThenApplyNewService};
pub use self::apply::{apply_fn, new_apply_fn, Apply, ApplyNewService}; pub use self::apply::{apply_fn, new_apply_fn, Apply, ApplyNewService};
pub use self::apply_cfg::{apply_cfg, new_apply_cfg}; pub use self::apply_cfg::{apply_cfg, new_apply_cfg};
pub use self::fn_service::{new_service_cfg, new_service_fn, service_fn, ServiceFn}; pub use self::fn_service::{new_service_cfg, new_service_fn, service_fn, ServiceFn};
@ -36,8 +43,34 @@ pub use self::map_init_err::MapInitErr;
pub use self::then::{Then, ThenNewService}; pub use self::then::{Then, ThenNewService};
pub use self::transform::{apply_transform, IntoTransform, Transform}; pub use self::transform::{apply_transform, IntoTransform, Transform};
use self::and_then_apply::AndThenTransform; pub trait IntoFuture {
use self::and_then_apply_fn::{AndThenApply, AndThenApplyNewService}; type Item;
type Error;
type Future: Future<Output = Result<Self::Item, Self::Error>>;
fn into_future(self) -> Self::Future;
}
impl<F: Future<Output = Result<I, E>>, I, E> IntoFuture for F {
type Item = I;
type Error = E;
type Future = F;
fn into_future(self) -> Self::Future {
self
}
}
/*
impl <I,E> IntoFuture for Result<I,E> {
type Item = I;
type Error = E;
type Future = Ready<Self>;
fn into_future(self) -> Self::Future {
ready(self)
}
}
*/
/// An asynchronous function from `Request` to a `Response`. /// An asynchronous function from `Request` to a `Response`.
pub trait Service { pub trait Service {
@ -51,7 +84,7 @@ pub trait Service {
type Error; type Error;
/// The future response value. /// The future response value.
type Future: Future<Item = Self::Response, Error = Self::Error>; type Future: Future<Output = Result<Self::Response, Self::Error>>;
/// Returns `Ready` when the service is able to process requests. /// Returns `Ready` when the service is able to process requests.
/// ///
@ -62,7 +95,10 @@ pub trait Service {
/// This is a **best effort** implementation. False positives are permitted. /// This is a **best effort** implementation. False positives are permitted.
/// It is permitted for the service to return `Ready` from a `poll_ready` /// It is permitted for the service to return `Ready` from a `poll_ready`
/// call and the next invocation of `call` results in an error. /// call and the next invocation of `call` results in an error.
fn poll_ready(&mut self) -> Poll<(), Self::Error>; fn poll_ready(
self: Pin<&mut Self>,
ctx: &mut task::Context<'_>,
) -> Poll<Result<(), Self::Error>>;
/// Process the request and return the response asynchronously. /// Process the request and return the response asynchronously.
/// ///
@ -74,6 +110,31 @@ pub trait Service {
/// Calling `call` without calling `poll_ready` is permitted. The /// Calling `call` without calling `poll_ready` is permitted. The
/// implementation must be resilient to this fact. /// implementation must be resilient to this fact.
fn call(&mut self, req: Self::Request) -> Self::Future; fn call(&mut self, req: Self::Request) -> Self::Future;
#[cfg(test)]
fn poll_test(&mut self) -> Poll<Result<(), Self::Error>> {
// kinda stupid method, but works for our test purposes
unsafe {
let mut this = Pin::new_unchecked(self);
tokio::runtime::current_thread::Builder::new()
.build()
.unwrap()
.block_on(futures::future::poll_fn(move |cx| {
let this = &mut this;
Poll::Ready(this.as_mut().poll_ready(cx))
}))
}
}
fn poll_once<'a>(&'a mut self) -> LocalBoxFuture<'a, Poll<Result<(), Self::Error>>> {
unsafe {
let mut this = Pin::new_unchecked(self);
Pin::new_unchecked(Box::new(futures::future::poll_fn(move |cx| {
let this = &mut this;
Poll::Ready(this.as_mut().poll_ready(cx))
})))
}
}
} }
/// An extension trait for `Service`s that provides a variety of convenient /// An extension trait for `Service`s that provides a variety of convenient
@ -206,7 +267,7 @@ pub trait NewService {
type InitError; type InitError;
/// The future of the `Service` instance. /// The future of the `Service` instance.
type Future: Future<Item = Self::Service, Error = Self::InitError>; type Future: Future<Output = Result<Self::Service, Self::InitError>>;
/// Create and return a new service value asynchronously. /// Create and return a new service value asynchronously.
fn new_service(&self, cfg: &Self::Config) -> Self::Future; fn new_service(&self, cfg: &Self::Config) -> Self::Future;
@ -343,8 +404,11 @@ where
type Error = S::Error; type Error = S::Error;
type Future = S::Future; type Future = S::Future;
fn poll_ready(&mut self) -> Poll<(), S::Error> { fn poll_ready(
(**self).poll_ready() self: Pin<&mut Self>,
ctx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>> {
unsafe { self.map_unchecked_mut(|s| &mut **s).poll_ready(ctx) }
} }
fn call(&mut self, request: Self::Request) -> S::Future { fn call(&mut self, request: Self::Request) -> S::Future {
@ -361,8 +425,14 @@ where
type Error = S::Error; type Error = S::Error;
type Future = S::Future; type Future = S::Future;
fn poll_ready(&mut self) -> Poll<(), S::Error> { fn poll_ready(
(**self).poll_ready() mut self: Pin<&mut Self>,
ctx: &mut Context<'_>,
) -> Poll<Result<(), S::Error>> {
unsafe {
let p: &mut S = Pin::as_mut(&mut self).get_mut();
Pin::new_unchecked(p).poll_ready(ctx)
}
} }
fn call(&mut self, request: Self::Request) -> S::Future { fn call(&mut self, request: Self::Request) -> S::Future {
@ -379,12 +449,18 @@ where
type Error = S::Error; type Error = S::Error;
type Future = S::Future; type Future = S::Future;
fn poll_ready(&mut self) -> Poll<(), S::Error> { fn poll_ready(
self.borrow_mut().poll_ready() self: Pin<&mut Self>,
ctx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>> {
unsafe {
let r = self.get_unchecked_mut();
Pin::new_unchecked(&mut (*(**r).borrow_mut())).poll_ready(ctx)
}
} }
fn call(&mut self, request: Self::Request) -> S::Future { fn call(&mut self, request: Self::Request) -> S::Future {
self.borrow_mut().call(request) (&mut (**self).borrow_mut()).call(request)
} }
} }

View File

@ -1,13 +1,19 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use futures::{Async, Future, Poll}; use futures::{Future, Poll};
use super::{NewService, Service}; use super::{NewService, Service};
use std::pin::Pin;
use std::task::Context;
use pin_project::pin_project;
/// Service for the `map` combinator, changing the type of a service's response. /// Service for the `map` combinator, changing the type of a service's response.
/// ///
/// This is created by the `ServiceExt::map` method. /// This is created by the `ServiceExt::map` method.
#[pin_project]
pub struct Map<A, F, Response> { pub struct Map<A, F, Response> {
#[pin]
service: A, service: A,
f: F, f: F,
_t: PhantomData<Response>, _t: PhantomData<Response>,
@ -52,8 +58,11 @@ where
type Error = A::Error; type Error = A::Error;
type Future = MapFuture<A, F, Response>; type Future = MapFuture<A, F, Response>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(
self.service.poll_ready() self: Pin<&mut Self>,
ctx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>> {
self.project().service.poll_ready(ctx)
} }
fn call(&mut self, req: A::Request) -> Self::Future { fn call(&mut self, req: A::Request) -> Self::Future {
@ -61,12 +70,14 @@ where
} }
} }
#[pin_project]
pub struct MapFuture<A, F, Response> pub struct MapFuture<A, F, Response>
where where
A: Service, A: Service,
F: FnMut(A::Response) -> Response, F: FnMut(A::Response) -> Response,
{ {
f: F, f: F,
#[pin]
fut: A::Future, fut: A::Future,
} }
@ -85,13 +96,14 @@ where
A: Service, A: Service,
F: FnMut(A::Response) -> Response, F: FnMut(A::Response) -> Response,
{ {
type Item = Response; type Output = Result<Response, A::Error>;
type Error = A::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.fut.poll()? { let this = self.project();
Async::Ready(resp) => Ok(Async::Ready((self.f)(resp))), match this.fut.poll(cx) {
Async::NotReady => Ok(Async::NotReady), Poll::Ready(Ok(resp)) => Poll::Ready(Ok((this.f)(resp))),
Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
Poll::Pending => Poll::Pending,
} }
} }
} }
@ -151,11 +163,13 @@ where
} }
} }
#[pin_project]
pub struct MapNewServiceFuture<A, F, Res> pub struct MapNewServiceFuture<A, F, Res>
where where
A: NewService, A: NewService,
F: FnMut(A::Response) -> Res, F: FnMut(A::Response) -> Res,
{ {
#[pin]
fut: A::Future, fut: A::Future,
f: Option<F>, f: Option<F>,
} }
@ -175,34 +189,38 @@ where
A: NewService, A: NewService,
F: FnMut(A::Response) -> Res, F: FnMut(A::Response) -> Res,
{ {
type Item = Map<A::Service, F, Res>; type Output = Result<Map<A::Service, F, Res>, A::InitError>;
type Error = A::InitError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if let Async::Ready(service) = self.fut.poll()? { let this = self.project();
Ok(Async::Ready(Map::new(service, self.f.take().unwrap()))) if let Poll::Ready(svc) = this.fut.poll(cx)? {
Poll::Ready(Ok(Map::new(svc, this.f.take().unwrap())))
} else { } else {
Ok(Async::NotReady) Poll::Pending
} }
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use futures::future::{ok, FutureResult}; use futures::future::{ok, Ready};
use super::*; use super::*;
use crate::{IntoNewService, Service, ServiceExt}; use crate::{IntoNewService, Service, ServiceExt};
struct Srv; struct Srv;
impl Service for Srv { impl Service for Srv {
type Request = (); type Request = ();
type Response = (); type Response = ();
type Error = (); type Error = ();
type Future = FutureResult<(), ()>; type Future = Ready<Result<(), ()>>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(
Ok(Async::Ready(())) self: Pin<&mut Self>,
ctx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
} }
fn call(&mut self, _: ()) -> Self::Future { fn call(&mut self, _: ()) -> Self::Future {
@ -210,32 +228,28 @@ mod tests {
} }
} }
#[test] #[tokio::test]
fn test_poll_ready() { async fn test_poll_ready() {
let mut srv = Srv.map(|_| "ok"); let mut srv = Srv.map(|_| "ok");
let res = srv.poll_ready(); let res = srv.poll_once().await;
assert!(res.is_ok()); assert_eq!(res, Poll::Ready(Ok(())));
assert_eq!(res.unwrap(), Async::Ready(()));
} }
#[test] #[tokio::test]
fn test_call() { async fn test_call() {
let mut srv = Srv.map(|_| "ok"); let mut srv = Srv.map(|_| "ok");
let res = srv.call(()).poll(); let res = srv.call(()).await;
assert!(res.is_ok()); assert!(res.is_ok());
assert_eq!(res.unwrap(), Async::Ready("ok")); assert_eq!(res.unwrap(), "ok");
} }
#[test] #[tokio::test]
fn test_new_service() { async fn test_new_service() {
let blank = || Ok::<_, ()>(Srv); let blank = || ok::<_, ()>(Srv);
let new_srv = blank.into_new_service().map(|_| "ok"); let new_srv = blank.into_new_service().map(|_| "ok");
if let Async::Ready(mut srv) = new_srv.new_service(&()).poll().unwrap() { let mut srv = new_srv.new_service(&()).await.unwrap();
let res = srv.call(()).poll(); let res = srv.call(()).await;
assert!(res.is_ok()); assert!(res.is_ok());
assert_eq!(res.unwrap(), Async::Ready("ok")); assert_eq!(res.unwrap(), ("ok"));
} else {
panic!()
}
} }
} }

View File

@ -1,14 +1,20 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use futures::{Async, Future, Poll}; use futures::{Future, Poll};
use super::{NewService, Service}; use super::{NewService, Service};
use pin_project::pin_project;
use std::pin::Pin;
use std::task::Context;
/// Service for the `map_err` combinator, changing the type of a service's /// Service for the `map_err` combinator, changing the type of a service's
/// error. /// error.
/// ///
/// This is created by the `ServiceExt::map_err` method. /// This is created by the `ServiceExt::map_err` method.
#[pin_project]
pub struct MapErr<A, F, E> { pub struct MapErr<A, F, E> {
#[pin]
service: A, service: A,
f: F, f: F,
_t: PhantomData<E>, _t: PhantomData<E>,
@ -53,8 +59,12 @@ where
type Error = E; type Error = E;
type Future = MapErrFuture<A, F, E>; type Future = MapErrFuture<A, F, E>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(
self.service.poll_ready().map_err(&self.f) mut self: Pin<&mut Self>,
ctx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>> {
let mut this = self.project();
this.service.poll_ready(ctx).map_err(this.f)
} }
fn call(&mut self, req: A::Request) -> Self::Future { fn call(&mut self, req: A::Request) -> Self::Future {
@ -62,12 +72,14 @@ where
} }
} }
#[pin_project]
pub struct MapErrFuture<A, F, E> pub struct MapErrFuture<A, F, E>
where where
A: Service, A: Service,
F: Fn(A::Error) -> E, F: Fn(A::Error) -> E,
{ {
f: F, f: F,
#[pin]
fut: A::Future, fut: A::Future,
} }
@ -86,11 +98,11 @@ where
A: Service, A: Service,
F: Fn(A::Error) -> E, F: Fn(A::Error) -> E,
{ {
type Item = A::Response; type Output = Result<A::Response, E>;
type Error = E;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.fut.poll().map_err(&self.f) let mut this = self.project();
this.fut.poll(cx).map_err(this.f)
} }
} }
@ -156,11 +168,13 @@ where
} }
} }
#[pin_project]
pub struct MapErrNewServiceFuture<A, F, E> pub struct MapErrNewServiceFuture<A, F, E>
where where
A: NewService, A: NewService,
F: Fn(A::Error) -> E, F: Fn(A::Error) -> E,
{ {
#[pin]
fut: A::Future, fut: A::Future,
f: F, f: F,
} }
@ -180,24 +194,25 @@ where
A: NewService, A: NewService,
F: Fn(A::Error) -> E + Clone, F: Fn(A::Error) -> E + Clone,
{ {
type Item = MapErr<A::Service, F, E>; type Output = Result<MapErr<A::Service, F, E>, A::InitError>;
type Error = A::InitError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if let Async::Ready(service) = self.fut.poll()? { let this = self.project();
Ok(Async::Ready(MapErr::new(service, self.f.clone()))) if let Poll::Ready(svc) = this.fut.poll(cx)? {
Poll::Ready(Ok(MapErr::new(svc, this.f.clone())))
} else { } else {
Ok(Async::NotReady) Poll::Pending
} }
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use futures::future::{err, FutureResult}; use futures::future::{err, Ready};
use super::*; use super::*;
use crate::{IntoNewService, NewService, Service, ServiceExt}; use crate::{IntoNewService, NewService, Service, ServiceExt};
use tokio::future::ok;
struct Srv; struct Srv;
@ -205,10 +220,13 @@ mod tests {
type Request = (); type Request = ();
type Response = (); type Response = ();
type Error = (); type Error = ();
type Future = FutureResult<(), ()>; type Future = Ready<Result<(), ()>>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(
Err(()) self: Pin<&mut Self>,
ctx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Err(()))
} }
fn call(&mut self, _: ()) -> Self::Future { fn call(&mut self, _: ()) -> Self::Future {
@ -216,32 +234,33 @@ mod tests {
} }
} }
#[test] #[tokio::test]
fn test_poll_ready() { async fn test_poll_ready() {
let mut srv = Srv.map_err(|_| "error"); let mut srv = Srv.map_err(|_| "error");
let res = srv.poll_ready(); let res = srv.poll_once().await;
assert!(res.is_err()); if let Poll::Ready(res) = res {
assert_eq!(res.err().unwrap(), "error");
}
#[test]
fn test_call() {
let mut srv = Srv.map_err(|_| "error");
let res = srv.call(()).poll();
assert!(res.is_err());
assert_eq!(res.err().unwrap(), "error");
}
#[test]
fn test_new_service() {
let blank = || Ok::<_, ()>(Srv);
let new_srv = blank.into_new_service().map_err(|_| "error");
if let Async::Ready(mut srv) = new_srv.new_service(&()).poll().unwrap() {
let res = srv.call(()).poll();
assert!(res.is_err()); assert!(res.is_err());
assert_eq!(res.err().unwrap(), "error"); assert_eq!(res.err().unwrap(), "error");
} else { } else {
panic!() panic!("Should be ready");
} }
} }
#[tokio::test]
async fn test_call() {
let mut srv = Srv.map_err(|_| "error");
let res = srv.call(()).await;
assert!(res.is_err());
assert_eq!(res.err().unwrap(), "error");
}
#[tokio::test]
async fn test_new_service() {
let blank = || ok::<_, ()>(Srv);
let new_srv = blank.into_new_service().map_err(|_| "error");
let mut srv = new_srv.new_service(&()).await.unwrap();
let res = srv.call(()).await;
assert!(res.is_err());
assert_eq!(res.err().unwrap(), "error");
}
} }

View File

@ -4,6 +4,10 @@ use futures::{Future, Poll};
use super::NewService; use super::NewService;
use pin_project::pin_project;
use std::pin::Pin;
use std::task::Context;
/// `MapInitErr` service combinator /// `MapInitErr` service combinator
pub struct MapInitErr<A, F, E> { pub struct MapInitErr<A, F, E> {
a: A, a: A,
@ -58,13 +62,14 @@ where
MapInitErrFuture::new(self.a.new_service(cfg), self.f.clone()) MapInitErrFuture::new(self.a.new_service(cfg), self.f.clone())
} }
} }
#[pin_project]
pub struct MapInitErrFuture<A, F, E> pub struct MapInitErrFuture<A, F, E>
where where
A: NewService, A: NewService,
F: Fn(A::InitError) -> E, F: Fn(A::InitError) -> E,
{ {
f: F, f: F,
#[pin]
fut: A::Future, fut: A::Future,
} }
@ -83,10 +88,10 @@ where
A: NewService, A: NewService,
F: Fn(A::InitError) -> E, F: Fn(A::InitError) -> E,
{ {
type Item = A::Service; type Output = Result<A::Service, E>;
type Error = E;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.fut.poll().map_err(&self.f) let mut this = self.project();
this.fut.poll(cx).map_err(this.f)
} }
} }

View File

@ -1,14 +1,21 @@
use futures::{Async, Future, Poll}; use futures::{Future, Poll};
use std::pin::Pin;
use std::task::Context;
use super::{IntoNewService, NewService, Service}; use super::{IntoNewService, NewService, Service};
use crate::cell::Cell; use crate::cell::Cell;
use pin_project::pin_project;
/// Service for the `then` combinator, chaining a computation onto the end of /// Service for the `then` combinator, chaining a computation onto the end of
/// another service. /// another service.
/// ///
/// This is created by the `ServiceExt::then` method. /// This is created by the `ServiceExt::then` method.
#[pin_project]
pub struct Then<A, B> { pub struct Then<A, B> {
#[pin]
a: A, a: A,
#[pin]
b: Cell<B>, b: Cell<B>,
} }
@ -45,12 +52,16 @@ where
type Error = B::Error; type Error = B::Error;
type Future = ThenFuture<A, B>; type Future = ThenFuture<A, B>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(
let not_ready = self.a.poll_ready()?.is_not_ready(); self: Pin<&mut Self>,
if self.b.get_mut().poll_ready()?.is_not_ready() || not_ready { ctx: &mut Context<'_>,
Ok(Async::NotReady) ) -> Poll<Result<(), Self::Error>> {
let this = self.project();
let not_ready = !this.a.poll_ready(ctx)?.is_ready();
if !this.b.get_pin().poll_ready(ctx)?.is_ready() || not_ready {
Poll::Pending
} else { } else {
Ok(Async::Ready(())) Poll::Ready(Ok(()))
} }
} }
@ -59,13 +70,16 @@ where
} }
} }
#[pin_project]
pub struct ThenFuture<A, B> pub struct ThenFuture<A, B>
where where
A: Service, A: Service,
B: Service<Request = Result<A::Response, A::Error>>, B: Service<Request = Result<A::Response, A::Error>>,
{ {
b: Cell<B>, b: Cell<B>,
#[pin]
fut_b: Option<B::Future>, fut_b: Option<B::Future>,
#[pin]
fut_a: Option<A::Future>, fut_a: Option<A::Future>,
} }
@ -88,26 +102,33 @@ where
A: Service, A: Service,
B: Service<Request = Result<A::Response, A::Error>>, B: Service<Request = Result<A::Response, A::Error>>,
{ {
type Item = B::Response; type Output = Result<B::Response, B::Error>;
type Error = B::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if let Some(ref mut fut) = self.fut_b { let mut this = self.project();
return fut.poll();
}
match self.fut_a.as_mut().expect("bug in actix-service").poll() { loop {
Ok(Async::Ready(resp)) => { let mut fut_a = this.fut_a.as_mut();
let _ = self.fut_a.take(); let mut fut_b = this.fut_b.as_mut();
self.fut_b = Some(self.b.get_mut().call(Ok(resp)));
self.poll() if let Some(fut) = fut_b.as_mut().as_pin_mut() {
return fut.poll(cx);
} }
Err(err) => {
let _ = self.fut_a.take(); match fut_a
self.fut_b = Some(self.b.get_mut().call(Err(err))); .as_mut()
self.poll() .as_pin_mut()
.expect("Bug in actix-service")
.poll(cx)
{
Poll::Ready(r) => {
fut_a.set(None);
let new_fut = this.b.get_mut().call(r);
fut_b.set(Some(new_fut));
}
Poll::Pending => return Poll::Pending,
} }
Ok(Async::NotReady) => Ok(Async::NotReady),
} }
} }
} }
@ -175,6 +196,7 @@ where
} }
} }
#[pin_project]
pub struct ThenNewServiceFuture<A, B> pub struct ThenNewServiceFuture<A, B>
where where
A: NewService, A: NewService,
@ -185,7 +207,9 @@ where
InitError = A::InitError, InitError = A::InitError,
>, >,
{ {
#[pin]
fut_b: B::Future, fut_b: B::Future,
#[pin]
fut_a: A::Future, fut_a: A::Future,
a: Option<A::Service>, a: Option<A::Service>,
b: Option<B::Service>, b: Option<B::Service>,
@ -221,53 +245,59 @@ where
InitError = A::InitError, InitError = A::InitError,
>, >,
{ {
type Item = Then<A::Service, B::Service>; type Output = Result<Then<A::Service, B::Service>, A::InitError>;
type Error = A::InitError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.a.is_none() { let this = self.project();
if let Async::Ready(service) = self.fut_a.poll()? { if this.a.is_none() {
self.a = Some(service); if let Poll::Ready(service) = this.fut_a.poll(cx)? {
*this.a = Some(service);
} }
} }
if this.b.is_none() {
if self.b.is_none() { if let Poll::Ready(service) = this.fut_b.poll(cx)? {
if let Async::Ready(service) = self.fut_b.poll()? { *this.b = Some(service);
self.b = Some(service);
} }
} }
if this.a.is_some() && this.b.is_some() {
if self.a.is_some() && self.b.is_some() { Poll::Ready(Ok(Then::new(
Ok(Async::Ready(Then::new( this.a.take().unwrap(),
self.a.take().unwrap(), this.b.take().unwrap(),
self.b.take().unwrap(),
))) )))
} else { } else {
Ok(Async::NotReady) Poll::Pending
} }
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use futures::future::{err, ok, FutureResult}; use futures::future::{err, ok, ready, Ready};
use futures::{Async, Future, Poll}; use futures::{Future, Poll};
use std::cell::Cell; use std::cell::Cell;
use std::rc::Rc; use std::rc::Rc;
use crate::{IntoNewService, NewService, Service, ServiceExt}; use crate::{IntoNewService, NewService, Service, ServiceExt};
use std::pin::Pin;
use std::task::Context;
#[derive(Clone)] #[derive(Clone)]
struct Srv1(Rc<Cell<usize>>); struct Srv1(Rc<Cell<usize>>);
impl Service for Srv1 { impl Service for Srv1 {
type Request = Result<&'static str, &'static str>; type Request = Result<&'static str, &'static str>;
type Response = &'static str; type Response = &'static str;
type Error = (); type Error = ();
type Future = FutureResult<Self::Response, Self::Error>; type Future = Ready<Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(
self.0.set(self.0.get() + 1); self: Pin<&mut Self>,
Ok(Async::Ready(())) ctx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>> {
let mut this = self.get_mut();
this.0.set(this.0.get() + 1);
Poll::Ready(Ok(()))
} }
fn call(&mut self, req: Result<&'static str, &'static str>) -> Self::Future { fn call(&mut self, req: Result<&'static str, &'static str>) -> Self::Future {
@ -284,11 +314,15 @@ mod tests {
type Request = Result<&'static str, ()>; type Request = Result<&'static str, ()>;
type Response = (&'static str, &'static str); type Response = (&'static str, &'static str);
type Error = (); type Error = ();
type Future = FutureResult<Self::Response, ()>; type Future = Ready<Result<Self::Response, ()>>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(
self.0.set(self.0.get() + 1); self: Pin<&mut Self>,
Ok(Async::Ready(())) ctx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>> {
let mut this = self.get_mut();
this.0.set(this.0.get() + 1);
Poll::Ready(Err(()))
} }
fn call(&mut self, req: Result<&'static str, ()>) -> Self::Future { fn call(&mut self, req: Result<&'static str, ()>) -> Self::Future {
@ -299,46 +333,44 @@ mod tests {
} }
} }
#[test] #[tokio::test]
fn test_poll_ready() { async fn test_poll_ready() {
let cnt = Rc::new(Cell::new(0)); let cnt = Rc::new(Cell::new(0));
let mut srv = Srv1(cnt.clone()).then(Srv2(cnt.clone())); let mut srv = Srv1(cnt.clone()).then(Srv2(cnt.clone()));
let res = srv.poll_ready(); let res = srv.poll_once().await;
assert!(res.is_ok()); assert_eq!(res, Poll::Ready(Err(())));
assert_eq!(res.unwrap(), Async::Ready(()));
assert_eq!(cnt.get(), 2); assert_eq!(cnt.get(), 2);
} }
#[test] #[tokio::test]
fn test_call() { async fn test_call() {
let cnt = Rc::new(Cell::new(0)); let cnt = Rc::new(Cell::new(0));
let mut srv = Srv1(cnt.clone()).then(Srv2(cnt)).clone(); let mut srv = Srv1(cnt.clone()).then(Srv2(cnt)).clone();
let res = srv.call(Ok("srv1")).poll(); let res = srv.call(Ok("srv1")).await;
assert!(res.is_ok()); assert!(res.is_ok());
assert_eq!(res.unwrap(), Async::Ready(("srv1", "ok"))); assert_eq!(res.unwrap(), (("srv1", "ok")));
let res = srv.call(Err("srv")).poll(); let res = srv.call(Err("srv")).await;
assert!(res.is_ok()); assert!(res.is_ok());
assert_eq!(res.unwrap(), Async::Ready(("srv2", "err"))); assert_eq!(res.unwrap(), (("srv2", "err")));
} }
#[test] #[tokio::test]
fn test_new_service() { async fn test_new_service() {
let cnt = Rc::new(Cell::new(0)); let cnt = Rc::new(Cell::new(0));
let cnt2 = cnt.clone(); let cnt2 = cnt.clone();
let blank = move || Ok::<_, ()>(Srv1(cnt2.clone())); let blank = move || ready(Ok::<_, ()>(Srv1(cnt2.clone())));
let new_srv = blank.into_new_service().then(move || Ok(Srv2(cnt.clone()))); let new_srv = blank
if let Async::Ready(mut srv) = new_srv.clone().new_service(&()).poll().unwrap() { .into_new_service()
let res = srv.call(Ok("srv1")).poll(); .then(move || ready(Ok(Srv2(cnt.clone()))));
assert!(res.is_ok()); let mut srv = new_srv.clone().new_service(&()).await.unwrap();
assert_eq!(res.unwrap(), Async::Ready(("srv1", "ok"))); let res = srv.call(Ok("srv1")).await;
assert!(res.is_ok());
assert_eq!(res.unwrap(), (("srv1", "ok")));
let res = srv.call(Err("srv")).poll(); let res = srv.call(Err("srv")).await;
assert!(res.is_ok()); assert!(res.is_ok());
assert_eq!(res.unwrap(), Async::Ready(("srv2", "err"))); assert_eq!(res.unwrap(), (("srv2", "err")));
} else {
panic!()
}
} }
} }

View File

@ -1,10 +1,13 @@
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use futures::{Async, Future, IntoFuture, Poll};
use crate::transform_err::{TransformFromErr, TransformMapInitErr}; use crate::transform_err::{TransformFromErr, TransformMapInitErr};
use crate::{IntoNewService, NewService, Service}; use crate::{IntoNewService, NewService, Service};
use futures::{Future, Poll};
use std::pin::Pin;
use std::task::Context;
use pin_project::pin_project;
/// The `Transform` trait defines the interface of a Service factory. `Transform` /// The `Transform` trait defines the interface of a Service factory. `Transform`
/// is often implemented for middleware, defining how to construct a /// is often implemented for middleware, defining how to construct a
@ -32,7 +35,7 @@ pub trait Transform<S> {
type InitError; type InitError;
/// The future response value. /// The future response value.
type Future: Future<Item = Self::Transform, Error = Self::InitError>; type Future: Future<Output = Result<Self::Transform, Self::InitError>>;
/// Creates and returns a new Service component, asynchronously /// Creates and returns a new Service component, asynchronously
fn new_transform(&self, service: S) -> Self::Future; fn new_transform(&self, service: S) -> Self::Future;
@ -193,19 +196,21 @@ where
fn new_service(&self, cfg: &S::Config) -> Self::Future { fn new_service(&self, cfg: &S::Config) -> Self::Future {
ApplyTransformFuture { ApplyTransformFuture {
t_cell: self.t.clone(), t_cell: self.t.clone(),
fut_a: self.s.new_service(cfg).into_future(), fut_a: self.s.new_service(cfg),
fut_t: None, fut_t: None,
} }
} }
} }
#[pin_project]
pub struct ApplyTransformFuture<T, S> pub struct ApplyTransformFuture<T, S>
where where
S: NewService, S: NewService,
T: Transform<S::Service, InitError = S::InitError>, T: Transform<S::Service, InitError = S::InitError>,
{ {
#[pin]
fut_a: S::Future, fut_a: S::Future,
fut_t: Option<<T::Future as IntoFuture>::Future>, #[pin]
fut_t: Option<T::Future>,
t_cell: Rc<T>, t_cell: Rc<T>,
} }
@ -214,19 +219,21 @@ where
S: NewService, S: NewService,
T: Transform<S::Service, InitError = S::InitError>, T: Transform<S::Service, InitError = S::InitError>,
{ {
type Item = T::Transform; type Output = Result<T::Transform, T::InitError>;
type Error = T::InitError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.fut_t.is_none() { let mut this = self.project();
if let Async::Ready(service) = self.fut_a.poll()? {
self.fut_t = Some(self.t_cell.new_transform(service).into_future()); if this.fut_t.as_mut().as_pin_mut().is_none() {
if let Poll::Ready(service) = this.fut_a.poll(cx)? {
this.fut_t.set(Some(this.t_cell.new_transform(service)));
} }
} }
if let Some(ref mut fut) = self.fut_t {
fut.poll() if let Some(fut) = this.fut_t.as_mut().as_pin_mut() {
fut.poll(cx)
} else { } else {
Ok(Async::NotReady) Poll::Pending
} }
} }
} }

View File

@ -3,6 +3,10 @@ use std::marker::PhantomData;
use futures::{Future, Poll}; use futures::{Future, Poll};
use super::Transform; use super::Transform;
use std::pin::Pin;
use std::task::Context;
use pin_project::pin_project;
/// Transform for the `map_err` combinator, changing the type of a new /// Transform for the `map_err` combinator, changing the type of a new
/// transform's init error. /// transform's init error.
@ -63,12 +67,13 @@ where
} }
} }
} }
#[pin_project]
pub struct TransformMapInitErrFuture<T, S, F, E> pub struct TransformMapInitErrFuture<T, S, F, E>
where where
T: Transform<S>, T: Transform<S>,
F: Fn(T::InitError) -> E, F: Fn(T::InitError) -> E,
{ {
#[pin]
fut: T::Future, fut: T::Future,
f: F, f: F,
} }
@ -78,11 +83,11 @@ where
T: Transform<S>, T: Transform<S>,
F: Fn(T::InitError) -> E + Clone, F: Fn(T::InitError) -> E + Clone,
{ {
type Item = T::Transform; type Output = Result<T::Transform, E>;
type Error = E;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.fut.poll().map_err(&self.f) let this = self.project();
this.fut.poll(cx).map_err(this.f)
} }
} }
@ -139,11 +144,13 @@ where
} }
} }
#[pin_project]
pub struct TransformFromErrFuture<T, S, E> pub struct TransformFromErrFuture<T, S, E>
where where
T: Transform<S>, T: Transform<S>,
E: From<T::InitError>, E: From<T::InitError>,
{ {
#[pin]
fut: T::Future, fut: T::Future,
_t: PhantomData<E>, _t: PhantomData<E>,
} }
@ -153,10 +160,9 @@ where
T: Transform<S>, T: Transform<S>,
E: From<T::InitError>, E: From<T::InitError>,
{ {
type Item = T::Transform; type Output = Result<T::Transform, E>;
type Error = E;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.fut.poll().map_err(E::from) self.project().fut.poll(cx).map_err(E::from)
} }
} }

View File

@ -19,7 +19,7 @@ path = "src/lib.rs"
[dependencies] [dependencies]
actix-rt = "0.2.1" actix-rt = "0.2.1"
actix-server = "0.5.0" actix-server = "0.5.0"
actix-server-config = "0.1.0" actix-server-config = "0.2.0"
actix-testing = "0.1.0" actix-testing = "0.1.0"
log = "0.4" log = "0.4"

View File

@ -1,5 +1,10 @@
# Changes # Changes
## [0.2.0] - 2019-10-14
* Upgrade actix-server and actix-server-config deps
## [0.1.0] - 2019-09-25 ## [0.1.0] - 2019-09-25
* Initial impl * Initial impl

View File

@ -1,6 +1,6 @@
[package] [package]
name = "actix-testing" name = "actix-testing"
version = "0.1.0" version = "0.2.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"] authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix testing utils" description = "Actix testing utils"
keywords = ["network", "framework", "async", "futures"] keywords = ["network", "framework", "async", "futures"]
@ -17,10 +17,10 @@ name = "actix_testing"
path = "src/lib.rs" path = "src/lib.rs"
[dependencies] [dependencies]
actix-rt = "0.2.1" actix-rt = "0.2.5"
actix-server = "0.6.0" actix-server = "0.7.0"
actix-server-config = "0.1.0" actix-server-config = "0.2.0"
actix-service = "0.4.0" actix-service = "0.4.2"
log = "0.4" log = "0.4"
net2 = "0.2" net2 = "0.2"

View File

@ -1,5 +1,11 @@
# Changes # Changes
## [0.2.0] - 2019-??-??
### Changed
* Migrate to `std::future`
## [0.1.2] - 2019-08-05 ## [0.1.2] - 2019-08-05
### Changed ### Changed

View File

@ -1,6 +1,6 @@
[package] [package]
name = "actix-threadpool" name = "actix-threadpool"
version = "0.1.2" version = "0.2.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"] authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix thread pool for sync code" description = "Actix thread pool for sync code"
keywords = ["actix", "network", "framework", "async", "futures"] keywords = ["actix", "network", "framework", "async", "futures"]
@ -19,7 +19,7 @@ path = "src/lib.rs"
[dependencies] [dependencies]
derive_more = "0.15" derive_more = "0.15"
futures = "0.1.25" futures = "0.3.1"
parking_lot = "0.9" parking_lot = "0.9"
lazy_static = "1.2" lazy_static = "1.2"
log = "0.4" log = "0.4"

View File

@ -1,33 +1,34 @@
//! Thread pool for blocking operations //! Thread pool for blocking operations
use std::fmt; use std::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
use derive_more::Display; use derive_more::Display;
use futures::sync::oneshot; use futures::channel::oneshot;
use futures::{Async, Future, Poll};
use parking_lot::Mutex; use parking_lot::Mutex;
use threadpool::ThreadPool; use threadpool::ThreadPool;
/// Env variable for default cpu pool size /// Env variable for default cpu pool size.
const ENV_CPU_POOL_VAR: &str = "ACTIX_THREADPOOL"; const ENV_CPU_POOL_VAR: &str = "ACTIX_THREADPOOL";
lazy_static::lazy_static! { lazy_static::lazy_static! {
pub(crate) static ref DEFAULT_POOL: Mutex<ThreadPool> = { pub(crate) static ref DEFAULT_POOL: Mutex<ThreadPool> = {
let default = match std::env::var(ENV_CPU_POOL_VAR) { let num = std::env::var(ENV_CPU_POOL_VAR)
Ok(val) => { .map_err(|_| ())
if let Ok(val) = val.parse() { .and_then(|val| {
val val.parse().map_err(|_| log::warn!(
} else { "Can not parse {} value, using default",
log::error!("Can not parse ACTIX_THREADPOOL value"); ENV_CPU_POOL_VAR,
num_cpus::get() * 5 ))
} })
} .unwrap_or_else(|_| num_cpus::get() * 5);
Err(_) => num_cpus::get() * 5,
};
Mutex::new( Mutex::new(
threadpool::Builder::new() threadpool::Builder::new()
.thread_name("actix-web".to_owned()) .thread_name("actix-web".to_owned())
.num_threads(default) .num_threads(num)
.build(), .build(),
) )
}; };
@ -39,22 +40,17 @@ thread_local! {
}; };
} }
/// Blocking operation execution error /// Error of blocking operation execution being cancelled.
#[derive(Debug, Display)] #[derive(Clone, Copy, Debug, Display)]
pub enum BlockingError<E: fmt::Debug> { #[display(fmt = "Thread pool is gone")]
#[display(fmt = "{:?}", _0)] pub struct Cancelled;
Error(E),
#[display(fmt = "Thread pool is gone")]
Canceled,
}
/// Execute blocking function on a thread pool, returns future that resolves /// Execute blocking function on a thread pool, returns future that resolves
/// to result of the function execution. /// to result of the function execution.
pub fn run<F, I, E>(f: F) -> CpuFuture<I, E> pub fn run<F, I>(f: F) -> CpuFuture<I>
where where
F: FnOnce() -> Result<I, E> + Send + 'static, F: FnOnce() -> I + Send + 'static,
I: Send + 'static, I: Send + 'static,
E: Send + fmt::Debug + 'static,
{ {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
POOL.with(|pool| { POOL.with(|pool| {
@ -70,19 +66,16 @@ where
/// Blocking operation completion future. It resolves with results /// Blocking operation completion future. It resolves with results
/// of blocking function execution. /// of blocking function execution.
pub struct CpuFuture<I, E> { pub struct CpuFuture<I> {
rx: oneshot::Receiver<Result<I, E>>, rx: oneshot::Receiver<I>,
} }
impl<I, E: fmt::Debug> Future for CpuFuture<I, E> { impl<I> Future for CpuFuture<I> {
type Item = I; type Output = Result<I, Cancelled>;
type Error = BlockingError<E>;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let res = futures::try_ready!(self.rx.poll().map_err(|_| BlockingError::Canceled)); let rx = Pin::new(&mut Pin::get_mut(self).rx);
match res { let res = futures::ready!(rx.poll(cx));
Ok(val) => Ok(Async::Ready(val)), Poll::Ready(res.map_err(|_| Cancelled))
Err(err) => Err(BlockingError::Error(err)),
}
} }
} }

View File

@ -1,5 +1,15 @@
# Changes # Changes
## [0.4.7] - 2019-10-14
* Re-register task on every framed transport poll.
## [0.4.6] - 2019-10-08
* Refactor `Counter` type. register current task in available method.
## [0.4.5] - 2019-07-19 ## [0.4.5] - 2019-07-19
### Removed ### Removed

View File

@ -1,6 +1,6 @@
[package] [package]
name = "actix-utils" name = "actix-utils"
version = "0.4.5" version = "0.4.7"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"] authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix utils - various actix net related services" description = "Actix utils - various actix net related services"
keywords = ["network", "framework", "async", "futures"] keywords = ["network", "framework", "async", "futures"]

View File

@ -25,11 +25,13 @@ impl Counter {
})) }))
} }
/// Get counter guard.
pub fn get(&self) -> CounterGuard { pub fn get(&self) -> CounterGuard {
CounterGuard::new(self.0.clone()) CounterGuard::new(self.0.clone())
} }
/// Check if counter is not at capacity /// Check if counter is not at capacity. If counter at capacity
/// it registers notification for current task.
pub fn available(&self) -> bool { pub fn available(&self) -> bool {
self.0.available() self.0.available()
} }
@ -57,11 +59,7 @@ impl Drop for CounterGuard {
impl CounterInner { impl CounterInner {
fn inc(&self) { fn inc(&self) {
let num = self.count.get() + 1; self.count.set(self.count.get() + 1);
self.count.set(num);
if num == self.capacity {
self.task.register();
}
} }
fn dec(&self) { fn dec(&self) {
@ -73,6 +71,11 @@ impl CounterInner {
} }
fn available(&self) -> bool { fn available(&self) -> bool {
self.count.get() < self.capacity if self.count.get() < self.capacity {
true
} else {
self.task.register();
false
}
} }
} }

View File

@ -129,7 +129,6 @@ where
}; };
let mut cell = self.inner.clone(); let mut cell = self.inner.clone();
cell.get_mut().task.register();
tokio_current_thread::spawn(self.service.call(item).then(move |item| { tokio_current_thread::spawn(self.service.call(item).then(move |item| {
let inner = cell.get_mut(); let inner = cell.get_mut();
inner.buf.push_back(item); inner.buf.push_back(item);
@ -293,6 +292,8 @@ where
type Error = FramedTransportError<S::Error, U>; type Error = FramedTransportError<S::Error, U>;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
self.inner.get_ref().task.register();
match mem::replace(&mut self.state, TransportState::Processing) { match mem::replace(&mut self.state, TransportState::Processing) {
TransportState::Processing => { TransportState::Processing => {
if self.poll_read() || self.poll_write() { if self.poll_read() || self.poll_write() {

View File

@ -195,7 +195,7 @@ fn from_hex(v: u8) -> Option<u8> {
#[inline] #[inline]
fn restore_ch(d1: u8, d2: u8) -> Option<u8> { fn restore_ch(d1: u8, d2: u8) -> Option<u8> {
from_hex(d1).and_then(|d1| from_hex(d2).and_then(move |d2| Some(d1 << 4 | d2))) from_hex(d1).and_then(|d1| from_hex(d2).map(move |d2| d1 << 4 | d2))
} }
#[cfg(test)] #[cfg(test)]