1
0
mirror of https://github.com/fafhrd91/actix-net synced 2025-08-14 23:50:32 +02:00

Compare commits

...

45 Commits

Author SHA1 Message Date
Nikolay Kim
ae9bc5ae78 refactor ApplyConfig combinator 2019-03-12 16:32:10 -07:00
Nikolay Kim
21c289d7e4 fix InOrderService::poll_ready() nested service rediness check 2019-03-12 16:03:05 -07:00
Nikolay Kim
5e6eed905c fix InFlightService::poll_ready() nested service rediness check 2019-03-12 15:48:02 -07:00
Nikolay Kim
6801a38de5 check readiness for all services 2019-03-12 15:15:14 -07:00
Nikolay Kim
39356690b0 use ServerConfig for system configuration 2019-03-12 14:14:21 -07:00
Nikolay Kim
f6f292a678 enforce constraint on OpensslAcceptor 2019-03-12 13:57:28 -07:00
Nikolay Kim
b3366bc1af service response is not important 2019-03-12 13:55:31 -07:00
Nikolay Kim
2c1f8f0b96 enforce constraints on AndThenNewService type 2019-03-12 13:50:14 -07:00
Nikolay Kim
e7465bfa2e fix map_err constraints 2019-03-12 13:45:05 -07:00
Nikolay Kim
755d4958c5 use IntoService types for transform services 2019-03-12 13:39:04 -07:00
Nikolay Kim
825117fd4c add Deref/DerefMut impls for Io 2019-03-12 13:12:22 -07:00
Nikolay Kim
7033b50fed add Io::set method for overriding param 2019-03-12 12:53:43 -07:00
Nikolay Kim
ef9bfb8981 add helpers 2019-03-12 12:53:08 -07:00
Nikolay Kim
bef199f831 add blocking mod support 2019-03-11 22:54:27 -07:00
Nikolay Kim
f1d4bcef4b add Arbiter::exec_fn and exec functions 2019-03-11 22:51:17 -07:00
Nikolay Kim
8e13ba7bce update readme 2019-03-11 18:24:31 -07:00
Nikolay Kim
9a9b3e9ca9 update server tests 2019-03-11 15:19:28 -07:00
Nikolay Kim
5567fb41d2 add default type parameter 2019-03-11 13:48:55 -07:00
Nikolay Kim
ad50595ece add PartialEq impl for Io 2019-03-11 13:37:30 -07:00
Nikolay Kim
2430c7247b update timing for travis 2019-03-11 12:53:16 -07:00
Nikolay Kim
1bf0f1e1a5 add Debug impl for Io; update examples 2019-03-11 12:46:12 -07:00
Nikolay Kim
9887aef6e8 add delay to test 2019-03-11 12:35:57 -07:00
Nikolay Kim
787255d030 add io parameters 2019-03-11 12:01:55 -07:00
Nikolay Kim
f696914038 prepare router release 2019-03-09 14:38:08 -08:00
Nikolay Kim
3618f542fb prepare release actix-utils 2019-03-09 14:30:37 -08:00
Nikolay Kim
1f54ae9051 update deps 2019-03-09 14:23:08 -08:00
Nikolay Kim
86f57e5a4a prepare actix-service release 2019-03-09 14:10:02 -08:00
Nikolay Kim
43ad18ccb1 remove get_decoded 2019-03-09 13:58:07 -08:00
Nikolay Kim
34995a8ccf revert re-quoting change 2019-03-09 13:56:09 -08:00
Nikolay Kim
0ff300c40f export ApplyConfig 2019-03-09 09:05:51 -08:00
Nikolay Kim
629ef23371 add .apply_cfg new service combinator 2019-03-09 09:02:23 -08:00
Nikolay Kim
d2b96ff877 add ServerConfig to server services 2019-03-09 07:31:22 -08:00
Nikolay Kim
ac62e2dbf9 revert generic request in actix-utils 2019-03-09 07:27:35 -08:00
Nikolay Kim
6bbbdba921 revert generic Request change 2019-03-09 06:36:23 -08:00
Nikolay Kim
2099629fe3 cleanup ssl services 2019-03-08 22:41:30 -08:00
Nikolay Kim
a4d4770462 remove server config 2019-03-08 22:38:39 -08:00
Nikolay Kim
70ead175b9 IntoService for fn_cfg_factory 2019-03-08 20:51:50 -08:00
Nikolay Kim
49867b5e9d fix IntoService 2019-03-08 20:50:29 -08:00
Nikolay Kim
0f064c43e9 remove uneeded code 2019-03-08 20:10:47 -08:00
Nikolay Kim
7db29544f9 add ServerConfig param for server service 2019-03-08 19:43:13 -08:00
Nikolay Kim
4850cf41ff rename module 2019-03-08 16:26:30 -08:00
Nikolay Kim
046142ffbc added is_prefix_match and resource_path 2019-03-08 15:34:40 -08:00
Nikolay Kim
49e6dbcda2 remove unused ResourceMap 2019-03-08 12:33:44 -08:00
Nikolay Kim
877614a494 add params decoding 2019-03-08 04:43:51 -08:00
Nikolay Kim
ac0e8b9e53 re-enable examples 2019-03-06 23:33:35 -08:00
62 changed files with 2256 additions and 1273 deletions

View File

@@ -35,7 +35,7 @@ script:
cargo test --features="ssl,tls,rust-tls" -- --nocapture cargo test --features="ssl,tls,rust-tls" -- --nocapture
cd actix-codec && cargo test && cd .. cd actix-codec && cargo test && cd ..
cd actix-service && cargo test && cd .. cd actix-service && cargo test && cd ..
cd actix-server && cargo test --features="ssl,tls,rust-tls" -- --nocapture && cd .. cd actix-server && cargo test --all-features -- --nocapture && cd ..
cd actix-rt && cargo test && cd .. cd actix-rt && cargo test && cd ..
cd actix-connector && cargo test && cd .. cd actix-connector && cargo test && cd ..
cd actix-utils && cargo test && cd .. cd actix-utils && cargo test && cd ..

View File

@@ -1,3 +1,18 @@
[package]
name = "actix-net"
version = "0.3.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix net - framework for the compisible 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",
@@ -5,7 +20,19 @@ members = [
"actix-rt", "actix-rt",
"actix-service", "actix-service",
"actix-server", "actix-server",
"actix-server-config",
"actix-test-server", "actix-test-server",
"actix-utils", "actix-utils",
"router", "router",
] ]
[dev-dependencies]
actix-service = "0.3.3"
actix-codec = "0.1.1"
actix-rt = "0.2.0"
actix-server = { path="actix-server", features=["ssl"] }
env_logger = "0.6"
futures = "0.1.25"
openssl = "0.10"
tokio-tcp = "0.1"
tokio-openssl = "0.3"

View File

@@ -1,20 +1,18 @@
# Actix net [![Build Status](https://travis-ci.org/actix/actix-net.svg?branch=master)](https://travis-ci.org/actix/actix-net) [![codecov](https://codecov.io/gh/actix/actix-net/branch/master/graph/badge.svg)](https://codecov.io/gh/actix/actix-net) [![crates.io](https://meritbadge.herokuapp.com/actix-net)](https://crates.io/crates/actix-net) [![Join the chat at https://gitter.im/actix/actix](https://badges.gitter.im/actix/actix.svg)](https://gitter.im/actix/actix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) # Actix net [![Build Status](https://travis-ci.org/actix/actix-net.svg?branch=master)](https://travis-ci.org/actix/actix-net) [![codecov](https://codecov.io/gh/actix/actix-net/branch/master/graph/badge.svg)](https://codecov.io/gh/actix/actix-net) [![crates.io](https://meritbadge.herokuapp.com/actix-net)](https://crates.io/crates/actix-net) [![Join the chat at https://gitter.im/actix/actix](https://badges.gitter.im/actix/actix.svg)](https://gitter.im/actix/actix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
Actix net - framework for composable network services (experimental) Actix net - framework for composable network services
## Documentation & community resources ## Documentation & community resources
* [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.26 or later * Minimum supported Rust version: 1.32 or later
## Example ## Example
```rust ```rust
fn main() { fn main() -> io::Result<()> {
let sys = actix_rt::System::new("test");
// load ssl keys // load ssl keys
let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
builder.set_private_key_file("./examples/key.pem", SslFiletype::PEM).unwrap(); builder.set_private_key_file("./examples/key.pem", SslFiletype::PEM).unwrap();
@@ -26,7 +24,7 @@ fn main() {
// bind socket address and start workers. By default server uses number of // bind socket address and start workers. By default server uses number of
// available logical cpu as threads count. actix net start separate // available logical cpu as threads count. actix net start separate
// instances of service pipeline in each worker. // instances of service pipeline in each worker.
actix_server::build() Server::build()
.bind( .bind(
// configure service pipeline // configure service pipeline
"basic", "0.0.0.0:8443", "basic", "0.0.0.0:8443",
@@ -35,28 +33,23 @@ fn main() {
let acceptor = acceptor.clone(); let acceptor = acceptor.clone();
// service for converting incoming TcpStream to a SslStream<TcpStream> // service for converting incoming TcpStream to a SslStream<TcpStream>
(move |stream| { fn_service(move |stream: Io<tokio_tcp::TcpStream>| {
SslAcceptorExt::accept_async(&acceptor, stream) SslAcceptorExt::accept_async(&acceptor, stream.into_parts().0)
.map_err(|e| println!("Openssl error: {}", e)) .map_err(|e| println!("Openssl error: {}", e))
}) })
// convert closure to a `NewService` // .and_then() combinator uses other service to convert incoming `Request` to a
.into_new_service() // `Response` and then uses that response as an input for next
// service. in this case, on success we use `logger` service
// .and_then() combinator uses other service to convert incoming `Request` to a `Response` .and_then(fn_service(logger))
// and then uses that response as an input for next service. // Next service counts number of connections
// in this case, on success we use `logger` service .and_then(move |_| {
.and_then(logger) let num = num.fetch_add(1, Ordering::Relaxed);
println!("got ssl connection {:?}", num);
// Next service counts number of connections future::ok(())
.and_then(move |req| { })
let num = num.fetch_add(1, Ordering::Relaxed); },
println!("processed {:?} connections", num); )?
future::ok(()) .run()
})
}).unwrap()
.start();
sys.run();
} }
``` ```

View File

@@ -27,9 +27,8 @@ default = []
ssl = ["openssl", "tokio-openssl"] ssl = ["openssl", "tokio-openssl"]
[dependencies] [dependencies]
#actix-service = "0.3.0" actix-service = "0.3.3"
actix-service = { path="../actix-service" } actix-codec = "0.1.1"
actix-codec = "0.1.0"
futures = "0.1" futures = "0.1"
tokio-tcp = "0.1" tokio-tcp = "0.1"
tokio-current-thread = "0.1" tokio-current-thread = "0.1"

View File

@@ -167,8 +167,8 @@ impl Connector {
/// Create new connector with custom resolver /// Create new connector with custom resolver
pub fn with_resolver( pub fn with_resolver(
resolver: Resolver<Connect>, resolver: Resolver<Connect>,
) -> impl Service<Connect, Response = (Connect, TcpStream), Error = ConnectorError> + Clone ) -> impl Service<Request = Connect, Response = (Connect, TcpStream), Error = ConnectorError>
{ + Clone {
Connector { resolver } Connector { resolver }
} }
@@ -177,8 +177,8 @@ impl Connector {
cfg: ResolverConfig, cfg: ResolverConfig,
opts: ResolverOpts, opts: ResolverOpts,
) -> impl NewService< ) -> impl NewService<
Connect,
(), (),
Request = Connect,
Response = (Connect, TcpStream), Response = (Connect, TcpStream),
Error = ConnectorError, Error = ConnectorError,
InitError = E, InitError = E,
@@ -195,7 +195,8 @@ impl Clone for Connector {
} }
} }
impl Service<Connect> for Connector { impl Service for Connector {
type Request = Connect;
type Response = (Connect, TcpStream); type Response = (Connect, TcpStream);
type Error = ConnectorError; type Error = ConnectorError;
type Future = Either<ConnectorFuture, ConnectorTcpFuture>; type Future = Either<ConnectorFuture, ConnectorTcpFuture>;
@@ -272,7 +273,8 @@ impl<T: RequestPort> Default for TcpConnector<T> {
} }
} }
impl<T: RequestPort> Service<(T, VecDeque<IpAddr>)> for TcpConnector<T> { impl<T: RequestPort> Service for TcpConnector<T> {
type Request = (T, VecDeque<IpAddr>);
type Response = (T, TcpStream); type Response = (T, TcpStream);
type Error = io::Error; type Error = io::Error;
type Future = TcpConnectorResponse<T>; type Future = TcpConnectorResponse<T>;
@@ -352,7 +354,8 @@ impl DefaultConnector {
} }
} }
impl Service<Connect> for DefaultConnector { impl Service for DefaultConnector {
type Request = Connect;
type Response = TcpStream; type Response = TcpStream;
type Error = ConnectorError; type Error = ConnectorError;
type Future = DefaultConnectorFuture; type Future = DefaultConnectorFuture;

View File

@@ -67,7 +67,8 @@ impl<T> Clone for Resolver<T> {
} }
} }
impl<T: RequestHost> Service<T> for Resolver<T> { impl<T: RequestHost> Service for Resolver<T> {
type Request = T;
type Response = (T, VecDeque<IpAddr>); type Response = (T, VecDeque<IpAddr>);
type Error = ResolveError; type Error = ResolveError;
type Future = ResolverFuture<T>; type Future = ResolverFuture<T>;

View File

@@ -26,7 +26,8 @@ impl<R, T, E> OpensslConnector<R, T, E> {
impl<R: RequestHost, T: AsyncRead + AsyncWrite> OpensslConnector<R, T, ()> { impl<R: RequestHost, T: AsyncRead + AsyncWrite> OpensslConnector<R, T, ()> {
pub fn service( pub fn service(
connector: SslConnector, connector: SslConnector,
) -> impl Service<(R, T), Response = (R, SslStream<T>), Error = HandshakeError<T>> { ) -> impl Service<Request = (R, T), Response = (R, SslStream<T>), Error = HandshakeError<T>>
{
OpensslConnectorService { OpensslConnectorService {
connector: connector, connector: connector,
_t: PhantomData, _t: PhantomData,
@@ -43,9 +44,10 @@ impl<R, T, E> Clone for OpensslConnector<R, T, E> {
} }
} }
impl<R: RequestHost, T: AsyncRead + AsyncWrite, E> NewService<(R, T), ()> impl<R: RequestHost, T: AsyncRead + AsyncWrite, E> NewService<()>
for OpensslConnector<R, T, E> for OpensslConnector<R, T, E>
{ {
type Request = (R, T);
type Response = (R, SslStream<T>); type Response = (R, SslStream<T>);
type Error = HandshakeError<T>; type Error = HandshakeError<T>;
type Service = OpensslConnectorService<R, T>; type Service = OpensslConnectorService<R, T>;
@@ -65,9 +67,8 @@ pub struct OpensslConnectorService<R, T> {
_t: PhantomData<(R, T)>, _t: PhantomData<(R, T)>,
} }
impl<R: RequestHost, T: AsyncRead + AsyncWrite> Service<(R, T)> impl<R: RequestHost, T: AsyncRead + AsyncWrite> Service for OpensslConnectorService<R, T> {
for OpensslConnectorService<R, T> type Request = (R, T);
{
type Response = (R, SslStream<T>); type Response = (R, SslStream<T>);
type Error = HandshakeError<T>; type Error = HandshakeError<T>;
type Future = ConnectAsyncExt<R, T>; type Future = ConnectAsyncExt<R, T>;

View File

@@ -1,5 +1,15 @@
# Changes # Changes
## [0.2.1] - 2019-03-11
### Added
* Added `blocking` module
* Arbiter::exec_fn - execute fn on the arbiter's thread
* Arbiter::exec - execute fn on the arbiter's thread and wait result
## [0.2.0] - 2019-03-06 ## [0.2.0] - 2019-03-06
* `run` method returns `io::Result<()>` * `run` method returns `io::Result<()>`

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "actix-rt" name = "actix-rt"
version = "0.2.0" version = "0.2.1"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"] authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix runtime" description = "Actix runtime"
keywords = ["network", "framework", "async", "futures"] keywords = ["network", "framework", "async", "futures"]
@@ -18,9 +18,14 @@ name = "actix_rt"
path = "src/lib.rs" path = "src/lib.rs"
[dependencies] [dependencies]
log = "0.4"
bytes = "0.4" bytes = "0.4"
derive_more = "0.14"
futures = "0.1.25" futures = "0.1.25"
parking_lot = "0.7"
lazy_static = "1.2"
log = "0.4"
num_cpus = "1.10"
threadpool = "1.7"
tokio-current-thread = "0.1" tokio-current-thread = "0.1"
tokio-executor = "0.1.5" tokio-executor = "0.1.5"
tokio-reactor = "0.1.7" tokio-reactor = "0.1.7"

View File

@@ -4,7 +4,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
use std::{fmt, thread}; use std::{fmt, thread};
use futures::sync::mpsc::{unbounded, UnboundedReceiver, UnboundedSender}; use futures::sync::mpsc::{unbounded, UnboundedReceiver, UnboundedSender};
use futures::sync::oneshot::{channel, Sender}; use futures::sync::oneshot::{channel, Canceled, Sender};
use futures::{future, Async, Future, IntoFuture, Poll, Stream}; use futures::{future, Async, Future, IntoFuture, Poll, Stream};
use tokio_current_thread::spawn; use tokio_current_thread::spawn;
@@ -22,6 +22,7 @@ pub(crate) static COUNT: AtomicUsize = AtomicUsize::new(0);
pub(crate) enum ArbiterCommand { pub(crate) enum ArbiterCommand {
Stop, Stop,
Execute(Box<Future<Item = (), Error = ()> + Send>), Execute(Box<Future<Item = (), Error = ()> + Send>),
ExecuteFn(Box<FnExec>),
} }
impl fmt::Debug for ArbiterCommand { impl fmt::Debug for ArbiterCommand {
@@ -29,6 +30,7 @@ impl fmt::Debug for ArbiterCommand {
match self { match self {
ArbiterCommand::Stop => write!(f, "ArbiterCommand::Stop"), ArbiterCommand::Stop => write!(f, "ArbiterCommand::Stop"),
ArbiterCommand::Execute(_) => write!(f, "ArbiterCommand::Execute"), ArbiterCommand::Execute(_) => write!(f, "ArbiterCommand::Execute"),
ArbiterCommand::ExecuteFn(_) => write!(f, "ArbiterCommand::ExecuteFn"),
} }
} }
} }
@@ -158,6 +160,35 @@ impl Arbiter {
.0 .0
.unbounded_send(ArbiterCommand::Execute(Box::new(future))); .unbounded_send(ArbiterCommand::Execute(Box::new(future)));
} }
/// Send a function to the arbiter's thread and exeute.
pub fn exec_fn<F>(&self, f: F)
where
F: FnOnce() + Send + 'static,
{
let _ = self
.0
.unbounded_send(ArbiterCommand::ExecuteFn(Box::new(move || {
let _ = f();
})));
}
/// Send a function to the arbiter's thread, exeute and return result.
pub fn exec<F, R>(&self, f: F) -> impl Future<Item = R, Error = Canceled>
where
F: FnOnce() -> R + Send + 'static,
R: Send + 'static,
{
let (tx, rx) = channel();
let _ = self
.0
.unbounded_send(ArbiterCommand::ExecuteFn(Box::new(move || {
if !tx.is_canceled() {
let _ = tx.send(f());
}
})));
rx
}
} }
struct ArbiterController { struct ArbiterController {
@@ -194,6 +225,9 @@ impl Future for ArbiterController {
ArbiterCommand::Execute(fut) => { ArbiterCommand::Execute(fut) => {
spawn(fut); spawn(fut);
} }
ArbiterCommand::ExecuteFn(f) => {
f.call_box();
}
}, },
Ok(Async::NotReady) => return Ok(Async::NotReady), Ok(Async::NotReady) => return Ok(Async::NotReady),
} }
@@ -257,11 +291,16 @@ impl Future for SystemArbiter {
} }
} }
// /// Execute function in arbiter's thread pub trait FnExec: Send + 'static {
// impl<I: Send, E: Send> Handler<Execute<I, E>> for SystemArbiter { fn call_box(self: Box<Self>);
// type Result = Result<I, E>; }
// fn handle(&mut self, msg: Execute<I, E>, _: &mut Context<Self>) -> Result<I, E> { impl<F> FnExec for F
// msg.exec() where
// } F: FnOnce() + Send + 'static,
// } {
#[cfg_attr(feature = "cargo-clippy", allow(boxed_local))]
fn call_box(self: Box<Self>) {
(*self)()
}
}

88
actix-rt/src/blocking.rs Normal file
View File

@@ -0,0 +1,88 @@
//! Thread pool for blocking operations
use std::fmt;
use derive_more::Display;
use futures::sync::oneshot;
use futures::{Async, Future, Poll};
use parking_lot::Mutex;
use threadpool::ThreadPool;
/// Env variable for default cpu pool size
const ENV_CPU_POOL_VAR: &str = "ACTIX_CPU_POOL";
lazy_static::lazy_static! {
pub(crate) static ref DEFAULT_POOL: Mutex<ThreadPool> = {
let default = match std::env::var(ENV_CPU_POOL_VAR) {
Ok(val) => {
if let Ok(val) = val.parse() {
val
} else {
log::error!("Can not parse ACTIX_CPU_POOL value");
num_cpus::get() * 5
}
}
Err(_) => num_cpus::get() * 5,
};
Mutex::new(
threadpool::Builder::new()
.thread_name("actix-web".to_owned())
.num_threads(default)
.build(),
)
};
}
thread_local! {
static POOL: ThreadPool = {
DEFAULT_POOL.lock().clone()
};
}
/// Blocking operation execution error
#[derive(Debug, Display)]
pub enum BlockingError<E: fmt::Debug> {
#[display(fmt = "{:?}", _0)]
Error(E),
#[display(fmt = "Thread pool is gone")]
Canceled,
}
/// Execute blocking function on a thread pool, returns future that resolves
/// to result of the function execution.
pub fn run<F, I, E>(f: F) -> CpuFuture<I, E>
where
F: FnOnce() -> Result<I, E> + Send + 'static,
I: Send + 'static,
E: Send + fmt::Debug + 'static,
{
let (tx, rx) = oneshot::channel();
POOL.with(|pool| {
pool.execute(move || {
if !tx.is_canceled() {
let _ = tx.send(f());
}
})
});
CpuFuture { rx }
}
/// Blocking operation completion future. It resolves with results
/// of blocking function execution.
pub struct CpuFuture<I, E> {
rx: oneshot::Receiver<Result<I, E>>,
}
impl<I, E: fmt::Debug> Future for CpuFuture<I, E> {
type Item = I;
type Error = BlockingError<E>;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let res = futures::try_ready!(self.rx.poll().map_err(|_| BlockingError::Canceled));
match res {
Ok(val) => Ok(Async::Ready(val)),
Err(err) => Err(BlockingError::Error(err)),
}
}
}

View File

@@ -1,6 +1,7 @@
//! A runtime implementation that runs everything on the current thread. //! A runtime implementation that runs everything on the current thread.
mod arbiter; mod arbiter;
pub mod blocking;
mod builder; mod builder;
mod runtime; mod runtime;
mod system; mod system;

View File

@@ -1,14 +1,18 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::io; use std::io;
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use futures::sync::mpsc::UnboundedSender; use futures::sync::mpsc::UnboundedSender;
use crate::arbiter::{Arbiter, SystemCommand}; use crate::arbiter::{Arbiter, SystemCommand};
use crate::builder::{Builder, SystemRunner}; use crate::builder::{Builder, SystemRunner};
static SYSTEM_COUNT: AtomicUsize = ATOMIC_USIZE_INIT;
/// System is a runtime manager. /// System is a runtime manager.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct System { pub struct System {
id: usize,
sys: UnboundedSender<SystemCommand>, sys: UnboundedSender<SystemCommand>,
arbiter: Arbiter, arbiter: Arbiter,
stop_on_panic: bool, stop_on_panic: bool,
@@ -29,6 +33,7 @@ impl System {
sys, sys,
arbiter, arbiter,
stop_on_panic, stop_on_panic,
id: SYSTEM_COUNT.fetch_add(1, Ordering::SeqCst),
}; };
System::set_current(sys.clone()); System::set_current(sys.clone());
sys sys
@@ -82,6 +87,11 @@ impl System {
}) })
} }
/// System id
pub fn id(&self) -> usize {
self.id
}
/// Stop the system /// Stop the system
pub fn stop(&self) { pub fn stop(&self) {
self.stop_with_code(0) self.stop_with_code(0)

View File

@@ -0,0 +1,17 @@
[package]
name = "actix-server-config"
version = "0.1.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix server config utils"
homepage = "https://actix.rs"
repository = "https://github.com/actix/actix-net.git"
license = "MIT/Apache-2.0"
edition = "2018"
workspace = ".."
[lib]
name = "actix_server_config"
path = "src/lib.rs"
[dependencies]
futures = "0.1.25"

View File

@@ -0,0 +1,132 @@
use std::cell::Cell;
use std::fmt;
use std::net::SocketAddr;
use std::rc::Rc;
#[derive(Debug, Clone)]
pub struct ServerConfig {
addr: SocketAddr,
secure: Rc<Cell<bool>>,
}
impl ServerConfig {
pub fn new(addr: SocketAddr) -> Self {
ServerConfig {
addr,
secure: Rc::new(Cell::new(false)),
}
}
/// Returns the address of the local half of this TCP server socket
pub fn local_addr(&self) -> SocketAddr {
self.addr
}
/// Returns true if connection is secure (tls enabled)
pub fn secure(&self) -> bool {
self.secure.as_ref().get()
}
/// Set secure flag
pub fn set_secure(&self) {
self.secure.as_ref().set(true)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Protocol {
Unknown,
Http10,
Http11,
Http2,
Proto1,
Proto2,
Proto3,
Proto4,
Proto5,
Proto6,
}
pub struct Io<T, P = ()> {
io: T,
proto: Protocol,
params: P,
}
impl<T> Io<T, ()> {
pub fn new(io: T) -> Self {
Self {
io,
proto: Protocol::Unknown,
params: (),
}
}
}
impl<T, P> Io<T, P> {
/// Reconstruct from a parts.
pub fn from_parts(io: T, params: P, proto: Protocol) -> Self {
Self { io, params, proto }
}
/// Deconstruct into a parts.
pub fn into_parts(self) -> (T, P, Protocol) {
(self.io, self.params, self.proto)
}
/// Returns a shared reference to the underlying stream.
pub fn get_ref(&self) -> &T {
&self.io
}
/// Returns a mutable reference to the underlying stream.
pub fn get_mut(&mut self) -> &mut T {
&mut self.io
}
/// Get selected protocol
pub fn protocol(&self) -> Protocol {
self.proto
}
/// Return new Io object with new parameter.
pub fn set<U>(self, params: U) -> Io<T, U> {
Io {
io: self.io,
proto: self.proto,
params: params,
}
}
/// Maps an Io<_, P> to Io<_, U> by applying a function to a contained value.
pub fn map<U, F>(self, op: F) -> Io<T, U>
where
F: FnOnce(P) -> U,
{
Io {
io: self.io,
proto: self.proto,
params: op(self.params),
}
}
}
impl<T, P> std::ops::Deref for Io<T, P> {
type Target = T;
fn deref(&self) -> &T {
&self.io
}
}
impl<T, P> std::ops::DerefMut for Io<T, P> {
fn deref_mut(&mut self) -> &mut T {
&mut self.io
}
}
impl<T: fmt::Debug, P> fmt::Debug for Io<T, P> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Io {{{:?}}}", self.io)
}
}

View File

@@ -33,9 +33,9 @@ ssl = ["openssl", "tokio-openssl"]
rust-tls = ["rustls", "tokio-rustls", "webpki", "webpki-roots"] rust-tls = ["rustls", "tokio-rustls", "webpki", "webpki-roots"]
[dependencies] [dependencies]
#actix-service = "0.3.2" actix-rt = "0.2.1"
actix-service = { path="../actix-service" } actix-service = "0.3.3"
actix-rt = "0.2.0" actix-server-config = { path="../actix-server-config" }
log = "0.4" log = "0.4"
num_cpus = "1.0" num_cpus = "1.0"
@@ -64,5 +64,6 @@ webpki = { version = "0.19", optional = true }
webpki-roots = { version = "0.16", optional = true } webpki-roots = { version = "0.16", optional = true }
[dev-dependencies] [dev-dependencies]
env_logger = "0.6" bytes = "0.4"
actix-codec = "0.1.0" actix-codec = "0.1.0"
env_logger = "0.6"

View File

@@ -12,8 +12,8 @@ use num_cpus;
use tokio_timer::sleep; use tokio_timer::sleep;
use crate::accept::{AcceptLoop, AcceptNotify, Command}; use crate::accept::{AcceptLoop, AcceptNotify, Command};
use crate::config::{ConfiguredService, ServiceConfig};
use crate::server::{Server, ServerCommand}; use crate::server::{Server, ServerCommand};
use crate::service_config::{ConfiguredService, ServiceConfig};
use crate::services::{InternalServiceFactory, ServiceFactory, StreamNewService}; use crate::services::{InternalServiceFactory, ServiceFactory, StreamNewService};
use crate::signals::{Signal, Signals}; use crate::signals::{Signal, Signals};
use crate::worker::{self, Worker, WorkerAvailability, WorkerClient}; use crate::worker::{self, Worker, WorkerAvailability, WorkerClient};
@@ -23,6 +23,7 @@ use crate::{ssl, Token};
pub struct ServerBuilder { pub struct ServerBuilder {
threads: usize, threads: usize,
token: Token, token: Token,
backlog: i32,
workers: Vec<(usize, WorkerClient)>, workers: Vec<(usize, WorkerClient)>,
services: Vec<Box<InternalServiceFactory>>, services: Vec<Box<InternalServiceFactory>>,
sockets: Vec<(Token, net::TcpListener)>, sockets: Vec<(Token, net::TcpListener)>,
@@ -53,6 +54,7 @@ impl ServerBuilder {
services: Vec::new(), services: Vec::new(),
sockets: Vec::new(), sockets: Vec::new(),
accept: AcceptLoop::new(server.clone()), accept: AcceptLoop::new(server.clone()),
backlog: 2048,
exit: false, exit: false,
shutdown_timeout: Duration::from_secs(30), shutdown_timeout: Duration::from_secs(30),
no_signals: false, no_signals: false,
@@ -70,6 +72,21 @@ impl ServerBuilder {
self self
} }
/// Set the maximum number of pending connections.
///
/// This refers to the number of clients that can be waiting to be served.
/// Exceeding this number results in the client getting an error when
/// attempting to connect. It should only affect servers under significant
/// load.
///
/// Generally set in the 64-2048 range. Default value is 2048.
///
/// This method should be called before `bind()` method call.
pub fn backlog(mut self, num: i32) -> Self {
self.backlog = num;
self
}
/// Sets the maximum per-worker number of concurrent connections. /// Sets the maximum per-worker number of concurrent connections.
/// ///
/// All socket listeners will stop accepting connections when this limit is /// All socket listeners will stop accepting connections when this limit is
@@ -125,7 +142,7 @@ impl ServerBuilder {
where where
F: Fn(&mut ServiceConfig) -> io::Result<()>, F: Fn(&mut ServiceConfig) -> io::Result<()>,
{ {
let mut cfg = ServiceConfig::new(self.threads); let mut cfg = ServiceConfig::new(self.threads, self.backlog);
f(&mut cfg)?; f(&mut cfg)?;
@@ -133,7 +150,7 @@ impl ServerBuilder {
let mut srv = ConfiguredService::new(apply); let mut srv = ConfiguredService::new(apply);
for (name, lst) in cfg.services { for (name, lst) in cfg.services {
let token = self.token.next(); let token = self.token.next();
srv.stream(token, name); srv.stream(token, name, lst.local_addr()?);
self.sockets.push((token, lst)); self.sockets.push((token, lst));
} }
self.services.push(Box::new(srv)); self.services.push(Box::new(srv));
@@ -149,16 +166,16 @@ impl ServerBuilder {
F: ServiceFactory, F: ServiceFactory,
U: net::ToSocketAddrs, U: net::ToSocketAddrs,
{ {
let sockets = bind_addr(addr)?; let sockets = bind_addr(addr, self.backlog)?;
let token = self.token.next();
self.services.push(StreamNewService::create(
name.as_ref().to_string(),
token,
factory,
));
for lst in sockets { for lst in sockets {
let token = self.token.next();
self.services.push(StreamNewService::create(
name.as_ref().to_string(),
token,
factory.clone(),
lst.local_addr()?,
));
self.sockets.push((token, lst)); self.sockets.push((token, lst));
} }
Ok(self) Ok(self)
@@ -170,7 +187,7 @@ impl ServerBuilder {
name: N, name: N,
lst: net::TcpListener, lst: net::TcpListener,
factory: F, factory: F,
) -> Self ) -> io::Result<Self>
where where
F: ServiceFactory, F: ServiceFactory,
{ {
@@ -179,9 +196,10 @@ impl ServerBuilder {
name.as_ref().to_string(), name.as_ref().to_string(),
token, token,
factory, factory,
lst.local_addr()?,
)); ));
self.sockets.push((token, lst)); self.sockets.push((token, lst));
self Ok(self)
} }
/// Spawn new thread and start listening for incoming connections. /// Spawn new thread and start listening for incoming connections.
@@ -194,19 +212,18 @@ impl ServerBuilder {
/// ```rust,ignore /// ```rust,ignore
/// use actix_web::*; /// use actix_web::*;
/// ///
/// fn main() { /// fn main() -> std::io::Result<()> {
/// Server::new(). /// Server::new().
/// .service( /// .service(
/// HttpServer::new(|| App::new().resource("/", |r| r.h(|_| HttpResponse::Ok()))) /// HttpServer::new(|| App::new().service(web::service("/").to(|| HttpResponse::Ok())))
/// .bind("127.0.0.1:0") /// .bind("127.0.0.1:0")
/// .expect("Can not bind to 127.0.0.1:0")) /// .run()
/// .run();
/// } /// }
/// ``` /// ```
pub fn run(self) { pub fn run(self) -> io::Result<()> {
let sys = System::new("http-server"); let sys = System::new("http-server");
self.start(); self.start();
sys.run(); sys.run()
} }
/// Starts processing incoming connections and return server controller. /// Starts processing incoming connections and return server controller.
@@ -393,12 +410,15 @@ impl Future for ServerBuilder {
} }
} }
pub(super) fn bind_addr<S: net::ToSocketAddrs>(addr: S) -> io::Result<Vec<net::TcpListener>> { pub(super) fn bind_addr<S: net::ToSocketAddrs>(
addr: S,
backlog: i32,
) -> io::Result<Vec<net::TcpListener>> {
let mut err = None; let mut err = None;
let mut succ = false; let mut succ = false;
let mut sockets = Vec::new(); let mut sockets = Vec::new();
for addr in addr.to_socket_addrs()? { for addr in addr.to_socket_addrs()? {
match create_tcp_listener(addr) { match create_tcp_listener(addr, backlog) {
Ok(lst) => { Ok(lst) => {
succ = true; succ = true;
sockets.push(lst); sockets.push(lst);
@@ -421,12 +441,12 @@ pub(super) fn bind_addr<S: net::ToSocketAddrs>(addr: S) -> io::Result<Vec<net::T
} }
} }
fn create_tcp_listener(addr: net::SocketAddr) -> io::Result<net::TcpListener> { fn create_tcp_listener(addr: net::SocketAddr, backlog: i32) -> io::Result<net::TcpListener> {
let builder = match addr { let builder = match addr {
net::SocketAddr::V4(_) => TcpBuilder::new_v4()?, net::SocketAddr::V4(_) => TcpBuilder::new_v4()?,
net::SocketAddr::V6(_) => TcpBuilder::new_v6()?, net::SocketAddr::V6(_) => TcpBuilder::new_v6()?,
}; };
builder.reuse_address(true)?; builder.reuse_address(true)?;
builder.bind(addr)?; builder.bind(addr)?;
Ok(builder.listen(1024)?) Ok(builder.listen(backlog)?)
} }

View File

@@ -2,17 +2,19 @@
mod accept; mod accept;
mod builder; mod builder;
mod config;
mod counter; mod counter;
mod server; mod server;
mod service_config;
mod services; mod services;
mod signals; mod signals;
pub mod ssl; pub mod ssl;
mod worker; mod worker;
pub use actix_server_config::{Io, Protocol, ServerConfig};
pub use self::builder::ServerBuilder; pub use self::builder::ServerBuilder;
pub use self::config::{ServiceConfig, ServiceRuntime};
pub use self::server::Server; pub use self::server::Server;
pub use self::service_config::{ServiceConfig, ServiceRuntime};
pub use self::services::ServiceFactory; pub use self::services::ServiceFactory;
#[doc(hidden)] #[doc(hidden)]

View File

@@ -1,6 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::{fmt, io, net}; use std::{fmt, io, net};
use actix_server_config::{Io, ServerConfig};
use actix_service::{IntoNewService, NewService}; use actix_service::{IntoNewService, NewService};
use futures::future::{join_all, Future}; use futures::future::{join_all, Future};
use log::error; use log::error;
@@ -18,12 +19,14 @@ pub struct ServiceConfig {
pub(crate) services: Vec<(String, net::TcpListener)>, pub(crate) services: Vec<(String, net::TcpListener)>,
pub(crate) apply: Option<Box<ServiceRuntimeConfiguration>>, pub(crate) apply: Option<Box<ServiceRuntimeConfiguration>>,
pub(crate) threads: usize, pub(crate) threads: usize,
pub(crate) backlog: i32,
} }
impl ServiceConfig { impl ServiceConfig {
pub(super) fn new(threads: usize) -> ServiceConfig { pub(super) fn new(threads: usize, backlog: i32) -> ServiceConfig {
ServiceConfig { ServiceConfig {
threads, threads,
backlog,
services: Vec::new(), services: Vec::new(),
apply: None, apply: None,
} }
@@ -42,7 +45,7 @@ impl ServiceConfig {
where where
U: net::ToSocketAddrs, U: net::ToSocketAddrs,
{ {
let sockets = bind_addr(addr)?; let sockets = bind_addr(addr, self.backlog)?;
for lst in sockets { for lst in sockets {
self.listen(name.as_ref(), lst); self.listen(name.as_ref(), lst);
@@ -73,7 +76,7 @@ impl ServiceConfig {
pub(super) struct ConfiguredService { pub(super) struct ConfiguredService {
rt: Box<ServiceRuntimeConfiguration>, rt: Box<ServiceRuntimeConfiguration>,
names: HashMap<Token, String>, names: HashMap<Token, (String, net::SocketAddr)>,
services: HashMap<String, Token>, services: HashMap<String, Token>,
} }
@@ -86,15 +89,15 @@ impl ConfiguredService {
} }
} }
pub(super) fn stream(&mut self, token: Token, name: String) { pub(super) fn stream(&mut self, token: Token, name: String, addr: net::SocketAddr) {
self.names.insert(token, name.clone()); self.names.insert(token, (name.clone(), addr));
self.services.insert(name, token); self.services.insert(name, token);
} }
} }
impl InternalServiceFactory for ConfiguredService { impl InternalServiceFactory for ConfiguredService {
fn name(&self, token: Token) -> &str { fn name(&self, token: Token) -> &str {
&self.names[&token] &self.names[&token].0
} }
fn clone_factory(&self) -> Box<InternalServiceFactory> { fn clone_factory(&self) -> Box<InternalServiceFactory> {
@@ -114,7 +117,8 @@ impl InternalServiceFactory for ConfiguredService {
// construct services // construct services
let mut fut = Vec::new(); let mut fut = Vec::new();
for (token, ns) in rt.services { for (token, ns) in rt.services {
fut.push(ns.new_service(&()).map(move |service| (token, service))); let config = ServerConfig::new(self.names[&token].1);
fut.push(ns.new_service(&config).map(move |service| (token, service)));
} }
Box::new(join_all(fut).map_err(|e| { Box::new(join_all(fut).map_err(|e| {
@@ -169,8 +173,8 @@ impl ServiceRuntime {
pub fn service<T, F>(&mut self, name: &str, service: F) pub fn service<T, F>(&mut self, name: &str, service: F)
where where
F: IntoNewService<T, TcpStream>, F: IntoNewService<T, ServerConfig>,
T: NewService<TcpStream, Response = ()> + 'static, T: NewService<ServerConfig, Request = Io<TcpStream>> + 'static,
T::Future: 'static, T::Future: 'static,
T::Service: 'static, T::Service: 'static,
T::InitError: fmt::Debug, T::InitError: fmt::Debug,
@@ -191,7 +195,8 @@ impl ServiceRuntime {
type BoxedNewService = Box< type BoxedNewService = Box<
NewService< NewService<
(Option<CounterGuard>, ServerMessage), ServerConfig,
Request = (Option<CounterGuard>, ServerMessage),
Response = (), Response = (),
Error = (), Error = (),
InitError = (), InitError = (),
@@ -204,22 +209,23 @@ struct ServiceFactory<T> {
inner: T, inner: T,
} }
impl<T> NewService<(Option<CounterGuard>, ServerMessage)> for ServiceFactory<T> impl<T> NewService<ServerConfig> for ServiceFactory<T>
where where
T: NewService<TcpStream, Response = ()>, T: NewService<ServerConfig, Request = Io<TcpStream>>,
T::Future: 'static, T::Future: 'static,
T::Service: 'static, T::Service: 'static,
T::Error: 'static, T::Error: 'static,
T::InitError: fmt::Debug + 'static, T::InitError: fmt::Debug + 'static,
{ {
type Request = (Option<CounterGuard>, ServerMessage);
type Response = (); type Response = ();
type Error = (); type Error = ();
type InitError = (); type InitError = ();
type Service = BoxedServerService; type Service = BoxedServerService;
type Future = Box<Future<Item = BoxedServerService, Error = ()>>; type Future = Box<Future<Item = BoxedServerService, Error = ()>>;
fn new_service(&self, _: &()) -> Self::Future { fn new_service(&self, cfg: &ServerConfig) -> Self::Future {
Box::new(self.inner.new_service(&()).map_err(|_| ()).map(|s| { Box::new(self.inner.new_service(cfg).map_err(|_| ()).map(|s| {
let service: BoxedServerService = Box::new(StreamService::new(s)); let service: BoxedServerService = Box::new(StreamService::new(s));
service service
})) }))

View File

@@ -1,7 +1,8 @@
use std::net; use std::net::{self, SocketAddr};
use std::time::Duration; use std::time::Duration;
use actix_rt::spawn; use actix_rt::spawn;
use actix_server_config::{Io, ServerConfig};
use actix_service::{NewService, Service}; use actix_service::{NewService, Service};
use futures::future::{err, ok, FutureResult}; use futures::future::{err, ok, FutureResult};
use futures::{Future, Poll}; use futures::{Future, Poll};
@@ -23,7 +24,7 @@ pub(crate) enum ServerMessage {
} }
pub trait ServiceFactory: Send + Clone + 'static { pub trait ServiceFactory: Send + Clone + 'static {
type NewService: NewService<TcpStream>; type NewService: NewService<ServerConfig, Request = Io<TcpStream>>;
fn create(&self) -> Self::NewService; fn create(&self) -> Self::NewService;
} }
@@ -38,7 +39,7 @@ pub(crate) trait InternalServiceFactory: Send {
pub(crate) type BoxedServerService = Box< pub(crate) type BoxedServerService = Box<
Service< Service<
(Option<CounterGuard>, ServerMessage), Request = (Option<CounterGuard>, ServerMessage),
Response = (), Response = (),
Error = (), Error = (),
Future = FutureResult<(), ()>, Future = FutureResult<(), ()>,
@@ -55,12 +56,13 @@ impl<T> StreamService<T> {
} }
} }
impl<T> Service<(Option<CounterGuard>, ServerMessage)> for StreamService<T> impl<T> Service for StreamService<T>
where where
T: Service<TcpStream>, T: Service<Request = Io<TcpStream>>,
T::Future: 'static, T::Future: 'static,
T::Error: 'static, T::Error: 'static,
{ {
type Request = (Option<CounterGuard>, ServerMessage);
type Response = (); type Response = ();
type Error = (); type Error = ();
type Future = FutureResult<(), ()>; type Future = FutureResult<(), ()>;
@@ -77,7 +79,7 @@ where
}); });
if let Ok(stream) = stream { if let Ok(stream) = stream {
spawn(self.service.call(stream).then(move |res| { spawn(self.service.call(Io::new(stream)).then(move |res| {
drop(guard); drop(guard);
res.map_err(|_| ()).map(|_| ()) res.map_err(|_| ()).map(|_| ())
})); }));
@@ -95,14 +97,25 @@ pub(crate) struct StreamNewService<F: ServiceFactory> {
name: String, name: String,
inner: F, inner: F,
token: Token, token: Token,
addr: SocketAddr,
} }
impl<F> StreamNewService<F> impl<F> StreamNewService<F>
where where
F: ServiceFactory, F: ServiceFactory,
{ {
pub(crate) fn create(name: String, token: Token, inner: F) -> Box<InternalServiceFactory> { pub(crate) fn create(
Box::new(Self { name, token, inner }) name: String,
token: Token,
inner: F,
addr: SocketAddr,
) -> Box<InternalServiceFactory> {
Box::new(Self {
name,
token,
inner,
addr,
})
} }
} }
@@ -119,15 +132,17 @@ where
name: self.name.clone(), name: self.name.clone(),
inner: self.inner.clone(), inner: self.inner.clone(),
token: self.token, token: self.token,
addr: self.addr,
}) })
} }
fn create(&self) -> Box<Future<Item = Vec<(Token, BoxedServerService)>, Error = ()>> { fn create(&self) -> Box<Future<Item = Vec<(Token, BoxedServerService)>, Error = ()>> {
let token = self.token; let token = self.token;
let config = ServerConfig::new(self.addr);
Box::new( Box::new(
self.inner self.inner
.create() .create()
.new_service(&()) .new_service(&config)
.map_err(|_| ()) .map_err(|_| ())
.map(move |inner| { .map(move |inner| {
let service: BoxedServerService = Box::new(StreamService::new(inner)); let service: BoxedServerService = Box::new(StreamService::new(inner));
@@ -154,7 +169,7 @@ impl InternalServiceFactory for Box<InternalServiceFactory> {
impl<F, T> ServiceFactory for F impl<F, T> ServiceFactory for F
where where
F: Fn() -> T + Send + Clone + 'static, F: Fn() -> T + Send + Clone + 'static,
T: NewService<TcpStream>, T: NewService<ServerConfig, Request = Io<TcpStream>>,
{ {
type NewService = T; type NewService = T;

View File

@@ -6,18 +6,19 @@ use futures::{future::ok, future::FutureResult, Async, Future, Poll};
use native_tls::{self, Error, HandshakeError, TlsAcceptor}; use native_tls::{self, Error, HandshakeError, TlsAcceptor};
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
use super::MAX_CONN_COUNTER;
use crate::counter::{Counter, CounterGuard}; use crate::counter::{Counter, CounterGuard};
use crate::ssl::MAX_CONN_COUNTER;
use crate::{Io, Protocol, ServerConfig};
/// Support `SSL` connections via native-tls package /// Support `SSL` connections via native-tls package
/// ///
/// `tls` feature enables `NativeTlsAcceptor` type /// `tls` feature enables `NativeTlsAcceptor` type
pub struct NativeTlsAcceptor<T> { pub struct NativeTlsAcceptor<T, P = ()> {
acceptor: TlsAcceptor, acceptor: TlsAcceptor,
io: PhantomData<T>, io: PhantomData<(T, P)>,
} }
impl<T: AsyncRead + AsyncWrite> NativeTlsAcceptor<T> { impl<T: AsyncRead + AsyncWrite, P> NativeTlsAcceptor<T, P> {
/// Create `NativeTlsAcceptor` instance /// Create `NativeTlsAcceptor` instance
pub fn new(acceptor: TlsAcceptor) -> Self { pub fn new(acceptor: TlsAcceptor) -> Self {
NativeTlsAcceptor { NativeTlsAcceptor {
@@ -27,7 +28,7 @@ impl<T: AsyncRead + AsyncWrite> NativeTlsAcceptor<T> {
} }
} }
impl<T: AsyncRead + AsyncWrite> Clone for NativeTlsAcceptor<T> { impl<T: AsyncRead + AsyncWrite, P> Clone for NativeTlsAcceptor<T, P> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
acceptor: self.acceptor.clone(), acceptor: self.acceptor.clone(),
@@ -36,14 +37,17 @@ impl<T: AsyncRead + AsyncWrite> Clone for NativeTlsAcceptor<T> {
} }
} }
impl<T: AsyncRead + AsyncWrite> NewService<T> for NativeTlsAcceptor<T> { impl<T: AsyncRead + AsyncWrite, P> NewService<ServerConfig> for NativeTlsAcceptor<T, P> {
type Response = TlsStream<T>; type Request = Io<T, P>;
type Response = Io<TlsStream<T>, P>;
type Error = Error; type Error = Error;
type Service = NativeTlsAcceptorService<T>; type Service = NativeTlsAcceptorService<T, P>;
type InitError = (); type InitError = ();
type Future = FutureResult<Self::Service, Self::InitError>; type Future = FutureResult<Self::Service, Self::InitError>;
fn new_service(&self, _: &()) -> Self::Future { fn new_service(&self, cfg: &ServerConfig) -> Self::Future {
cfg.set_secure();
MAX_CONN_COUNTER.with(|conns| { MAX_CONN_COUNTER.with(|conns| {
ok(NativeTlsAcceptorService { ok(NativeTlsAcceptorService {
acceptor: self.acceptor.clone(), acceptor: self.acceptor.clone(),
@@ -54,16 +58,17 @@ impl<T: AsyncRead + AsyncWrite> NewService<T> for NativeTlsAcceptor<T> {
} }
} }
pub struct NativeTlsAcceptorService<T> { pub struct NativeTlsAcceptorService<T, P> {
acceptor: TlsAcceptor, acceptor: TlsAcceptor,
io: PhantomData<T>, io: PhantomData<(T, P)>,
conns: Counter, conns: Counter,
} }
impl<T: AsyncRead + AsyncWrite> Service<T> for NativeTlsAcceptorService<T> { impl<T: AsyncRead + AsyncWrite, P> Service for NativeTlsAcceptorService<T, P> {
type Response = TlsStream<T>; type Request = Io<T, P>;
type Response = Io<TlsStream<T>, P>;
type Error = Error; type Error = Error;
type Future = Accept<T>; type Future = Accept<T, P>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(&mut self) -> Poll<(), Self::Error> {
if self.conns.available() { if self.conns.available() {
@@ -73,10 +78,12 @@ impl<T: AsyncRead + AsyncWrite> Service<T> for NativeTlsAcceptorService<T> {
} }
} }
fn call(&mut self, req: T) -> Self::Future { fn call(&mut self, req: Self::Request) -> Self::Future {
let (io, params, _) = req.into_parts();
Accept { Accept {
_guard: self.conns.get(), _guard: self.conns.get(),
inner: Some(self.acceptor.accept(req)), inner: Some(self.acceptor.accept(io)),
params: Some(params),
} }
} }
} }
@@ -95,21 +102,30 @@ pub struct TlsStream<S> {
/// Future returned from `NativeTlsAcceptor::accept` which will resolve /// Future returned from `NativeTlsAcceptor::accept` which will resolve
/// once the accept handshake has finished. /// once the accept handshake has finished.
pub struct Accept<S> { pub struct Accept<S, P> {
inner: Option<Result<native_tls::TlsStream<S>, HandshakeError<S>>>, inner: Option<Result<native_tls::TlsStream<S>, HandshakeError<S>>>,
params: Option<P>,
_guard: CounterGuard, _guard: CounterGuard,
} }
impl<Io: AsyncRead + AsyncWrite> Future for Accept<Io> { impl<T: AsyncRead + AsyncWrite, P> Future for Accept<T, P> {
type Item = TlsStream<Io>; type Item = Io<TlsStream<T>, P>;
type Error = Error; type Error = Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
match self.inner.take().expect("cannot poll MidHandshake twice") { match self.inner.take().expect("cannot poll MidHandshake twice") {
Ok(stream) => Ok(TlsStream { inner: stream }.into()), Ok(stream) => Ok(Async::Ready(Io::from_parts(
TlsStream { inner: stream },
self.params.take().unwrap(),
Protocol::Unknown,
))),
Err(HandshakeError::Failure(e)) => Err(e), Err(HandshakeError::Failure(e)) => Err(e),
Err(HandshakeError::WouldBlock(s)) => match s.handshake() { Err(HandshakeError::WouldBlock(s)) => match s.handshake() {
Ok(stream) => Ok(TlsStream { inner: stream }.into()), Ok(stream) => Ok(Async::Ready(Io::from_parts(
TlsStream { inner: stream },
self.params.take().unwrap(),
Protocol::Unknown,
))),
Err(HandshakeError::Failure(e)) => Err(e), Err(HandshakeError::Failure(e)) => Err(e),
Err(HandshakeError::WouldBlock(s)) => { Err(HandshakeError::WouldBlock(s)) => {
self.inner = Some(Err(HandshakeError::WouldBlock(s))); self.inner = Some(Err(HandshakeError::WouldBlock(s)));

View File

@@ -6,18 +6,19 @@ use openssl::ssl::{HandshakeError, SslAcceptor};
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
use tokio_openssl::{AcceptAsync, SslAcceptorExt, SslStream}; use tokio_openssl::{AcceptAsync, SslAcceptorExt, SslStream};
use super::MAX_CONN_COUNTER;
use crate::counter::{Counter, CounterGuard}; use crate::counter::{Counter, CounterGuard};
use crate::ssl::MAX_CONN_COUNTER;
use crate::{Io, Protocol, ServerConfig};
/// Support `SSL` connections via openssl package /// Support `SSL` connections via openssl package
/// ///
/// `ssl` feature enables `OpensslAcceptor` type /// `ssl` feature enables `OpensslAcceptor` type
pub struct OpensslAcceptor<T> { pub struct OpensslAcceptor<T: AsyncRead + AsyncWrite, P = ()> {
acceptor: SslAcceptor, acceptor: SslAcceptor,
io: PhantomData<T>, io: PhantomData<(T, P)>,
} }
impl<T> OpensslAcceptor<T> { impl<T: AsyncRead + AsyncWrite, P> OpensslAcceptor<T, P> {
/// Create default `OpensslAcceptor` /// Create default `OpensslAcceptor`
pub fn new(acceptor: SslAcceptor) -> Self { pub fn new(acceptor: SslAcceptor) -> Self {
OpensslAcceptor { OpensslAcceptor {
@@ -27,7 +28,7 @@ impl<T> OpensslAcceptor<T> {
} }
} }
impl<T: AsyncRead + AsyncWrite> Clone for OpensslAcceptor<T> { impl<T: AsyncRead + AsyncWrite, P> Clone for OpensslAcceptor<T, P> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
acceptor: self.acceptor.clone(), acceptor: self.acceptor.clone(),
@@ -36,14 +37,17 @@ impl<T: AsyncRead + AsyncWrite> Clone for OpensslAcceptor<T> {
} }
} }
impl<T: AsyncRead + AsyncWrite> NewService<T> for OpensslAcceptor<T> { impl<T: AsyncRead + AsyncWrite, P> NewService<ServerConfig> for OpensslAcceptor<T, P> {
type Response = SslStream<T>; type Request = Io<T, P>;
type Response = Io<SslStream<T>, P>;
type Error = HandshakeError<T>; type Error = HandshakeError<T>;
type Service = OpensslAcceptorService<T>; type Service = OpensslAcceptorService<T, P>;
type InitError = (); type InitError = ();
type Future = FutureResult<Self::Service, Self::InitError>; type Future = FutureResult<Self::Service, Self::InitError>;
fn new_service(&self, _: &()) -> Self::Future { fn new_service(&self, cfg: &ServerConfig) -> Self::Future {
cfg.set_secure();
MAX_CONN_COUNTER.with(|conns| { MAX_CONN_COUNTER.with(|conns| {
ok(OpensslAcceptorService { ok(OpensslAcceptorService {
acceptor: self.acceptor.clone(), acceptor: self.acceptor.clone(),
@@ -54,16 +58,17 @@ impl<T: AsyncRead + AsyncWrite> NewService<T> for OpensslAcceptor<T> {
} }
} }
pub struct OpensslAcceptorService<T> { pub struct OpensslAcceptorService<T, P> {
acceptor: SslAcceptor, acceptor: SslAcceptor,
io: PhantomData<T>,
conns: Counter, conns: Counter,
io: PhantomData<(T, P)>,
} }
impl<T: AsyncRead + AsyncWrite> Service<T> for OpensslAcceptorService<T> { impl<T: AsyncRead + AsyncWrite, P> Service for OpensslAcceptorService<T, P> {
type Response = SslStream<T>; type Request = Io<T, P>;
type Response = Io<SslStream<T>, P>;
type Error = HandshakeError<T>; type Error = HandshakeError<T>;
type Future = OpensslAcceptorServiceFut<T>; type Future = OpensslAcceptorServiceFut<T, P>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(&mut self) -> Poll<(), Self::Error> {
if self.conns.available() { if self.conns.available() {
@@ -73,27 +78,52 @@ impl<T: AsyncRead + AsyncWrite> Service<T> for OpensslAcceptorService<T> {
} }
} }
fn call(&mut self, req: T) -> Self::Future { fn call(&mut self, req: Self::Request) -> Self::Future {
let (io, params, _) = req.into_parts();
OpensslAcceptorServiceFut { OpensslAcceptorServiceFut {
_guard: self.conns.get(), _guard: self.conns.get(),
fut: SslAcceptorExt::accept_async(&self.acceptor, req), fut: SslAcceptorExt::accept_async(&self.acceptor, io),
params: Some(params),
} }
} }
} }
pub struct OpensslAcceptorServiceFut<T> pub struct OpensslAcceptorServiceFut<T, P>
where where
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
{ {
fut: AcceptAsync<T>, fut: AcceptAsync<T>,
params: Option<P>,
_guard: CounterGuard, _guard: CounterGuard,
} }
impl<T: AsyncRead + AsyncWrite> Future for OpensslAcceptorServiceFut<T> { impl<T: AsyncRead + AsyncWrite, P> Future for OpensslAcceptorServiceFut<T, P> {
type Item = SslStream<T>; type Item = Io<SslStream<T>, P>;
type Error = HandshakeError<T>; type Error = HandshakeError<T>;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
self.fut.poll() let io = futures::try_ready!(self.fut.poll());
let proto = if let Some(protos) = io.get_ref().ssl().selected_alpn_protocol() {
const H2: &[u8] = b"\x02h2";
const HTTP10: &[u8] = b"\x08http/1.0";
const HTTP11: &[u8] = b"\x08http/1.1";
if protos.windows(3).any(|window| window == H2) {
Protocol::Http2
} else if protos.windows(9).any(|window| window == HTTP11) {
Protocol::Http11
} else if protos.windows(9).any(|window| window == HTTP10) {
Protocol::Http10
} else {
Protocol::Unknown
}
} else {
Protocol::Unknown
};
Ok(Async::Ready(Io::from_parts(
io,
self.params.take().unwrap(),
proto,
)))
} }
} }

View File

@@ -8,18 +8,19 @@ use rustls::{ServerConfig, ServerSession};
use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::{AsyncRead, AsyncWrite};
use tokio_rustls::{Accept, TlsAcceptor, TlsStream}; use tokio_rustls::{Accept, TlsAcceptor, TlsStream};
use super::MAX_CONN_COUNTER;
use crate::counter::{Counter, CounterGuard}; use crate::counter::{Counter, CounterGuard};
use crate::ssl::MAX_CONN_COUNTER;
use crate::{Io, Protocol, ServerConfig as SrvConfig};
/// Support `SSL` connections via rustls package /// Support `SSL` connections via rustls package
/// ///
/// `rust-tls` feature enables `RustlsAcceptor` type /// `rust-tls` feature enables `RustlsAcceptor` type
pub struct RustlsAcceptor<T> { pub struct RustlsAcceptor<T, P = ()> {
config: Arc<ServerConfig>, config: Arc<ServerConfig>,
io: PhantomData<T>, io: PhantomData<(T, P)>,
} }
impl<T: AsyncRead + AsyncWrite> RustlsAcceptor<T> { impl<T: AsyncRead + AsyncWrite, P> RustlsAcceptor<T, P> {
/// Create `RustlsAcceptor` new service /// Create `RustlsAcceptor` new service
pub fn new(config: ServerConfig) -> Self { pub fn new(config: ServerConfig) -> Self {
RustlsAcceptor { RustlsAcceptor {
@@ -29,7 +30,7 @@ impl<T: AsyncRead + AsyncWrite> RustlsAcceptor<T> {
} }
} }
impl<T> Clone for RustlsAcceptor<T> { impl<T, P> Clone for RustlsAcceptor<T, P> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
config: self.config.clone(), config: self.config.clone(),
@@ -38,14 +39,17 @@ impl<T> Clone for RustlsAcceptor<T> {
} }
} }
impl<T: AsyncRead + AsyncWrite> NewService<T> for RustlsAcceptor<T> { impl<T: AsyncRead + AsyncWrite, P> NewService<SrvConfig> for RustlsAcceptor<T, P> {
type Response = TlsStream<T, ServerSession>; type Request = Io<T, P>;
type Response = Io<TlsStream<T, ServerSession>, P>;
type Error = io::Error; type Error = io::Error;
type Service = RustlsAcceptorService<T>; type Service = RustlsAcceptorService<T, P>;
type InitError = (); type InitError = ();
type Future = FutureResult<Self::Service, Self::InitError>; type Future = FutureResult<Self::Service, Self::InitError>;
fn new_service(&self, _: &()) -> Self::Future { fn new_service(&self, cfg: &SrvConfig) -> Self::Future {
cfg.set_secure();
MAX_CONN_COUNTER.with(|conns| { MAX_CONN_COUNTER.with(|conns| {
ok(RustlsAcceptorService { ok(RustlsAcceptorService {
acceptor: self.config.clone().into(), acceptor: self.config.clone().into(),
@@ -56,16 +60,17 @@ impl<T: AsyncRead + AsyncWrite> NewService<T> for RustlsAcceptor<T> {
} }
} }
pub struct RustlsAcceptorService<T> { pub struct RustlsAcceptorService<T, P> {
acceptor: TlsAcceptor, acceptor: TlsAcceptor,
io: PhantomData<T>, io: PhantomData<(T, P)>,
conns: Counter, conns: Counter,
} }
impl<T: AsyncRead + AsyncWrite> Service<T> for RustlsAcceptorService<T> { impl<T: AsyncRead + AsyncWrite, P> Service for RustlsAcceptorService<T, P> {
type Response = TlsStream<T, ServerSession>; type Request = Io<T, P>;
type Response = Io<TlsStream<T, ServerSession>, P>;
type Error = io::Error; type Error = io::Error;
type Future = RustlsAcceptorServiceFut<T>; type Future = RustlsAcceptorServiceFut<T, P>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(&mut self) -> Poll<(), Self::Error> {
if self.conns.available() { if self.conns.available() {
@@ -75,27 +80,35 @@ impl<T: AsyncRead + AsyncWrite> Service<T> for RustlsAcceptorService<T> {
} }
} }
fn call(&mut self, req: T) -> Self::Future { fn call(&mut self, req: Self::Request) -> Self::Future {
let (io, params, _) = req.into_parts();
RustlsAcceptorServiceFut { RustlsAcceptorServiceFut {
_guard: self.conns.get(), _guard: self.conns.get(),
fut: self.acceptor.accept(req), fut: self.acceptor.accept(io),
params: Some(params),
} }
} }
} }
pub struct RustlsAcceptorServiceFut<T> pub struct RustlsAcceptorServiceFut<T, P>
where where
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
{ {
fut: Accept<T>, fut: Accept<T>,
params: Option<P>,
_guard: CounterGuard, _guard: CounterGuard,
} }
impl<T: AsyncRead + AsyncWrite> Future for RustlsAcceptorServiceFut<T> { impl<T: AsyncRead + AsyncWrite, P> Future for RustlsAcceptorServiceFut<T, P> {
type Item = TlsStream<T, ServerSession>; type Item = Io<TlsStream<T, ServerSession>, 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> {
self.fut.poll() let io = futures::try_ready!(self.fut.poll());
Ok(Async::Ready(Io::from_parts(
io,
self.params.take().unwrap(),
Protocol::Unknown,
)))
} }
} }

View File

@@ -0,0 +1,147 @@
use std::io::Read;
use std::sync::mpsc;
use std::{net, thread, time};
use actix_codec::{BytesCodec, Framed};
use actix_server::{Io, Server, ServerConfig};
use actix_service::{fn_cfg_factory, fn_service, IntoService};
use bytes::Bytes;
use futures::{Future, Sink};
use net2::TcpBuilder;
use tokio_tcp::TcpStream;
fn unused_addr() -> net::SocketAddr {
let addr: net::SocketAddr = "127.0.0.1:0".parse().unwrap();
let socket = TcpBuilder::new_v4().unwrap();
socket.bind(&addr).unwrap();
socket.reuse_address(true).unwrap();
let tcp = socket.to_tcp_listener().unwrap();
tcp.local_addr().unwrap()
}
#[test]
fn test_bind() {
let addr = unused_addr();
thread::spawn(move || {
Server::build()
.bind("test", addr, move || {
fn_cfg_factory(move |cfg: &ServerConfig| {
assert_eq!(cfg.local_addr(), addr);
Ok::<_, ()>((|_| Ok::<_, ()>(())).into_service())
})
})
.unwrap()
.run()
});
thread::sleep(time::Duration::from_millis(500));
assert!(net::TcpStream::connect(addr).is_ok());
}
#[test]
fn test_bind_no_config() {
let addr = unused_addr();
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let sys = actix_rt::System::new("test");
let srv = Server::build()
.bind("test", addr, move || fn_service(|_| Ok::<_, ()>(())))
.unwrap()
.start();
let _ = tx.send((srv, actix_rt::System::current()));
let _ = sys.run();
});
let (_, sys) = rx.recv().unwrap();
assert!(net::TcpStream::connect(addr).is_ok());
let _ = sys.stop();
}
#[test]
fn test_listen() {
let addr = unused_addr();
thread::spawn(move || {
let lst = net::TcpListener::bind(addr).unwrap();
Server::build()
.listen("test", lst, move || {
fn_cfg_factory(move |cfg: &ServerConfig| {
assert_eq!(cfg.local_addr(), addr);
Ok::<_, ()>((|_| Ok::<_, ()>(())).into_service())
})
})
.unwrap()
.run()
});
thread::sleep(time::Duration::from_millis(500));
assert!(net::TcpStream::connect(addr).is_ok());
}
#[test]
#[cfg(unix)]
fn test_start() {
let addr = unused_addr();
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let sys = actix_rt::System::new("test");
let srv = Server::build()
.backlog(100)
.bind("test", addr, move || {
fn_cfg_factory(move |cfg: &ServerConfig| {
assert_eq!(cfg.local_addr(), addr);
Ok::<_, ()>(
(|io: Io<TcpStream>| {
Framed::new(io.into_parts().0, BytesCodec)
.send(Bytes::from_static(b"test"))
.then(|_| Ok::<_, ()>(()))
})
.into_service(),
)
})
})
.unwrap()
.start();
let _ = tx.send((srv, actix_rt::System::current()));
let _ = sys.run();
});
let (srv, sys) = rx.recv().unwrap();
let mut buf = [0u8; 4];
let mut conn = net::TcpStream::connect(addr).unwrap();
let _ = conn.read_exact(&mut buf);
assert_eq!(buf, b"test"[..]);
// pause
let _ = srv.pause();
thread::sleep(time::Duration::from_millis(200));
let mut conn = net::TcpStream::connect(addr).unwrap();
conn.set_read_timeout(Some(time::Duration::from_millis(100)))
.unwrap();
let res = conn.read_exact(&mut buf);
assert!(res.is_err());
// resume
let _ = srv.resume();
thread::sleep(time::Duration::from_millis(100));
assert!(net::TcpStream::connect(addr).is_ok());
assert!(net::TcpStream::connect(addr).is_ok());
assert!(net::TcpStream::connect(addr).is_ok());
let mut buf = [0u8; 4];
let mut conn = net::TcpStream::connect(addr).unwrap();
let _ = conn.read_exact(&mut buf);
assert_eq!(buf, b"test"[..]);
// stop
let _ = srv.stop(false);
thread::sleep(time::Duration::from_millis(100));
assert!(net::TcpStream::connect(addr).is_err());
thread::sleep(time::Duration::from_millis(100));
let _ = sys.stop();
}

View File

@@ -1,11 +1,29 @@
# Changes # Changes
## [0.3.2] - 2019-03-xx ## [0.3.4] - 2019-03-12
### Added
* Add `Transform::from_err()` combinator
* Add `apply_fn` helper
* Add `apply_fn_factory` helper
* Add `apply_transform` helper
* Add `apply_cfg` helper
## [0.3.3] - 2019-03-09
### Added ### Added
* Add `ApplyTransform` new service for transform and new service. * Add `ApplyTransform` new service for transform and new service.
* Add `NewService::apply_cfg()` combinator, allows to use
nested `NewService` with different config parameter.
### Changed ### Changed
* Revert IntoFuture change * Revert IntoFuture change

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "actix-service" name = "actix-service"
version = "0.3.2" version = "0.3.4"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"] authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix Service" description = "Actix Service"
keywords = ["network", "framework", "async", "futures"] keywords = ["network", "framework", "async", "futures"]
@@ -27,4 +27,4 @@ futures = "0.1.24"
void = "1.0.2" void = "1.0.2"
[dev-dependencies] [dev-dependencies]
actix-rt = "0.1" actix-rt = "0.2"

View File

@@ -1,4 +1,6 @@
use futures::{try_ready, Async, Future, Poll}; use std::marker::PhantomData;
use futures::{Async, Future, Poll};
use super::{IntoNewService, NewService, Service}; use super::{IntoNewService, NewService, Service};
use crate::cell::Cell; use crate::cell::Cell;
@@ -14,10 +16,10 @@ pub struct AndThen<A, B> {
impl<A, B> AndThen<A, B> { impl<A, B> AndThen<A, B> {
/// Create new `AndThen` combinator /// Create new `AndThen` combinator
pub fn new<R>(a: A, b: B) -> Self pub fn new(a: A, b: B) -> Self
where where
A: Service<R>, A: Service,
B: Service<A::Response, Error = A::Error>, B: Service<Request = A::Response, Error = A::Error>,
{ {
Self { a, b: Cell::new(b) } Self { a, b: Cell::new(b) }
} }
@@ -35,39 +37,44 @@ where
} }
} }
impl<A, B, R> Service<R> for AndThen<A, B> impl<A, B> Service for AndThen<A, B>
where where
A: Service<R>, A: Service,
B: Service<A::Response, Error = A::Error>, B: Service<Request = A::Response, Error = A::Error>,
{ {
type Request = A::Request;
type Response = B::Response; type Response = B::Response;
type Error = A::Error; type Error = A::Error;
type Future = AndThenFuture<A, B, R>; type Future = AndThenFuture<A, B>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(&mut self) -> Poll<(), Self::Error> {
try_ready!(self.a.poll_ready()); let not_ready = self.a.poll_ready()?.is_not_ready();
self.b.get_mut().poll_ready() if self.b.get_mut().poll_ready()?.is_not_ready() || not_ready {
Ok(Async::NotReady)
} else {
Ok(Async::Ready(()))
}
} }
fn call(&mut self, req: R) -> Self::Future { fn call(&mut self, req: A::Request) -> Self::Future {
AndThenFuture::new(self.a.call(req), self.b.clone()) AndThenFuture::new(self.a.call(req), self.b.clone())
} }
} }
pub struct AndThenFuture<A, B, R> pub struct AndThenFuture<A, B>
where where
A: Service<R>, A: Service,
B: Service<A::Response, Error = A::Error>, B: Service<Request = A::Response, Error = A::Error>,
{ {
b: Cell<B>, b: Cell<B>,
fut_b: Option<B::Future>, fut_b: Option<B::Future>,
fut_a: Option<A::Future>, fut_a: Option<A::Future>,
} }
impl<A, B, R> AndThenFuture<A, B, R> impl<A, B> AndThenFuture<A, B>
where where
A: Service<R>, A: Service,
B: Service<A::Response, Error = A::Error>, B: Service<Request = A::Response, Error = A::Error>,
{ {
fn new(a: A::Future, b: Cell<B>) -> Self { fn new(a: A::Future, b: Cell<B>) -> Self {
AndThenFuture { AndThenFuture {
@@ -78,10 +85,10 @@ where
} }
} }
impl<A, B, R> Future for AndThenFuture<A, B, R> impl<A, B> Future for AndThenFuture<A, B>
where where
A: Service<R>, A: Service,
B: Service<A::Response, Error = A::Error>, B: Service<Request = A::Response, Error = A::Error>,
{ {
type Item = B::Response; type Item = B::Response;
type Error = A::Error; type Error = A::Error;
@@ -104,59 +111,67 @@ where
} }
/// `AndThenNewService` new service combinator /// `AndThenNewService` new service combinator
pub struct AndThenNewService<A, B> { pub struct AndThenNewService<A, B, C>
where
A: NewService<C>,
B: NewService<C, Request = A::Response, Error = A::Error, InitError = A::InitError>,
{
a: A, a: A,
b: B, b: B,
_t: PhantomData<C>,
} }
impl<A, B> AndThenNewService<A, B> { impl<A, B, C> AndThenNewService<A, B, C>
where
A: NewService<C>,
B: NewService<C, Request = A::Response, Error = A::Error, InitError = A::InitError>,
{
/// Create new `AndThen` combinator /// Create new `AndThen` combinator
pub fn new<R, C, F: IntoNewService<B, A::Response, C>>(a: A, f: F) -> Self pub fn new<F: IntoNewService<B, C>>(a: A, f: F) -> Self {
where
A: NewService<R, C>,
B: NewService<A::Response, C, Error = A::Error, InitError = A::InitError>,
{
Self { Self {
a, a,
b: f.into_new_service(), b: f.into_new_service(),
_t: PhantomData,
} }
} }
} }
impl<A, B, R, C> NewService<R, C> for AndThenNewService<A, B> impl<A, B, C> NewService<C> for AndThenNewService<A, B, C>
where where
A: NewService<R, C>, A: NewService<C>,
B: NewService<A::Response, C, Error = A::Error, InitError = A::InitError>, B: NewService<C, Request = A::Response, Error = A::Error, InitError = A::InitError>,
{ {
type Request = A::Request;
type Response = B::Response; type Response = B::Response;
type Error = A::Error; type Error = A::Error;
type Service = AndThen<A::Service, B::Service>; type Service = AndThen<A::Service, B::Service>;
type InitError = A::InitError; type InitError = A::InitError;
type Future = AndThenNewServiceFuture<A, B, R, C>; type Future = AndThenNewServiceFuture<A, B, C>;
fn new_service(&self, cfg: &C) -> Self::Future { fn new_service(&self, cfg: &C) -> Self::Future {
AndThenNewServiceFuture::new(self.a.new_service(cfg), self.b.new_service(cfg)) AndThenNewServiceFuture::new(self.a.new_service(cfg), self.b.new_service(cfg))
} }
} }
impl<A, B> Clone for AndThenNewService<A, B> impl<A, B, C> Clone for AndThenNewService<A, B, C>
where where
A: Clone, A: NewService<C> + Clone,
B: Clone, B: NewService<C, Request = A::Response, Error = A::Error, InitError = A::InitError> + Clone,
{ {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
a: self.a.clone(), a: self.a.clone(),
b: self.b.clone(), b: self.b.clone(),
_t: PhantomData,
} }
} }
} }
pub struct AndThenNewServiceFuture<A, B, R, C> pub struct AndThenNewServiceFuture<A, B, C>
where where
A: NewService<R, C>, A: NewService<C>,
B: NewService<A::Response, C>, B: NewService<C, Request = A::Response>,
{ {
fut_b: B::Future, fut_b: B::Future,
fut_a: A::Future, fut_a: A::Future,
@@ -164,10 +179,10 @@ where
b: Option<B::Service>, b: Option<B::Service>,
} }
impl<A, B, R, C> AndThenNewServiceFuture<A, B, R, C> impl<A, B, C> AndThenNewServiceFuture<A, B, C>
where where
A: NewService<R, C>, A: NewService<C>,
B: NewService<A::Response, C, Error = A::Error, InitError = A::InitError>, B: NewService<C, Request = A::Response>,
{ {
fn new(fut_a: A::Future, fut_b: B::Future) -> Self { fn new(fut_a: A::Future, fut_b: B::Future) -> Self {
AndThenNewServiceFuture { AndThenNewServiceFuture {
@@ -179,10 +194,10 @@ where
} }
} }
impl<A, B, R, C> Future for AndThenNewServiceFuture<A, B, R, C> impl<A, B, C> Future for AndThenNewServiceFuture<A, B, C>
where where
A: NewService<R, C>, A: NewService<C>,
B: NewService<A::Response, C, Error = A::Error, InitError = A::InitError>, B: NewService<C, Request = A::Response, Error = A::Error, InitError = A::InitError>,
{ {
type Item = AndThen<A::Service, B::Service>; type Item = AndThen<A::Service, B::Service>;
type Error = A::InitError; type Error = A::InitError;
@@ -222,7 +237,8 @@ mod tests {
use crate::{NewService, Service, ServiceExt}; use crate::{NewService, Service, ServiceExt};
struct Srv1(Rc<Cell<usize>>); struct Srv1(Rc<Cell<usize>>);
impl Service<&'static str> for Srv1 { impl Service for Srv1 {
type Request = &'static str;
type Response = &'static str; type Response = &'static str;
type Error = (); type Error = ();
type Future = FutureResult<Self::Response, ()>; type Future = FutureResult<Self::Response, ()>;
@@ -240,7 +256,8 @@ mod tests {
#[derive(Clone)] #[derive(Clone)]
struct Srv2(Rc<Cell<usize>>); struct Srv2(Rc<Cell<usize>>);
impl Service<&'static str> for Srv2 { impl Service for Srv2 {
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 = FutureResult<Self::Response, ()>;

View File

@@ -1,4 +1,3 @@
use std::marker::PhantomData;
use std::rc::Rc; use std::rc::Rc;
use futures::{Async, Future, Poll}; use futures::{Async, Future, Poll};
@@ -8,22 +7,22 @@ use crate::from_err::FromErr;
use crate::{NewService, Transform}; use crate::{NewService, Transform};
/// `Apply` new service combinator /// `Apply` new service combinator
pub struct AndThenTransform<T, A, B, BR> { pub struct AndThenTransform<T, A, B, C> {
a: A, a: A,
b: B, b: B,
t: Rc<T>, t: Rc<T>,
_t: PhantomData<BR>, _t: std::marker::PhantomData<C>,
} }
impl<T, A, B, BR> AndThenTransform<T, A, B, BR> { impl<T, A, B, C> AndThenTransform<T, A, B, C>
where
A: NewService<C>,
B: NewService<C, InitError = A::InitError>,
T: Transform<B::Service, Request = A::Response, InitError = A::InitError>,
T::Error: From<A::Error>,
{
/// Create new `ApplyNewService` new service instance /// Create new `ApplyNewService` new service instance
pub fn new<AR, C>(t: T, a: A, b: B) -> Self pub fn new(t: T, a: A, b: B) -> Self {
where
A: NewService<AR, C>,
B: NewService<BR, C, InitError = A::InitError>,
T: Transform<B::Service, A::Response, InitError = A::InitError>,
T::Error: From<A::Error>,
{
Self { Self {
a, a,
b, b,
@@ -33,7 +32,7 @@ impl<T, A, B, BR> AndThenTransform<T, A, B, BR> {
} }
} }
impl<T, A, B, BR> Clone for AndThenTransform<T, A, B, BR> impl<T, A, B, C> Clone for AndThenTransform<T, A, B, C>
where where
A: Clone, A: Clone,
B: Clone, B: Clone,
@@ -48,19 +47,20 @@ where
} }
} }
impl<T, A, B, AR, BR, C> NewService<AR, C> for AndThenTransform<T, A, B, BR> impl<T, A, B, C> NewService<C> for AndThenTransform<T, A, B, C>
where where
A: NewService<AR, C>, A: NewService<C>,
B: NewService<BR, C, InitError = A::InitError>, B: NewService<C, InitError = A::InitError>,
T: Transform<B::Service, 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 Request = A::Request;
type Response = T::Response; type Response = T::Response;
type Error = T::Error; type Error = T::Error;
type InitError = T::InitError; type InitError = T::InitError;
type Service = AndThen<FromErr<A::Service, T::Error>, T::Transform>; type Service = AndThen<FromErr<A::Service, T::Error>, T::Transform>;
type Future = AndThenTransformFuture<T, A, B, AR, BR, C>; type Future = AndThenTransformFuture<T, A, B, C>;
fn new_service(&self, cfg: &C) -> Self::Future { fn new_service(&self, cfg: &C) -> Self::Future {
AndThenTransformFuture { AndThenTransformFuture {
@@ -74,11 +74,11 @@ where
} }
} }
pub struct AndThenTransformFuture<T, A, B, AR, BR, C> pub struct AndThenTransformFuture<T, A, B, C>
where where
A: NewService<AR, C>, A: NewService<C>,
B: NewService<BR, C, InitError = A::InitError>, B: NewService<C, InitError = A::InitError>,
T: Transform<B::Service, 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>,
{ {
fut_a: A::Future, fut_a: A::Future,
@@ -89,11 +89,11 @@ where
t_cell: Rc<T>, t_cell: Rc<T>,
} }
impl<T, A, B, AR, BR, C> Future for AndThenTransformFuture<T, A, B, AR, BR, C> impl<T, A, B, C> Future for AndThenTransformFuture<T, A, B, C>
where where
A: NewService<AR, C>, A: NewService<C>,
B: NewService<BR, C, InitError = A::InitError>, B: NewService<C, InitError = A::InitError>,
T: Transform<B::Service, 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 Item = AndThen<FromErr<A::Service, T::Error>, T::Transform>;
@@ -138,7 +138,8 @@ mod tests {
#[derive(Clone)] #[derive(Clone)]
struct Srv; struct Srv;
impl Service<()> for Srv { impl Service for Srv {
type Request = ();
type Response = (); type Response = ();
type Error = (); type Error = ();
type Future = FutureResult<(), ()>; type Future = FutureResult<(), ()>;

View File

@@ -1,28 +1,35 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use futures::{try_ready, Async, Future, IntoFuture, Poll}; use futures::{Async, Future, IntoFuture, Poll};
use super::{IntoNewService, IntoService, NewService, Service}; use super::{IntoNewService, IntoService, NewService, Service};
use crate::cell::Cell; use crate::cell::Cell;
/// `Apply` service combinator /// `Apply` service combinator
pub struct AndThenApply<A, B, F, Out, AReq, BReq> { pub struct AndThenApply<A, B, F, Out>
where
A: Service,
B: Service<Error = A::Error>,
F: FnMut(A::Response, &mut B) -> Out,
Out: IntoFuture,
Out::Error: Into<A::Error>,
{
a: A, a: A,
b: Cell<B>, b: Cell<B>,
f: Cell<F>, f: Cell<F>,
r: PhantomData<(Out, AReq, BReq)>, r: PhantomData<(Out,)>,
} }
impl<A, B, F, Out, AReq, BReq> AndThenApply<A, B, F, Out, AReq, BReq> impl<A, B, F, Out> AndThenApply<A, B, F, Out>
where where
A: Service<AReq>, A: Service,
B: Service<BReq, Error = A::Error>, B: Service<Error = A::Error>,
F: FnMut(A::Response, &mut B) -> Out, F: FnMut(A::Response, &mut B) -> Out,
Out: IntoFuture, Out: IntoFuture,
Out::Error: Into<A::Error>, Out::Error: Into<A::Error>,
{ {
/// Create new `Apply` combinator /// Create new `Apply` combinator
pub fn new<A1: IntoService<A, AReq>, B1: IntoService<B, BReq>>(a: A1, b: B1, f: F) -> Self { pub fn new<A1: IntoService<A>, B1: IntoService<B>>(a: A1, b: B1, f: F) -> Self {
Self { Self {
f: Cell::new(f), f: Cell::new(f),
a: a.into_service(), a: a.into_service(),
@@ -32,9 +39,13 @@ where
} }
} }
impl<A, B, F, Out, AReq, BReq> Clone for AndThenApply<A, B, F, Out, AReq, BReq> impl<A, B, F, Out> Clone for AndThenApply<A, B, F, Out>
where where
A: Clone, A: Service + Clone,
B: Service<Error = A::Error>,
F: FnMut(A::Response, &mut B) -> Out,
Out: IntoFuture,
Out::Error: Into<A::Error>,
{ {
fn clone(&self) -> Self { fn clone(&self) -> Self {
AndThenApply { AndThenApply {
@@ -46,38 +57,42 @@ where
} }
} }
impl<A, B, F, Out, AReq, BReq> Service<AReq> for AndThenApply<A, B, F, Out, AReq, BReq> impl<A, B, F, Out> Service for AndThenApply<A, B, F, Out>
where where
A: Service<AReq>, A: Service,
B: Service<BReq, Error = A::Error>, B: Service<Error = A::Error>,
F: FnMut(A::Response, &mut B) -> Out, F: FnMut(A::Response, &mut B) -> Out,
Out: IntoFuture, Out: IntoFuture,
Out::Error: Into<A::Error>, Out::Error: Into<A::Error>,
{ {
type Request = A::Request;
type Response = Out::Item; type Response = Out::Item;
type Error = A::Error; type Error = A::Error;
type Future = AndThenApplyFuture<A, B, F, Out, AReq, BReq>; type Future = AndThenApplyFuture<A, B, F, Out>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(&mut self) -> Poll<(), Self::Error> {
try_ready!(self.a.poll_ready()); let not_ready = self.a.poll_ready()?.is_not_ready();
self.b.get_mut().poll_ready() if self.b.get_mut().poll_ready()?.is_not_ready() || not_ready {
Ok(Async::NotReady)
} else {
Ok(Async::Ready(()))
}
} }
fn call(&mut self, req: AReq) -> Self::Future { fn call(&mut self, req: A::Request) -> Self::Future {
AndThenApplyFuture { AndThenApplyFuture {
b: self.b.clone(), b: self.b.clone(),
f: self.f.clone(), f: self.f.clone(),
fut_b: None, fut_b: None,
fut_a: Some(self.a.call(req)), fut_a: Some(self.a.call(req)),
_t: PhantomData,
} }
} }
} }
pub struct AndThenApplyFuture<A, B, F, Out, AReq, BReq> pub struct AndThenApplyFuture<A, B, F, Out>
where where
A: Service<AReq>, A: Service,
B: Service<BReq, Error = A::Error>, B: Service<Error = A::Error>,
F: FnMut(A::Response, &mut B) -> Out, F: FnMut(A::Response, &mut B) -> Out,
Out: IntoFuture, Out: IntoFuture,
Out::Error: Into<A::Error>, Out::Error: Into<A::Error>,
@@ -86,13 +101,12 @@ where
f: Cell<F>, f: Cell<F>,
fut_a: Option<A::Future>, fut_a: Option<A::Future>,
fut_b: Option<Out::Future>, fut_b: Option<Out::Future>,
_t: PhantomData<(AReq, BReq)>,
} }
impl<A, B, F, Out, AReq, BReq> Future for AndThenApplyFuture<A, B, F, Out, AReq, BReq> impl<A, B, F, Out> Future for AndThenApplyFuture<A, B, F, Out>
where where
A: Service<AReq>, A: Service,
B: Service<BReq, Error = A::Error>, B: Service<Error = A::Error>,
F: FnMut(A::Response, &mut B) -> Out, F: FnMut(A::Response, &mut B) -> Out,
Out: IntoFuture, Out: IntoFuture,
Out::Error: Into<A::Error>, Out::Error: Into<A::Error>,
@@ -119,23 +133,23 @@ where
} }
/// `ApplyNewService` new service combinator /// `ApplyNewService` new service combinator
pub struct AndThenApplyNewService<A, B, F, Out, AReq, BReq, Cfg> { pub struct AndThenApplyNewService<A, B, F, Out, Cfg> {
a: A, a: A,
b: B, b: B,
f: Cell<F>, f: Cell<F>,
r: PhantomData<(Out, AReq, BReq, Cfg)>, r: PhantomData<(Out, Cfg)>,
} }
impl<A, B, F, Out, AReq, BReq, Cfg> AndThenApplyNewService<A, B, F, Out, AReq, BReq, Cfg> impl<A, B, F, Out, Cfg> AndThenApplyNewService<A, B, F, Out, Cfg>
where where
A: NewService<AReq, Cfg>, A: NewService<Cfg>,
B: NewService<BReq, Cfg, Error = A::Error, InitError = A::InitError>, B: NewService<Cfg, Error = A::Error, InitError = A::InitError>,
F: FnMut(A::Response, &mut B::Service) -> Out, F: FnMut(A::Response, &mut B::Service) -> Out,
Out: IntoFuture, Out: IntoFuture,
Out::Error: Into<A::Error>, Out::Error: Into<A::Error>,
{ {
/// Create new `ApplyNewService` new service instance /// Create new `ApplyNewService` new service instance
pub fn new<A1: IntoNewService<A, AReq, Cfg>, B1: IntoNewService<B, BReq, Cfg>>( pub fn new<A1: IntoNewService<A, Cfg>, B1: IntoNewService<B, Cfg>>(
a: A1, a: A1,
b: B1, b: B1,
f: F, f: F,
@@ -149,8 +163,7 @@ where
} }
} }
impl<A, B, F, Out, AReq, BReq, Cfg> Clone impl<A, B, F, Out, Cfg> Clone for AndThenApplyNewService<A, B, F, Out, Cfg>
for AndThenApplyNewService<A, B, F, Out, AReq, BReq, Cfg>
where where
A: Clone, A: Clone,
B: Clone, B: Clone,
@@ -165,21 +178,21 @@ where
} }
} }
impl<A, B, F, Out, AReq, BReq, Cfg> NewService<AReq, Cfg> impl<A, B, F, Out, Cfg> NewService<Cfg> for AndThenApplyNewService<A, B, F, Out, Cfg>
for AndThenApplyNewService<A, B, F, Out, AReq, BReq, Cfg>
where where
A: NewService<AReq, Cfg>, A: NewService<Cfg>,
B: NewService<BReq, Cfg, Error = A::Error, InitError = A::InitError>, B: NewService<Cfg, Error = A::Error, InitError = A::InitError>,
F: FnMut(A::Response, &mut B::Service) -> Out, F: FnMut(A::Response, &mut B::Service) -> Out,
Out: IntoFuture, Out: IntoFuture,
Out::Error: Into<A::Error>, Out::Error: Into<A::Error>,
{ {
type Request = A::Request;
type Response = Out::Item; type Response = Out::Item;
type Error = A::Error; type Error = A::Error;
type Service = AndThenApply<A::Service, B::Service, F, Out, AReq, BReq>; type Service = AndThenApply<A::Service, B::Service, F, Out>;
type InitError = A::InitError; type InitError = A::InitError;
type Future = AndThenApplyNewServiceFuture<A, B, F, Out, AReq, BReq, Cfg>; type Future = AndThenApplyNewServiceFuture<A, B, F, Out, Cfg>;
fn new_service(&self, cfg: &Cfg) -> Self::Future { fn new_service(&self, cfg: &Cfg) -> Self::Future {
AndThenApplyNewServiceFuture { AndThenApplyNewServiceFuture {
@@ -192,10 +205,10 @@ where
} }
} }
pub struct AndThenApplyNewServiceFuture<A, B, F, Out, AReq, BReq, Cfg> pub struct AndThenApplyNewServiceFuture<A, B, F, Out, Cfg>
where where
A: NewService<AReq, Cfg>, A: NewService<Cfg>,
B: NewService<BReq, Cfg, Error = A::Error, InitError = A::InitError>, B: NewService<Cfg, Error = A::Error, InitError = A::InitError>,
F: FnMut(A::Response, &mut B::Service) -> Out, F: FnMut(A::Response, &mut B::Service) -> Out,
Out: IntoFuture, Out: IntoFuture,
Out::Error: Into<A::Error>, Out::Error: Into<A::Error>,
@@ -207,16 +220,15 @@ where
b: Option<B::Service>, b: Option<B::Service>,
} }
impl<A, B, F, Out, AReq, BReq, Cfg> Future impl<A, B, F, Out, Cfg> Future for AndThenApplyNewServiceFuture<A, B, F, Out, Cfg>
for AndThenApplyNewServiceFuture<A, B, F, Out, AReq, BReq, Cfg>
where where
A: NewService<AReq, Cfg>, A: NewService<Cfg>,
B: NewService<BReq, Cfg, Error = A::Error, InitError = A::InitError>, B: NewService<Cfg, Error = A::Error, InitError = A::InitError>,
F: FnMut(A::Response, &mut B::Service) -> Out, F: FnMut(A::Response, &mut B::Service) -> Out,
Out: IntoFuture, Out: IntoFuture,
Out::Error: Into<A::Error>, Out::Error: Into<A::Error>,
{ {
type Item = AndThenApply<A::Service, B::Service, F, Out, AReq, BReq>; type Item = AndThenApply<A::Service, B::Service, F, Out>;
type Error = A::InitError; type Error = A::InitError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
@@ -255,7 +267,8 @@ mod tests {
#[derive(Clone)] #[derive(Clone)]
struct Srv; struct Srv;
impl Service<()> for Srv { impl Service for Srv {
type Request = ();
type Response = (); type Response = ();
type Error = (); type Error = ();
type Future = FutureResult<(), ()>; type Future = FutureResult<(), ()>;

View File

@@ -4,24 +4,53 @@ use futures::{Async, Future, IntoFuture, Poll};
use super::{IntoNewService, IntoService, NewService, Service}; use super::{IntoNewService, IntoService, NewService, Service};
/// `Apply` service combinator /// Apply tranform function to a service
pub struct Apply<T, R, F, In, Out> { pub fn apply_fn<T, F, In, Out, U>(service: U, f: F) -> Apply<T, F, In, Out>
service: T, where
f: F, T: Service,
r: PhantomData<(R, In, Out)>, F: FnMut(In, &mut T) -> Out,
Out: IntoFuture,
Out::Error: From<T::Error>,
U: IntoService<T>,
{
Apply::new(service.into_service(), f)
} }
impl<T, R, F, In, Out> Apply<T, R, F, In, Out> /// Create fractory for `apply_fn` service.
pub fn apply_fn_factory<T, F, In, Out, Cfg, U>(
service: U,
f: F,
) -> ApplyNewService<T, F, In, Out, Cfg>
where where
T: NewService<Cfg>,
F: FnMut(In, &mut T::Service) -> Out + Clone,
Out: IntoFuture,
Out::Error: From<T::Error>,
U: IntoNewService<T, Cfg>,
{
ApplyNewService::new(service.into_new_service(), f)
}
#[doc(hidden)]
/// `Apply` service combinator
pub struct Apply<T, F, In, Out>
where
T: Service,
{
service: T,
f: F,
r: PhantomData<(In, Out)>,
}
impl<T, F, In, Out> Apply<T, F, In, Out>
where
T: Service,
F: FnMut(In, &mut T) -> Out, F: FnMut(In, &mut T) -> Out,
Out: IntoFuture,
Out::Error: From<T::Error>,
{ {
/// Create new `Apply` combinator /// Create new `Apply` combinator
pub fn new<I: IntoService<T, R>>(service: I, f: F) -> Self pub fn new<I: IntoService<T>>(service: I, f: F) -> Self {
where
T: Service<R>,
Out: IntoFuture,
Out::Error: From<T::Error>,
{
Self { Self {
service: service.into_service(), service: service.into_service(),
f, f,
@@ -30,9 +59,9 @@ where
} }
} }
impl<T, R, F, In, Out> Clone for Apply<T, R, F, In, Out> impl<T, F, In, Out> Clone for Apply<T, F, In, Out>
where where
T: Clone, T: Service + Clone,
F: Clone, F: Clone,
{ {
fn clone(&self) -> Self { fn clone(&self) -> Self {
@@ -44,13 +73,14 @@ where
} }
} }
impl<T, R, F, In, Out> Service<In> for Apply<T, R, F, In, Out> impl<T, F, In, Out> Service for Apply<T, F, In, Out>
where where
T: Service<R>, T: Service,
F: FnMut(In, &mut T) -> Out, F: FnMut(In, &mut T) -> Out,
Out: IntoFuture, Out: IntoFuture,
Out::Error: From<T::Error>, Out::Error: From<T::Error>,
{ {
type Request = In;
type Response = Out::Item; type Response = Out::Item;
type Error = Out::Error; type Error = Out::Error;
type Future = Out::Future; type Future = Out::Future;
@@ -65,21 +95,24 @@ where
} }
/// `ApplyNewService` new service combinator /// `ApplyNewService` new service combinator
pub struct ApplyNewService<T, F, In, Out, Req> { pub struct ApplyNewService<T, F, In, Out, Cfg>
where
T: NewService<Cfg>,
{
service: T, service: T,
f: F, f: F,
r: PhantomData<(In, Out, Req)>, r: PhantomData<(In, Out, Cfg)>,
} }
impl<T, F, In, Out, Req> ApplyNewService<T, F, In, Out, Req> { impl<T, F, In, Out, Cfg> ApplyNewService<T, F, In, Out, Cfg>
where
T: NewService<Cfg>,
F: FnMut(In, &mut T::Service) -> Out + Clone,
Out: IntoFuture,
Out::Error: From<T::Error>,
{
/// Create new `ApplyNewService` new service instance /// Create new `ApplyNewService` new service instance
pub fn new<Cfg, F1: IntoNewService<T, Req, Cfg>>(service: F1, f: F) -> Self pub fn new<F1: IntoNewService<T, Cfg>>(service: F1, f: F) -> Self {
where
T: NewService<Req, Cfg>,
F: FnMut(In, &mut T::Service) -> Out + Clone,
Out: IntoFuture,
Out::Error: From<T::Error>,
{
Self { Self {
f, f,
service: service.into_new_service(), service: service.into_new_service(),
@@ -88,10 +121,11 @@ impl<T, F, In, Out, Req> ApplyNewService<T, F, In, Out, Req> {
} }
} }
impl<T, F, In, Out, Req> Clone for ApplyNewService<T, F, In, Out, Req> impl<T, F, In, Out, Cfg> Clone for ApplyNewService<T, F, In, Out, Cfg>
where where
T: Clone, T: NewService<Cfg> + Clone,
F: Clone, F: FnMut(In, &mut T::Service) -> Out + Clone,
Out: IntoFuture,
{ {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
@@ -102,28 +136,29 @@ where
} }
} }
impl<T, F, In, Out, Req, Cfg> NewService<In, Cfg> for ApplyNewService<T, F, In, Out, Req> impl<T, F, In, Out, Cfg> NewService<Cfg> for ApplyNewService<T, F, In, Out, Cfg>
where where
T: NewService<Req, Cfg>, T: NewService<Cfg>,
F: FnMut(In, &mut T::Service) -> Out + Clone, F: FnMut(In, &mut T::Service) -> Out + Clone,
Out: IntoFuture, Out: IntoFuture,
Out::Error: From<T::Error>, Out::Error: From<T::Error>,
{ {
type Request = In;
type Response = Out::Item; type Response = Out::Item;
type Error = Out::Error; type Error = Out::Error;
type Service = Apply<T::Service, Req, F, In, Out>; type Service = Apply<T::Service, F, In, Out>;
type InitError = T::InitError; type InitError = T::InitError;
type Future = ApplyNewServiceFuture<T, F, In, Out, Req, Cfg>; type Future = ApplyNewServiceFuture<T, F, In, Out, Cfg>;
fn new_service(&self, cfg: &Cfg) -> Self::Future { fn new_service(&self, cfg: &Cfg) -> Self::Future {
ApplyNewServiceFuture::new(self.service.new_service(cfg), self.f.clone()) ApplyNewServiceFuture::new(self.service.new_service(cfg), self.f.clone())
} }
} }
pub struct ApplyNewServiceFuture<T, F, In, Out, Req, Cfg> pub struct ApplyNewServiceFuture<T, F, In, Out, Cfg>
where where
T: NewService<Req, Cfg>, T: NewService<Cfg>,
F: FnMut(In, &mut T::Service) -> Out + Clone, F: FnMut(In, &mut T::Service) -> Out + Clone,
Out: IntoFuture, Out: IntoFuture,
{ {
@@ -132,9 +167,9 @@ where
r: PhantomData<(In, Out)>, r: PhantomData<(In, Out)>,
} }
impl<T, F, In, Out, Req, Cfg> ApplyNewServiceFuture<T, F, In, Out, Req, Cfg> impl<T, F, In, Out, Cfg> ApplyNewServiceFuture<T, F, In, Out, Cfg>
where where
T: NewService<Req, Cfg>, T: NewService<Cfg>,
F: FnMut(In, &mut T::Service) -> Out + Clone, F: FnMut(In, &mut T::Service) -> Out + Clone,
Out: IntoFuture, Out: IntoFuture,
{ {
@@ -147,14 +182,14 @@ where
} }
} }
impl<T, F, In, Out, Req, Cfg> Future for ApplyNewServiceFuture<T, F, In, Out, Req, Cfg> impl<T, F, In, Out, Cfg> Future for ApplyNewServiceFuture<T, F, In, Out, Cfg>
where where
T: NewService<Req, Cfg>, T: NewService<Cfg>,
F: FnMut(In, &mut T::Service) -> Out + Clone, F: FnMut(In, &mut T::Service) -> Out + Clone,
Out: IntoFuture, Out: IntoFuture,
Out::Error: From<T::Error>, Out::Error: From<T::Error>,
{ {
type Item = Apply<T::Service, Req, F, In, Out>; type Item = Apply<T::Service, F, In, Out>;
type Error = T::InitError; type Error = T::InitError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
@@ -176,7 +211,8 @@ mod tests {
#[derive(Clone)] #[derive(Clone)]
struct Srv; struct Srv;
impl Service<()> for Srv { impl Service for Srv {
type Request = ();
type Response = (); type Response = ();
type Error = (); type Error = ();
type Future = FutureResult<(), ()>; type Future = FutureResult<(), ()>;

View File

@@ -0,0 +1,112 @@
use std::marker::PhantomData;
use crate::{IntoNewService, NewService};
/// Create new ApplyConfig` service factory combinator
pub fn apply_cfg<F, S, C1, C2, U>(f: F, service: U) -> ApplyConfig<F, S, C1, C2>
where
S: NewService<C2>,
F: Fn(&C1) -> C2,
U: IntoNewService<S, C2>,
{
ApplyConfig::new(service.into_new_service(), f)
}
/// `ApplyConfig` service factory combinator
pub struct ApplyConfig<F, S, C1, C2> {
s: S,
f: F,
r: PhantomData<(C1, C2)>,
}
impl<F, S, C1, C2> ApplyConfig<F, S, C1, C2>
where
S: NewService<C2>,
F: Fn(&C1) -> C2,
{
/// Create new ApplyConfig` service factory combinator
pub fn new<U: IntoNewService<S, C2>>(a: U, f: F) -> Self {
Self {
f,
s: a.into_new_service(),
r: PhantomData,
}
}
}
impl<F, S, C1, C2> Clone for ApplyConfig<F, S, C1, C2>
where
S: Clone,
F: Clone,
{
fn clone(&self) -> Self {
Self {
s: self.s.clone(),
f: self.f.clone(),
r: PhantomData,
}
}
}
impl<F, S, C1, C2> NewService<C1> for ApplyConfig<F, S, C1, C2>
where
S: NewService<C2>,
F: Fn(&C1) -> C2,
{
type Request = S::Request;
type Response = S::Response;
type Error = S::Error;
type Service = S::Service;
type InitError = S::InitError;
type Future = S::Future;
fn new_service(&self, cfg: &C1) -> Self::Future {
let cfg2 = (self.f)(cfg);
self.s.new_service(&cfg2)
}
}
#[cfg(test)]
mod tests {
use futures::future::{ok, FutureResult};
use futures::{Async, Future, Poll};
use crate::{fn_cfg_factory, NewService, Service};
#[derive(Clone)]
struct Srv;
impl Service for Srv {
type Request = ();
type Response = ();
type Error = ();
type Future = FutureResult<(), ()>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
Ok(Async::Ready(()))
}
fn call(&mut self, _: ()) -> Self::Future {
ok(())
}
}
#[test]
fn test_new_service() {
let new_srv = fn_cfg_factory(|_: &usize| Ok::<_, ()>(Srv)).apply_cfg(
fn_cfg_factory(|s: &String| {
assert_eq!(s, "test");
Ok::<_, ()>(Srv)
}),
|cfg: &usize| {
assert_eq!(*cfg, 1);
"test".to_string()
},
);
if let Async::Ready(mut srv) = new_srv.new_service(&1).poll().unwrap() {
assert!(srv.poll_ready().is_ok());
}
}
}

View File

@@ -30,7 +30,8 @@ impl<R, E> Default for Blank<R, E> {
} }
} }
impl<R, E> Service<R> for Blank<R, E> { impl<R, E> Service for Blank<R, E> {
type Request = R;
type Response = R; type Response = R;
type Error = E; type Error = E;
type Future = FutureResult<R, E>; type Future = FutureResult<R, E>;
@@ -67,7 +68,8 @@ impl<R, E1, E2> Default for BlankNewService<R, E1, E2> {
} }
} }
impl<R, E1, E2> NewService<R, ()> for BlankNewService<R, E1, E2> { impl<R, E1, E2> NewService<()> for BlankNewService<R, E1, E2> {
type Request = R;
type Response = R; type Response = R;
type Error = E1; type Error = E1;
type Service = Blank<R, E1>; type Service = Blank<R, E1>;

View File

@@ -1,49 +1,48 @@
use std::marker::PhantomData;
use crate::{NewService, Service}; use crate::{NewService, Service};
use futures::{Future, IntoFuture, Poll}; use futures::{Future, IntoFuture, Poll};
pub type BoxedService<Req, Res, Err> = Box< pub type BoxedService<Req, Res, Err> = Box<
Service<Req, Response = Res, Error = Err, Future = Box<Future<Item = Res, Error = Err>>>, Service<
Request = Req,
Response = Res,
Error = Err,
Future = Box<Future<Item = Res, Error = Err>>,
>,
>; >;
/// Create boxed new service /// Create boxed new service
pub fn new_service<T, R, C>( pub fn new_service<T, C>(
service: T, service: T,
) -> BoxedNewService<C, R, T::Response, T::Error, T::InitError> ) -> BoxedNewService<C, T::Request, T::Response, T::Error, T::InitError>
where where
C: 'static, C: 'static,
T: NewService<R, C> + 'static, T: NewService<C> + 'static,
T::Request: 'static,
T::Response: 'static, T::Response: 'static,
T::Service: 'static, T::Service: 'static,
T::Future: 'static, T::Future: 'static,
T::Error: 'static, T::Error: 'static,
T::InitError: 'static, T::InitError: 'static,
R: 'static,
{ {
BoxedNewService(Box::new(NewServiceWrapper { BoxedNewService(Box::new(NewServiceWrapper {
service, service,
_t: PhantomData, _t: std::marker::PhantomData,
})) }))
} }
/// Create boxed service /// Create boxed service
pub fn service<T, R>(service: T) -> BoxedService<R, T::Response, T::Error> pub fn service<T>(service: T) -> BoxedService<T::Request, T::Response, T::Error>
where where
T: Service<R> + 'static, T: Service + 'static,
T::Future: 'static, T::Future: 'static,
R: 'static,
{ {
Box::new(ServiceWrapper { Box::new(ServiceWrapper(service))
service,
_t: PhantomData,
})
} }
type Inner<C, Req, Res, Err, InitErr> = Box< type Inner<C, Req, Res, Err, InitErr> = Box<
NewService< NewService<
Req,
C, C,
Request = Req,
Response = Res, Response = Res,
Error = Err, Error = Err,
InitError = InitErr, InitError = InitErr,
@@ -54,14 +53,14 @@ type Inner<C, Req, Res, Err, InitErr> = Box<
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>);
impl<C, Req, Res, Err, InitErr> NewService<Req, C> impl<C, Req, Res, Err, InitErr> NewService<C> for BoxedNewService<C, Req, Res, Err, InitErr>
for BoxedNewService<C, Req, Res, Err, InitErr>
where where
Req: 'static, Req: 'static,
Res: 'static, Res: 'static,
Err: 'static, Err: 'static,
InitErr: 'static, InitErr: 'static,
{ {
type Request = Req;
type Response = Res; type Response = Res;
type Error = Err; type Error = Err;
type InitError = InitErr; type InitError = InitErr;
@@ -73,22 +72,23 @@ where
} }
} }
struct NewServiceWrapper<T: NewService<R, C>, R, C> { struct NewServiceWrapper<C, T: NewService<C>> {
service: T, service: T,
_t: std::marker::PhantomData<(R, C)>, _t: std::marker::PhantomData<C>,
} }
impl<C, T, Req, Res, Err, InitErr> NewService<Req, C> for NewServiceWrapper<T, Req, C> impl<C, T, Req, Res, Err, InitErr> NewService<C> for NewServiceWrapper<C, T>
where where
Req: 'static, Req: 'static,
Res: 'static, Res: 'static,
Err: 'static, Err: 'static,
InitErr: 'static, InitErr: 'static,
T: NewService<Req, C, Response = Res, Error = Err, InitError = InitErr>, T: NewService<C, Request = Req, Response = Res, Error = Err, InitError = InitErr>,
T::Future: 'static, T::Future: 'static,
T::Service: 'static, T::Service: 'static,
<T::Service as Service<Req>>::Future: 'static, <T::Service as Service>::Future: 'static,
{ {
type Request = Req;
type Response = Res; type Response = Res;
type Error = Err; type Error = Err;
type InitError = InitErr; type InitError = InitErr;
@@ -105,40 +105,33 @@ where
} }
} }
struct ServiceWrapper<T: Service<R>, R> { struct ServiceWrapper<T: Service>(T);
service: T,
_t: PhantomData<R>,
}
impl<T, R> ServiceWrapper<T, R> impl<T> ServiceWrapper<T>
where where
T: Service<R> + 'static, T: Service + 'static,
T::Future: 'static, T::Future: 'static,
R: 'static,
{ {
fn boxed(service: T) -> BoxedService<R, T::Response, T::Error> { fn boxed(service: T) -> BoxedService<T::Request, T::Response, T::Error> {
Box::new(ServiceWrapper { Box::new(ServiceWrapper(service))
service,
_t: PhantomData,
})
} }
} }
impl<T, Req, Res, Err> Service<Req> for ServiceWrapper<T, Req> impl<T, Req, Res, Err> Service for ServiceWrapper<T>
where where
T: Service<Req, Response = Res, Error = Err>, T: Service<Request = Req, Response = Res, Error = Err>,
T::Future: 'static, T::Future: 'static,
Req: 'static,
{ {
type Request = Req;
type Response = Res; type Response = Res;
type Error = Err; type Error = Err;
type Future = Box<Future<Item = Self::Response, Error = Self::Error>>; type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.service.poll_ready() self.0.poll_ready()
} }
fn call(&mut self, req: Req) -> Self::Future { fn call(&mut self, req: Self::Request) -> Self::Future {
Box::new(self.service.call(req)) Box::new(self.0.call(req))
} }
} }

View File

@@ -1,7 +1,7 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use futures::future::{ok, FutureResult}; use futures::future::{ok, Future, FutureResult};
use futures::{Async, IntoFuture, Poll}; use futures::{try_ready, Async, IntoFuture, Poll};
use crate::{IntoConfigurableNewService, IntoNewService, IntoService, NewService, Service}; use crate::{IntoConfigurableNewService, IntoNewService, IntoService, NewService, Service};
@@ -15,21 +15,22 @@ where
} }
/// Create `NewService` for function that can produce services /// Create `NewService` for function that can produce services
pub fn fn_factory<F, R, S, E, Req>(f: F) -> FnNewServiceNoConfig<F, R, S, E, Req> pub fn fn_factory<F, R, S, E>(f: F) -> FnNewServiceNoConfig<F, R, S, E>
where where
F: Fn() -> R, F: Fn() -> R,
R: IntoFuture<Item = S, Error = E>, R: IntoFuture<Item = S, Error = E>,
S: Service<Req>, S: Service,
{ {
FnNewServiceNoConfig::new(f) FnNewServiceNoConfig::new(f)
} }
/// Create `NewService` for function that can produce services with configuration /// Create `NewService` for function that can produce services with configuration
pub fn fn_cfg_factory<F, C, R, S, E, Req>(f: F) -> FnNewServiceConfig<F, C, R, S, E, Req> pub fn fn_cfg_factory<F, C, R, S, E>(f: F) -> FnNewServiceConfig<F, C, R, S, E>
where where
F: Fn(&C) -> R, F: Fn(&C) -> R,
R: IntoFuture<Item = S, Error = E>, R: IntoFuture<Error = E>,
S: Service<Req>, R::Item: IntoService<S>,
S: Service,
{ {
FnNewServiceConfig::new(f) FnNewServiceConfig::new(f)
} }
@@ -66,11 +67,12 @@ where
} }
} }
impl<F, Req, Out> Service<Req> for FnService<F, Req, Out> impl<F, Req, Out> Service for FnService<F, Req, Out>
where where
F: FnMut(Req) -> Out, F: FnMut(Req) -> Out,
Out: IntoFuture, Out: IntoFuture,
{ {
type Request = Req;
type Response = Out::Item; type Response = Out::Item;
type Error = Out::Error; type Error = Out::Error;
type Future = Out::Future; type Future = Out::Future;
@@ -84,7 +86,7 @@ where
} }
} }
impl<F, Req, Out> IntoService<FnService<F, Req, Out>, Req> for F impl<F, Req, Out> IntoService<FnService<F, Req, Out>> for F
where where
F: FnMut(Req) -> Out + 'static, F: FnMut(Req) -> Out + 'static,
Out: IntoFuture, Out: IntoFuture,
@@ -113,11 +115,12 @@ where
} }
} }
impl<F, Req, Out, Cfg> NewService<Req, Cfg> for FnNewService<F, Req, Out, Cfg> impl<F, Req, Out, Cfg> NewService<Cfg> for FnNewService<F, Req, Out, Cfg>
where where
F: FnMut(Req) -> Out + Clone, F: FnMut(Req) -> Out + Clone,
Out: IntoFuture, Out: IntoFuture,
{ {
type Request = Req;
type Response = Out::Item; type Response = Out::Item;
type Error = Out::Error; type Error = Out::Error;
type Service = FnService<F, Req, Out>; type Service = FnService<F, Req, Out>;
@@ -140,7 +143,7 @@ where
} }
} }
impl<F, Req, Out, Cfg> IntoNewService<FnNewService<F, Req, Out, Cfg>, Req, Cfg> for F impl<F, Req, Out, Cfg> IntoNewService<FnNewService<F, Req, Out, Cfg>, Cfg> for F
where where
F: Fn(Req) -> Out + Clone, F: Fn(Req) -> Out + Clone,
Out: IntoFuture, Out: IntoFuture,
@@ -151,33 +154,33 @@ where
} }
/// Converter for `Fn() -> Future<Service>` fn /// Converter for `Fn() -> Future<Service>` fn
pub struct FnNewServiceNoConfig<F, R, S, E, Req> pub struct FnNewServiceNoConfig<F, R, S, E>
where where
F: Fn() -> R, F: Fn() -> R,
R: IntoFuture<Item = S, Error = E>, R: IntoFuture<Item = S, Error = E>,
S: Service<Req>, S: Service,
{ {
f: F, f: F,
_t: PhantomData<Req>,
} }
impl<F, R, S, E, Req> FnNewServiceNoConfig<F, R, S, E, Req> impl<F, R, S, E> FnNewServiceNoConfig<F, R, S, E>
where where
F: Fn() -> R, F: Fn() -> R,
R: IntoFuture<Item = S, Error = E>, R: IntoFuture<Item = S, Error = E>,
S: Service<Req>, S: Service,
{ {
pub fn new(f: F) -> Self { pub fn new(f: F) -> Self {
FnNewServiceNoConfig { f, _t: PhantomData } FnNewServiceNoConfig { f }
} }
} }
impl<F, R, S, E, Req> NewService<Req, ()> for FnNewServiceNoConfig<F, R, S, E, Req> impl<F, R, S, E> NewService<()> for FnNewServiceNoConfig<F, R, S, E>
where where
F: Fn() -> R, F: Fn() -> R,
R: IntoFuture<Item = S, Error = E>, R: IntoFuture<Item = S, Error = E>,
S: Service<Req>, S: Service,
{ {
type Request = S::Request;
type Response = S::Response; type Response = S::Response;
type Error = S::Error; type Error = S::Error;
type Service = S; type Service = S;
@@ -190,104 +193,119 @@ where
} }
} }
impl<F, R, S, E, Req> Clone for FnNewServiceNoConfig<F, R, S, E, Req> impl<F, R, S, E> Clone for FnNewServiceNoConfig<F, R, S, E>
where where
F: Fn() -> R + Clone, F: Fn() -> R + Clone,
R: IntoFuture<Item = S, Error = E>, R: IntoFuture<Item = S, Error = E>,
S: Service<Req>, S: Service,
{ {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self::new(self.f.clone()) Self::new(self.f.clone())
} }
} }
impl<F, R, S, E, Req> IntoNewService<FnNewServiceNoConfig<F, R, S, E, Req>, Req, ()> for F impl<F, R, S, E> IntoNewService<FnNewServiceNoConfig<F, R, S, E>, ()> for F
where where
F: Fn() -> R, F: Fn() -> R,
R: IntoFuture<Item = S, Error = E>, R: IntoFuture<Item = S, Error = E>,
S: Service<Req>, S: Service,
{ {
fn into_new_service(self) -> FnNewServiceNoConfig<F, R, S, E, Req> { fn into_new_service(self) -> FnNewServiceNoConfig<F, R, S, E> {
FnNewServiceNoConfig::new(self) FnNewServiceNoConfig::new(self)
} }
} }
/// Convert `Fn(&Config) -> Future<Service>` fn to NewService /// Convert `Fn(&Config) -> Future<Service>` fn to NewService
pub struct FnNewServiceConfig<F, C, R, S, E, Req> pub struct FnNewServiceConfig<F, C, R, S, E>
where where
F: Fn(&C) -> R, F: Fn(&C) -> R,
R: IntoFuture<Item = S, Error = E>, R: IntoFuture<Error = E>,
S: Service<Req>, R::Item: IntoService<S>,
S: Service,
{ {
f: F, f: F,
_t: PhantomData<(C, R, S, E, Req)>, _t: PhantomData<(C, R, S, E)>,
} }
impl<F, C, R, S, E, Req> FnNewServiceConfig<F, C, R, S, E, Req> impl<F, C, R, S, E> FnNewServiceConfig<F, C, R, S, E>
where where
F: Fn(&C) -> R, F: Fn(&C) -> R,
R: IntoFuture<Item = S, Error = E>, R: IntoFuture<Error = E>,
S: Service<Req>, R::Item: IntoService<S>,
S: Service,
{ {
pub fn new(f: F) -> Self { pub fn new(f: F) -> Self {
FnNewServiceConfig { f, _t: PhantomData } FnNewServiceConfig { f, _t: PhantomData }
} }
} }
impl<F, C, R, S, E, Req> NewService<Req, C> for FnNewServiceConfig<F, C, R, S, E, Req> impl<F, C, R, S, E> NewService<C> for FnNewServiceConfig<F, C, R, S, E>
where where
F: Fn(&C) -> R, F: Fn(&C) -> R,
R: IntoFuture<Item = S, Error = E>, R: IntoFuture<Error = E>,
S: Service<Req>, R::Item: IntoService<S>,
S: Service,
{ {
type Request = S::Request;
type Response = S::Response; type Response = S::Response;
type Error = S::Error; type Error = S::Error;
type Service = S; type Service = S;
type InitError = E; type InitError = E;
type Future = R::Future; type Future = FnNewServiceConfigFut<R, S, E>;
fn new_service(&self, cfg: &C) -> Self::Future { fn new_service(&self, cfg: &C) -> Self::Future {
(self.f)(cfg).into_future() FnNewServiceConfigFut {
fut: (self.f)(cfg).into_future(),
_t: PhantomData,
}
} }
} }
impl<F, C, R, S, E, Req> Clone for FnNewServiceConfig<F, C, R, S, E, Req> pub struct FnNewServiceConfigFut<R, S, E>
where
R: IntoFuture<Error = E>,
R::Item: IntoService<S>,
S: Service,
{
fut: R::Future,
_t: PhantomData<(S,)>,
}
impl<R, S, E> Future for FnNewServiceConfigFut<R, S, E>
where
R: IntoFuture<Error = E>,
R::Item: IntoService<S>,
S: Service,
{
type Item = S;
type Error = R::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
Ok(Async::Ready(try_ready!(self.fut.poll()).into_service()))
}
}
impl<F, C, R, S, E> Clone for FnNewServiceConfig<F, C, R, S, E>
where where
F: Fn(&C) -> R + Clone, F: Fn(&C) -> R + Clone,
R: IntoFuture<Item = S, Error = E>, R: IntoFuture<Error = E>,
S: Service<Req>, R::Item: IntoService<S>,
S: Service,
{ {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self::new(self.f.clone()) Self::new(self.f.clone())
} }
} }
impl<F, C, R, S, E, Req> impl<F, C, R, S, E> IntoConfigurableNewService<FnNewServiceConfig<F, C, R, S, E>, C> for F
IntoConfigurableNewService<FnNewServiceConfig<F, C, R, S, E, Req>, Req, C> for F
where where
F: Fn(&C) -> R, F: Fn(&C) -> R,
R: IntoFuture<Item = S, Error = E>, R: IntoFuture<Error = E>,
S: Service<Req>, R::Item: IntoService<S>,
S: Service,
{ {
fn into_new_service(self) -> FnNewServiceConfig<F, C, R, S, E, Req> { fn into_new_service(self) -> FnNewServiceConfig<F, C, R, S, E> {
FnNewServiceConfig::new(self) FnNewServiceConfig::new(self)
} }
} }
#[cfg(test)]
mod tests {
use crate::{IntoService, Service, ServiceExt};
#[test]
fn test_fn_service() {
let mut rt = actix_rt::Runtime::new().unwrap();
let srv = (|_t: &str| -> Result<usize, ()> { Ok(1) }).into_service();
let mut srv = srv.and_then(|test: usize| Ok(test));
let s = "HELLO".to_owned();
let res = rt.block_on(srv.call(&s)).unwrap();
assert_eq!(res, 1);
}
}

View File

@@ -5,16 +5,29 @@ use futures::IntoFuture;
use crate::{Apply, IntoTransform, Service, Transform}; use crate::{Apply, IntoTransform, Service, Transform};
pub struct FnTransform<F, S, R, In, Out, Err> /// Use function as transform service
pub fn fn_transform<F, S, In, Out, Err>(
f: F,
) -> impl Transform<S, Request = In, Response = Out::Item, Error = Out::Error, InitError = Err>
where
S: Service,
F: FnMut(In, &mut S) -> Out + Clone,
Out: IntoFuture,
Out::Error: From<S::Error>,
{
FnTransform::new(f)
}
pub struct FnTransform<F, S, In, Out, Err>
where where
F: FnMut(In, &mut S) -> Out + Clone, F: FnMut(In, &mut S) -> Out + Clone,
Out: IntoFuture, Out: IntoFuture,
{ {
f: F, f: F,
_t: PhantomData<(S, R, In, Out, Err)>, _t: PhantomData<(S, In, Out, Err)>,
} }
impl<F, S, R, In, Out, Err> FnTransform<F, S, R, In, Out, Err> impl<F, S, In, Out, Err> FnTransform<F, S, In, Out, Err>
where where
F: FnMut(In, &mut S) -> Out + Clone, F: FnMut(In, &mut S) -> Out + Clone,
Out: IntoFuture, Out: IntoFuture,
@@ -24,16 +37,17 @@ where
} }
} }
impl<F, S, R, In, Out, Err> Transform<S, In> for FnTransform<F, S, R, In, Out, Err> impl<F, S, In, Out, Err> Transform<S> for FnTransform<F, S, In, Out, Err>
where where
S: Service<R>, S: Service,
F: FnMut(In, &mut S) -> Out + Clone, F: FnMut(In, &mut S) -> Out + Clone,
Out: IntoFuture, Out: IntoFuture,
Out::Error: From<S::Error>, Out::Error: From<S::Error>,
{ {
type Request = In;
type Response = Out::Item; type Response = Out::Item;
type Error = Out::Error; type Error = Out::Error;
type Transform = Apply<S, R, 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 = FutureResult<Self::Transform, Self::InitError>;
@@ -42,19 +56,19 @@ where
} }
} }
impl<F, S, R, In, Out, Err> IntoTransform<FnTransform<F, S, R, In, Out, Err>, S, In> for F impl<F, S, In, Out, Err> IntoTransform<FnTransform<F, S, In, Out, Err>, S> for F
where where
S: Service<R>, S: Service,
F: FnMut(In, &mut S) -> Out + Clone, F: FnMut(In, &mut S) -> Out + Clone,
Out: IntoFuture, Out: IntoFuture,
Out::Error: From<S::Error>, Out::Error: From<S::Error>,
{ {
fn into_transform(self) -> FnTransform<F, S, R, In, Out, Err> { fn into_transform(self) -> FnTransform<F, S, In, Out, Err> {
FnTransform::new(self) FnTransform::new(self)
} }
} }
impl<F, S, R, In, Out, Err> Clone for FnTransform<F, S, R, In, Out, Err> impl<F, S, In, Out, Err> Clone for FnTransform<F, S, In, Out, Err>
where where
F: FnMut(In, &mut S) -> Out + Clone, F: FnMut(In, &mut S) -> Out + Clone,
Out: IntoFuture, Out: IntoFuture,

View File

@@ -13,9 +13,9 @@ pub struct FromErr<A, E> {
} }
impl<A, E> FromErr<A, E> { impl<A, E> FromErr<A, E> {
pub(crate) fn new<R>(service: A) -> Self pub(crate) fn new(service: A) -> Self
where where
A: Service<R>, A: Service,
E: From<A::Error>, E: From<A::Error>,
{ {
FromErr { FromErr {
@@ -37,20 +37,21 @@ where
} }
} }
impl<A, E, R> Service<R> for FromErr<A, E> impl<A, E> Service for FromErr<A, E>
where where
A: Service<R>, A: Service,
E: From<A::Error>, E: From<A::Error>,
{ {
type Request = A::Request;
type Response = A::Response; type Response = A::Response;
type Error = E; type Error = E;
type Future = FromErrFuture<A, R, E>; type Future = FromErrFuture<A, E>;
fn poll_ready(&mut self) -> Poll<(), E> { fn poll_ready(&mut self) -> Poll<(), E> {
self.service.poll_ready().map_err(E::from) self.service.poll_ready().map_err(E::from)
} }
fn call(&mut self, req: R) -> Self::Future { fn call(&mut self, req: A::Request) -> Self::Future {
FromErrFuture { FromErrFuture {
fut: self.service.call(req), fut: self.service.call(req),
f: PhantomData, f: PhantomData,
@@ -58,14 +59,14 @@ where
} }
} }
pub struct FromErrFuture<A: Service<R>, R, E> { pub struct FromErrFuture<A: Service, E> {
fut: A::Future, fut: A::Future,
f: PhantomData<E>, f: PhantomData<E>,
} }
impl<A, R, E> Future for FromErrFuture<A, R, E> impl<A, E> Future for FromErrFuture<A, E>
where where
A: Service<R>, A: Service,
E: From<A::Error>, E: From<A::Error>,
{ {
type Item = A::Response; type Item = A::Response;
@@ -87,9 +88,9 @@ pub struct FromErrNewService<A, E, C> {
impl<A, E, C> FromErrNewService<A, E, C> { impl<A, E, C> FromErrNewService<A, E, C> {
/// Create new `FromErr` new service instance /// Create new `FromErr` new service instance
pub fn new<R>(a: A) -> Self pub fn new(a: A) -> Self
where where
A: NewService<R, C>, A: NewService<C>,
E: From<A::Error>, E: From<A::Error>,
{ {
Self { a, e: PhantomData } Self { a, e: PhantomData }
@@ -108,17 +109,18 @@ where
} }
} }
impl<A, E, C, R> NewService<R, C> for FromErrNewService<A, E, C> impl<A, E, C> NewService<C> for FromErrNewService<A, E, C>
where where
A: NewService<R, C>, A: NewService<C>,
E: From<A::Error>, E: From<A::Error>,
{ {
type Request = A::Request;
type Response = A::Response; type Response = A::Response;
type Error = E; type Error = E;
type Service = FromErr<A::Service, E>; type Service = FromErr<A::Service, E>;
type InitError = A::InitError; type InitError = A::InitError;
type Future = FromErrNewServiceFuture<A, E, C, R>; type Future = FromErrNewServiceFuture<A, E, C>;
fn new_service(&self, cfg: &C) -> Self::Future { fn new_service(&self, cfg: &C) -> Self::Future {
FromErrNewServiceFuture { FromErrNewServiceFuture {
@@ -128,18 +130,18 @@ where
} }
} }
pub struct FromErrNewServiceFuture<A, E, C, R> pub struct FromErrNewServiceFuture<A, E, C>
where where
A: NewService<R, C>, A: NewService<C>,
E: From<A::Error>, E: From<A::Error>,
{ {
fut: A::Future, fut: A::Future,
e: PhantomData<E>, e: PhantomData<E>,
} }
impl<A, E, C, R> Future for FromErrNewServiceFuture<A, E, C, R> impl<A, E, C> Future for FromErrNewServiceFuture<A, E, C>
where where
A: NewService<R, C>, A: NewService<C>,
E: From<A::Error>, E: From<A::Error>,
{ {
type Item = FromErr<A::Service, E>; type Item = FromErr<A::Service, E>;
@@ -162,7 +164,8 @@ mod tests {
use crate::{IntoNewService, NewService, Service, ServiceExt}; use crate::{IntoNewService, NewService, Service, ServiceExt};
struct Srv; struct Srv;
impl Service<()> for Srv { impl Service for Srv {
type Request = ();
type Response = (); type Response = ();
type Error = (); type Error = ();
type Future = FutureResult<(), ()>; type Future = FutureResult<(), ()>;

View File

@@ -9,6 +9,7 @@ mod and_then;
mod and_then_apply; mod and_then_apply;
mod and_then_apply_fn; mod and_then_apply_fn;
mod apply; mod apply;
mod apply_cfg;
pub mod blank; pub mod blank;
pub mod boxed; pub mod boxed;
mod cell; mod cell;
@@ -20,25 +21,41 @@ mod map_err;
mod map_init_err; mod map_init_err;
mod then; mod then;
mod transform; mod transform;
mod transform_map_init_err; mod transform_err;
#[doc(hidden)]
#[deprecated(since = "0.3.4", note = "please use `apply_fn` instead")]
pub use self::apply::Apply;
#[doc(hidden)]
#[deprecated(since = "0.3.4", note = "please use `apply_fn_factory` instead")]
pub use self::apply::ApplyNewService;
#[doc(hidden)]
#[deprecated(since = "0.3.4", note = "please use `fn_transform` instead")]
pub use self::fn_transform::FnTransform;
#[doc(hidden)]
#[deprecated(since = "0.3.4", note = "please use `apply_transform` instead")]
pub use self::transform::ApplyTransform;
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::AndThenTransform;
use self::and_then_apply_fn::{AndThenApply, AndThenApplyNewService}; use self::and_then_apply_fn::{AndThenApply, AndThenApplyNewService};
pub use self::apply::{Apply, ApplyNewService}; pub use self::apply::{apply_fn, apply_fn_factory};
pub use self::apply_cfg::apply_cfg;
use self::apply_cfg::ApplyConfig;
pub use self::fn_service::{fn_cfg_factory, fn_factory, fn_service, FnService}; pub use self::fn_service::{fn_cfg_factory, fn_factory, fn_service, FnService};
pub use self::fn_transform::FnTransform; pub use self::fn_transform::fn_transform;
pub use self::from_err::{FromErr, FromErrNewService}; pub use self::from_err::{FromErr, FromErrNewService};
pub use self::map::{Map, MapNewService}; pub use self::map::{Map, MapNewService};
pub use self::map_err::{MapErr, MapErrNewService}; pub use self::map_err::{MapErr, MapErrNewService};
pub use self::map_init_err::MapInitErr; pub use self::map_init_err::MapInitErr;
pub use self::then::{Then, ThenNewService}; pub use self::then::{Then, ThenNewService};
pub use self::transform::{ApplyTransform, IntoTransform, Transform}; pub use self::transform::{apply_transform, IntoTransform, Transform};
/// An asynchronous function from `Request` to a `Response`. /// An asynchronous function from `Request` to a `Response`.
/// pub trait Service {
/// `Request` - requests handled by the service. /// Requests handled by the service.
pub trait Service<Request> { type Request;
/// Responses given by the service. /// Responses given by the service.
type Response; type Response;
@@ -68,26 +85,22 @@ pub trait Service<Request> {
/// ///
/// 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: Request) -> Self::Future; fn call(&mut self, req: Self::Request) -> Self::Future;
} }
/// An extension trait for `Service`s that provides a variety of convenient /// An extension trait for `Service`s that provides a variety of convenient
/// adapters /// adapters
pub trait ServiceExt<Request>: Service<Request> { pub trait ServiceExt: Service {
/// Apply function to specified service and use it as a next service in /// Apply function to specified service and use it as a next service in
/// chain. /// chain.
fn apply_fn<F, B, B1, Out, Req>( fn apply_fn<F, B, B1, Out>(self, service: B1, f: F) -> AndThenApply<Self, B, F, Out>
self,
service: B1,
f: F,
) -> AndThenApply<Self, B, F, Out, Request, Req>
where where
Self: Sized, Self: Sized,
F: FnMut(Self::Response, &mut B) -> Out, F: FnMut(Self::Response, &mut B) -> Out,
Out: IntoFuture, Out: IntoFuture,
Out::Error: Into<Self::Error>, Out::Error: Into<Self::Error>,
B: Service<Req, Error = Self::Error>, B: Service<Error = Self::Error>,
B1: IntoService<B, Req>, B1: IntoService<B>,
{ {
AndThenApply::new(self, service, f) AndThenApply::new(self, service, f)
} }
@@ -104,8 +117,8 @@ pub trait ServiceExt<Request>: Service<Request> {
fn and_then<F, B>(self, service: F) -> AndThen<Self, B> fn and_then<F, B>(self, service: F) -> AndThen<Self, B>
where where
Self: Sized, Self: Sized,
F: IntoService<B, Self::Response>, F: IntoService<B>,
B: Service<Self::Response, Error = Self::Error>, B: Service<Request = Self::Response, Error = Self::Error>,
{ {
AndThen::new(self, service.into_service()) AndThen::new(self, service.into_service())
} }
@@ -131,7 +144,7 @@ pub trait ServiceExt<Request>: Service<Request> {
fn then<B>(self, service: B) -> Then<Self, B> fn then<B>(self, service: B) -> Then<Self, B>
where where
Self: Sized, Self: Sized,
B: Service<Result<Self::Response, Self::Error>, Error = Self::Error>, B: Service<Request = Result<Self::Response, Self::Error>, Error = Self::Error>,
{ {
Then::new(self, service) Then::new(self, service)
} }
@@ -170,7 +183,7 @@ pub trait ServiceExt<Request>: Service<Request> {
} }
} }
impl<T: ?Sized, R> ServiceExt<R> for T where T: Service<R> {} impl<T: ?Sized> ServiceExt for T where T: Service {}
/// Creates new `Service` values. /// Creates new `Service` values.
/// ///
@@ -180,9 +193,11 @@ impl<T: ?Sized, R> ServiceExt<R> for T where T: Service<R> {}
/// `NewService` trait, and uses that new `Service` value to process inbound /// `NewService` trait, and uses that new `Service` value to process inbound
/// requests on that new TCP stream. /// requests on that new TCP stream.
/// ///
/// * `Request` - requests handled by the service. /// `Config` is a service factory configuration type.
/// * `Config` - is a service factory configuration type. pub trait NewService<Config = ()> {
pub trait NewService<Request, Config = ()> { /// Requests handled by the service.
type Request;
/// Responses given by the service /// Responses given by the service
type Response; type Response;
@@ -190,7 +205,11 @@ pub trait NewService<Request, Config = ()> {
type Error; type Error;
/// The `Service` value created by this factory /// The `Service` value created by this factory
type Service: Service<Request, Response = Self::Response, Error = Self::Error>; type Service: Service<
Request = Self::Request,
Response = Self::Response,
Error = Self::Error,
>;
/// Errors produced while building a service. /// Errors produced while building a service.
type InitError; type InitError;
@@ -201,35 +220,35 @@ pub trait NewService<Request, Config = ()> {
/// Create and return a new service value asynchronously. /// Create and return a new service value asynchronously.
fn new_service(&self, cfg: &Config) -> Self::Future; fn new_service(&self, cfg: &Config) -> Self::Future;
/// Apply function to specified service and use it as a next service in /// Apply transform service to specified service and use it as a next service in
/// chain. /// chain.
fn apply<T, T1, B, B1, Req>( fn apply<T, T1, B, B1>(
self, self,
transform: T1, transform: T1,
service: B1, service: B1,
) -> AndThenTransform<T, Self, B, Req> ) -> AndThenTransform<T, Self, B, Config>
where where
Self: Sized, Self: Sized,
T: Transform<B::Service, Self::Response, InitError = Self::InitError>, T: Transform<B::Service, Request = Self::Response, InitError = Self::InitError>,
T::Error: From<Self::Error>, T::Error: From<Self::Error>,
T1: IntoTransform<T, B::Service, Self::Response>, T1: IntoTransform<T, B::Service>,
B: NewService<Req, Config, InitError = Self::InitError>, B: NewService<Config, InitError = Self::InitError>,
B1: IntoNewService<B, Req, Config>, B1: IntoNewService<B, Config>,
{ {
AndThenTransform::new(transform.into_transform(), self, service.into_new_service()) AndThenTransform::new(transform.into_transform(), self, service.into_new_service())
} }
/// Apply function to specified service and use it as a next service in /// Apply function to specified service and use it as a next service in
/// chain. /// chain.
fn apply_fn<B, I, F, Out, Req>( fn apply_fn<B, I, F, Out>(
self, self,
service: I, service: I,
f: F, f: F,
) -> AndThenApplyNewService<Self, B, F, Out, Request, Req, Config> ) -> AndThenApplyNewService<Self, B, F, Out, Config>
where where
Self: Sized, Self: Sized,
B: NewService<Req, Config, Error = Self::Error, InitError = Self::InitError>, B: NewService<Config, Error = Self::Error, InitError = Self::InitError>,
I: IntoNewService<B, Req, Config>, I: IntoNewService<B, Config>,
F: FnMut(Self::Response, &mut B::Service) -> Out, F: FnMut(Self::Response, &mut B::Service) -> Out,
Out: IntoFuture, Out: IntoFuture,
Out::Error: Into<Self::Error>, Out::Error: Into<Self::Error>,
@@ -237,12 +256,38 @@ pub trait NewService<Request, Config = ()> {
AndThenApplyNewService::new(self, service, f) AndThenApplyNewService::new(self, service, f)
} }
/// Call another service after call to this one has resolved successfully. /// Map this service's config type to a different config,
fn and_then<F, B>(self, new_service: F) -> AndThenNewService<Self, B> /// and use for nested service
fn apply_cfg<F, C, S, U>(
self,
service: U,
f: F,
) -> AndThenNewService<Self, ApplyConfig<F, S, Config, C>, Config>
where where
Self: Sized, Self: Sized,
F: IntoNewService<B, Self::Response, Config>, F: Fn(&Config) -> C,
B: NewService<Self::Response, Config, Error = Self::Error, InitError = Self::InitError>, U: IntoNewService<S, C>,
S: NewService<
C,
Request = Self::Response,
Error = Self::Error,
InitError = Self::InitError,
>,
{
self.and_then(ApplyConfig::new(service, f))
}
/// Call another service after call to this one has resolved successfully.
fn and_then<F, B>(self, new_service: F) -> AndThenNewService<Self, B, Config>
where
Self: Sized,
F: IntoNewService<B, Config>,
B: NewService<
Config,
Request = Self::Response,
Error = Self::Error,
InitError = Self::InitError,
>,
{ {
AndThenNewService::new(self, new_service) AndThenNewService::new(self, new_service)
} }
@@ -270,15 +315,15 @@ pub trait NewService<Request, Config = ()> {
fn then<F, B>(self, new_service: F) -> ThenNewService<Self, B, Config> fn then<F, B>(self, new_service: F) -> ThenNewService<Self, B, Config>
where where
Self: Sized, Self: Sized,
F: IntoNewService<B, Result<Self::Response, Self::Error>, Config>, F: IntoNewService<B, Config>,
B: NewService< B: NewService<
Result<Self::Response, Self::Error>,
Config, Config,
Request = Result<Self::Response, Self::Error>,
Error = Self::Error, Error = Self::Error,
InitError = Self::InitError, InitError = Self::InitError,
>, >,
{ {
ThenNewService::new(self, new_service.into_new_service()) ThenNewService::new(self, new_service)
} }
/// Map this service's output to a different type, returning a new service /// Map this service's output to a different type, returning a new service
@@ -295,7 +340,7 @@ pub trait NewService<Request, Config = ()> {
fn map_err<F, E>(self, f: F) -> MapErrNewService<Self, F, E, Config> fn map_err<F, E>(self, f: F) -> MapErrNewService<Self, F, E, Config>
where where
Self: Sized, Self: Sized,
F: Fn(Self::Error) -> E, F: Fn(Self::Error) -> E + Clone,
{ {
MapErrNewService::new(self, f) MapErrNewService::new(self, f)
} }
@@ -310,10 +355,11 @@ pub trait NewService<Request, Config = ()> {
} }
} }
impl<'a, S, R> Service<R> for &'a mut S impl<'a, S> Service for &'a mut S
where where
S: Service<R> + 'a, S: Service + 'a,
{ {
type Request = S::Request;
type Response = S::Response; type Response = S::Response;
type Error = S::Error; type Error = S::Error;
type Future = S::Future; type Future = S::Future;
@@ -322,15 +368,16 @@ where
(**self).poll_ready() (**self).poll_ready()
} }
fn call(&mut self, request: R) -> S::Future { fn call(&mut self, request: Self::Request) -> S::Future {
(**self).call(request) (**self).call(request)
} }
} }
impl<S, R> Service<R> for Box<S> impl<S> Service for Box<S>
where where
S: Service<R> + ?Sized, S: Service + ?Sized,
{ {
type Request = S::Request;
type Response = S::Response; type Response = S::Response;
type Error = S::Error; type Error = S::Error;
type Future = S::Future; type Future = S::Future;
@@ -339,15 +386,16 @@ where
(**self).poll_ready() (**self).poll_ready()
} }
fn call(&mut self, request: R) -> S::Future { fn call(&mut self, request: Self::Request) -> S::Future {
(**self).call(request) (**self).call(request)
} }
} }
impl<S, R, C> NewService<R, C> for Rc<S> impl<S, C> NewService<C> for Rc<S>
where where
S: NewService<R, C>, S: NewService<C>,
{ {
type Request = S::Request;
type Response = S::Response; type Response = S::Response;
type Error = S::Error; type Error = S::Error;
type Service = S::Service; type Service = S::Service;
@@ -359,10 +407,11 @@ where
} }
} }
impl<S, R, C> NewService<R, C> for Arc<S> impl<S, C> NewService<C> for Arc<S>
where where
S: NewService<R, C>, S: NewService<C>,
{ {
type Request = S::Request;
type Response = S::Response; type Response = S::Response;
type Error = S::Error; type Error = S::Error;
type Service = S::Service; type Service = S::Service;
@@ -375,35 +424,35 @@ where
} }
/// Trait for types that can be converted to a `Service` /// Trait for types that can be converted to a `Service`
pub trait IntoService<T, R> pub trait IntoService<T>
where where
T: Service<R>, T: Service,
{ {
/// Convert to a `Service` /// Convert to a `Service`
fn into_service(self) -> T; fn into_service(self) -> T;
} }
/// Trait for types that can be converted to a `NewService` /// Trait for types that can be converted to a `NewService`
pub trait IntoNewService<T, R, C = ()> pub trait IntoNewService<T, C = ()>
where where
T: NewService<R, C>, T: NewService<C>,
{ {
/// Convert to an `NewService` /// Convert to an `NewService`
fn into_new_service(self) -> T; fn into_new_service(self) -> T;
} }
impl<T, R> IntoService<T, R> for T impl<T> IntoService<T> for T
where where
T: Service<R>, T: Service,
{ {
fn into_service(self) -> T { fn into_service(self) -> T {
self self
} }
} }
impl<T, R, C> IntoNewService<T, R, C> for T impl<T, C> IntoNewService<T, C> for T
where where
T: NewService<R, C>, T: NewService<C>,
{ {
fn into_new_service(self) -> T { fn into_new_service(self) -> T {
self self
@@ -411,17 +460,17 @@ where
} }
/// Trait for types that can be converted to a configurable `NewService` /// Trait for types that can be converted to a configurable `NewService`
pub trait IntoConfigurableNewService<T, R, C> pub trait IntoConfigurableNewService<T, C>
where where
T: NewService<R, C>, T: NewService<C>,
{ {
/// Convert to an `NewService` /// Convert to an `NewService`
fn into_new_service(self) -> T; fn into_new_service(self) -> T;
} }
impl<T, R, C> IntoConfigurableNewService<T, R, C> for T impl<T, C> IntoConfigurableNewService<T, C> for T
where where
T: NewService<R, C>, T: NewService<C>,
{ {
fn into_new_service(self) -> T { fn into_new_service(self) -> T {
self self

View File

@@ -15,9 +15,9 @@ pub struct Map<A, F, Response> {
impl<A, F, Response> Map<A, F, Response> { impl<A, F, Response> Map<A, F, Response> {
/// Create new `Map` combinator /// Create new `Map` combinator
pub fn new<R>(service: A, f: F) -> Self pub fn new(service: A, f: F) -> Self
where where
A: Service<R>, A: Service,
F: FnMut(A::Response) -> Response, F: FnMut(A::Response) -> Response,
{ {
Self { Self {
@@ -42,36 +42,37 @@ where
} }
} }
impl<A, F, R, Response> Service<R> for Map<A, F, Response> impl<A, F, Response> Service for Map<A, F, Response>
where where
A: Service<R>, A: Service,
F: FnMut(A::Response) -> Response + Clone, F: FnMut(A::Response) -> Response + Clone,
{ {
type Request = A::Request;
type Response = Response; type Response = Response;
type Error = A::Error; type Error = A::Error;
type Future = MapFuture<A, F, R, Response>; type Future = MapFuture<A, F, Response>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.service.poll_ready() self.service.poll_ready()
} }
fn call(&mut self, req: R) -> Self::Future { fn call(&mut self, req: A::Request) -> Self::Future {
MapFuture::new(self.service.call(req), self.f.clone()) MapFuture::new(self.service.call(req), self.f.clone())
} }
} }
pub struct MapFuture<A, F, R, Response> pub struct MapFuture<A, F, Response>
where where
A: Service<R>, A: Service,
F: FnMut(A::Response) -> Response, F: FnMut(A::Response) -> Response,
{ {
f: F, f: F,
fut: A::Future, fut: A::Future,
} }
impl<A, F, R, Response> MapFuture<A, F, R, Response> impl<A, F, Response> MapFuture<A, F, Response>
where where
A: Service<R>, A: Service,
F: FnMut(A::Response) -> Response, F: FnMut(A::Response) -> Response,
{ {
fn new(fut: A::Future, f: F) -> Self { fn new(fut: A::Future, f: F) -> Self {
@@ -79,9 +80,9 @@ where
} }
} }
impl<A, F, R, Response> Future for MapFuture<A, F, R, Response> impl<A, F, Response> Future for MapFuture<A, F, Response>
where where
A: Service<R>, A: Service,
F: FnMut(A::Response) -> Response, F: FnMut(A::Response) -> Response,
{ {
type Item = Response; type Item = Response;
@@ -104,9 +105,9 @@ pub struct MapNewService<A, F, Res, Cfg> {
impl<A, F, Res, Cfg> MapNewService<A, F, Res, Cfg> { impl<A, F, Res, Cfg> MapNewService<A, F, Res, Cfg> {
/// Create new `Map` new service instance /// Create new `Map` new service instance
pub fn new<Req>(a: A, f: F) -> Self pub fn new(a: A, f: F) -> Self
where where
A: NewService<Req, Cfg>, A: NewService<Cfg>,
F: FnMut(A::Response) -> Res, F: FnMut(A::Response) -> Res,
{ {
Self { Self {
@@ -131,35 +132,36 @@ where
} }
} }
impl<A, F, Req, Res, Cfg> NewService<Req, Cfg> for MapNewService<A, F, Res, Cfg> impl<A, F, Res, Cfg> NewService<Cfg> for MapNewService<A, F, Res, Cfg>
where where
A: NewService<Req, Cfg>, A: NewService<Cfg>,
F: FnMut(A::Response) -> Res + Clone, F: FnMut(A::Response) -> Res + Clone,
{ {
type Request = A::Request;
type Response = Res; type Response = Res;
type Error = A::Error; type Error = A::Error;
type Service = Map<A::Service, F, Res>; type Service = Map<A::Service, F, Res>;
type InitError = A::InitError; type InitError = A::InitError;
type Future = MapNewServiceFuture<A, F, Req, Res, Cfg>; type Future = MapNewServiceFuture<A, F, Res, Cfg>;
fn new_service(&self, cfg: &Cfg) -> Self::Future { fn new_service(&self, cfg: &Cfg) -> Self::Future {
MapNewServiceFuture::new(self.a.new_service(cfg), self.f.clone()) MapNewServiceFuture::new(self.a.new_service(cfg), self.f.clone())
} }
} }
pub struct MapNewServiceFuture<A, F, Req, Res, Cfg> pub struct MapNewServiceFuture<A, F, Res, Cfg>
where where
A: NewService<Req, Cfg>, A: NewService<Cfg>,
F: FnMut(A::Response) -> Res, F: FnMut(A::Response) -> Res,
{ {
fut: A::Future, fut: A::Future,
f: Option<F>, f: Option<F>,
} }
impl<A, F, Req, Res, Cfg> MapNewServiceFuture<A, F, Req, Res, Cfg> impl<A, F, Res, Cfg> MapNewServiceFuture<A, F, Res, Cfg>
where where
A: NewService<Req, Cfg>, A: NewService<Cfg>,
F: FnMut(A::Response) -> Res, F: FnMut(A::Response) -> Res,
{ {
fn new(fut: A::Future, f: F) -> Self { fn new(fut: A::Future, f: F) -> Self {
@@ -167,9 +169,9 @@ where
} }
} }
impl<A, F, Req, Res, Cfg> Future for MapNewServiceFuture<A, F, Req, Res, Cfg> impl<A, F, Res, Cfg> Future for MapNewServiceFuture<A, F, Res, Cfg>
where where
A: NewService<Req, Cfg>, A: NewService<Cfg>,
F: FnMut(A::Response) -> Res, F: FnMut(A::Response) -> Res,
{ {
type Item = Map<A::Service, F, Res>; type Item = Map<A::Service, F, Res>;
@@ -192,7 +194,8 @@ mod tests {
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 Response = (); type Response = ();
type Error = (); type Error = ();
type Future = FutureResult<(), ()>; type Future = FutureResult<(), ()>;

View File

@@ -16,9 +16,9 @@ pub struct MapErr<A, F, E> {
impl<A, F, E> MapErr<A, F, E> { impl<A, F, E> MapErr<A, F, E> {
/// Create new `MapErr` combinator /// Create new `MapErr` combinator
pub fn new<R>(service: A, f: F) -> Self pub fn new(service: A, f: F) -> Self
where where
A: Service<R>, A: Service,
F: Fn(A::Error) -> E, F: Fn(A::Error) -> E,
{ {
Self { Self {
@@ -43,39 +43,47 @@ where
} }
} }
impl<A, F, E, R> Service<R> for MapErr<A, F, E> impl<A, F, E> Service for MapErr<A, F, E>
where where
A: Service<R>, A: Service,
F: Fn(A::Error) -> E + Clone, F: Fn(A::Error) -> E + Clone,
{ {
type Request = A::Request;
type Response = A::Response; type Response = A::Response;
type Error = E; type Error = E;
type Future = MapErrFuture<A, F, E, R>; type Future = MapErrFuture<A, F, E>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.service.poll_ready().map_err(&self.f) self.service.poll_ready().map_err(&self.f)
} }
fn call(&mut self, req: R) -> Self::Future { fn call(&mut self, req: A::Request) -> Self::Future {
MapErrFuture { MapErrFuture::new(self.service.call(req), self.f.clone())
fut: self.service.call(req),
f: self.f.clone(),
}
} }
} }
pub struct MapErrFuture<A, F, E, R> pub struct MapErrFuture<A, F, E>
where where
A: Service<R>, A: Service,
F: Fn(A::Error) -> E, F: Fn(A::Error) -> E,
{ {
f: F, f: F,
fut: A::Future, fut: A::Future,
} }
impl<A, F, E, R> Future for MapErrFuture<A, F, E, R> impl<A, F, E> MapErrFuture<A, F, E>
where where
A: Service<R>, A: Service,
F: Fn(A::Error) -> E,
{
fn new(fut: A::Future, f: F) -> Self {
MapErrFuture { f, fut }
}
}
impl<A, F, E> Future for MapErrFuture<A, F, E>
where
A: Service,
F: Fn(A::Error) -> E, F: Fn(A::Error) -> E,
{ {
type Item = A::Response; type Item = A::Response;
@@ -90,19 +98,23 @@ where
/// service's error. /// service's error.
/// ///
/// This is created by the `NewServiceExt::map_err` method. /// This is created by the `NewServiceExt::map_err` method.
pub struct MapErrNewService<A, F, E, C> { pub struct MapErrNewService<A, F, E, C>
where
A: NewService<C>,
F: Fn(A::Error) -> E + Clone,
{
a: A, a: A,
f: F, f: F,
e: PhantomData<(E, C)>, e: PhantomData<(E, C)>,
} }
impl<A, F, E, C> MapErrNewService<A, F, E, C> { impl<A, F, E, C> MapErrNewService<A, F, E, C>
where
A: NewService<C>,
F: Fn(A::Error) -> E + Clone,
{
/// Create new `MapErr` new service instance /// Create new `MapErr` new service instance
pub fn new<R>(a: A, f: F) -> Self pub fn new(a: A, f: F) -> Self {
where
A: NewService<R, C>,
F: Fn(A::Error) -> E,
{
Self { Self {
a, a,
f, f,
@@ -113,8 +125,8 @@ impl<A, F, E, C> MapErrNewService<A, F, E, C> {
impl<A, F, E, C> Clone for MapErrNewService<A, F, E, C> impl<A, F, E, C> Clone for MapErrNewService<A, F, E, C>
where where
A: Clone, A: NewService<C> + Clone,
F: Clone, F: Fn(A::Error) -> E + Clone,
{ {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
@@ -125,35 +137,36 @@ where
} }
} }
impl<A, F, E, R, C> NewService<R, C> for MapErrNewService<A, F, E, C> impl<A, F, E, C> NewService<C> for MapErrNewService<A, F, E, C>
where where
A: NewService<R, C>, A: NewService<C>,
F: Fn(A::Error) -> E + Clone, F: Fn(A::Error) -> E + Clone,
{ {
type Request = A::Request;
type Response = A::Response; type Response = A::Response;
type Error = E; type Error = E;
type Service = MapErr<A::Service, F, E>; type Service = MapErr<A::Service, F, E>;
type InitError = A::InitError; type InitError = A::InitError;
type Future = MapErrNewServiceFuture<A, F, E, R, C>; type Future = MapErrNewServiceFuture<A, F, E, C>;
fn new_service(&self, cfg: &C) -> Self::Future { fn new_service(&self, cfg: &C) -> Self::Future {
MapErrNewServiceFuture::new(self.a.new_service(cfg), self.f.clone()) MapErrNewServiceFuture::new(self.a.new_service(cfg), self.f.clone())
} }
} }
pub struct MapErrNewServiceFuture<A, F, E, R, C> pub struct MapErrNewServiceFuture<A, F, E, C>
where where
A: NewService<R, C>, A: NewService<C>,
F: Fn(A::Error) -> E, F: Fn(A::Error) -> E,
{ {
fut: A::Future, fut: A::Future,
f: F, f: F,
} }
impl<A, F, E, R, C> MapErrNewServiceFuture<A, F, E, R, C> impl<A, F, E, C> MapErrNewServiceFuture<A, F, E, C>
where where
A: NewService<R, C>, A: NewService<C>,
F: Fn(A::Error) -> E, F: Fn(A::Error) -> E,
{ {
fn new(fut: A::Future, f: F) -> Self { fn new(fut: A::Future, f: F) -> Self {
@@ -161,9 +174,9 @@ where
} }
} }
impl<A, F, E, R, C> Future for MapErrNewServiceFuture<A, F, E, R, C> impl<A, F, E, C> Future for MapErrNewServiceFuture<A, F, E, C>
where where
A: NewService<R, C>, A: NewService<C>,
F: Fn(A::Error) -> E + Clone, F: Fn(A::Error) -> E + Clone,
{ {
type Item = MapErr<A::Service, F, E>; type Item = MapErr<A::Service, F, E>;
@@ -187,7 +200,8 @@ mod tests {
struct Srv; struct Srv;
impl Service<()> for Srv { impl Service for Srv {
type Request = ();
type Response = (); type Response = ();
type Error = (); type Error = ();
type Future = FutureResult<(), ()>; type Future = FutureResult<(), ()>;

View File

@@ -13,9 +13,9 @@ pub struct MapInitErr<A, F, E, C> {
impl<A, F, E, C> MapInitErr<A, F, E, C> { impl<A, F, E, C> MapInitErr<A, F, E, C> {
/// Create new `MapInitErr` combinator /// Create new `MapInitErr` combinator
pub fn new<R>(a: A, f: F) -> Self pub fn new(a: A, f: F) -> Self
where where
A: NewService<R, C>, A: NewService<C>,
F: Fn(A::InitError) -> E, F: Fn(A::InitError) -> E,
{ {
Self { Self {
@@ -40,38 +40,46 @@ where
} }
} }
impl<A, F, E, R, C> NewService<R, C> for MapInitErr<A, F, E, C> impl<A, F, E, C> NewService<C> for MapInitErr<A, F, E, C>
where where
A: NewService<R, C>, A: NewService<C>,
F: Fn(A::InitError) -> E + Clone, F: Fn(A::InitError) -> E + Clone,
{ {
type Request = A::Request;
type Response = A::Response; type Response = A::Response;
type Error = A::Error; type Error = A::Error;
type Service = A::Service; type Service = A::Service;
type InitError = E; type InitError = E;
type Future = MapInitErrFuture<A, F, E, R, C>; type Future = MapInitErrFuture<A, F, E, C>;
fn new_service(&self, cfg: &C) -> Self::Future { fn new_service(&self, cfg: &C) -> Self::Future {
MapInitErrFuture { MapInitErrFuture::new(self.a.new_service(cfg), self.f.clone())
fut: self.a.new_service(cfg),
f: self.f.clone(),
}
} }
} }
pub struct MapInitErrFuture<A, F, E, R, C> pub struct MapInitErrFuture<A, F, E, C>
where where
A: NewService<R, C>, A: NewService<C>,
F: Fn(A::InitError) -> E, F: Fn(A::InitError) -> E,
{ {
f: F, f: F,
fut: A::Future, fut: A::Future,
} }
impl<A, F, E, R, C> Future for MapInitErrFuture<A, F, E, R, C> impl<A, F, E, C> MapInitErrFuture<A, F, E, C>
where where
A: NewService<R, C>, A: NewService<C>,
F: Fn(A::InitError) -> E,
{
fn new(fut: A::Future, f: F) -> Self {
MapInitErrFuture { f, fut }
}
}
impl<A, F, E, C> Future for MapInitErrFuture<A, F, E, C>
where
A: NewService<C>,
F: Fn(A::InitError) -> E, F: Fn(A::InitError) -> E,
{ {
type Item = A::Service; type Item = A::Service;

View File

@@ -1,8 +1,8 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use futures::{try_ready, Async, Future, Poll}; use futures::{Async, Future, Poll};
use super::{NewService, Service}; use super::{IntoNewService, NewService, Service};
use crate::cell::Cell; use crate::cell::Cell;
/// Service for the `then` combinator, chaining a computation onto the end of /// Service for the `then` combinator, chaining a computation onto the end of
@@ -16,10 +16,10 @@ pub struct Then<A, B> {
impl<A, B> Then<A, B> { impl<A, B> Then<A, B> {
/// Create new `Then` combinator /// Create new `Then` combinator
pub fn new<R>(a: A, b: B) -> Then<A, B> pub fn new(a: A, b: B) -> Then<A, B>
where where
A: Service<R>, A: Service,
B: Service<Result<A::Response, A::Error>, Error = A::Error>, B: Service<Request = Result<A::Response, A::Error>, Error = A::Error>,
{ {
Then { a, b: Cell::new(b) } Then { a, b: Cell::new(b) }
} }
@@ -37,39 +37,44 @@ where
} }
} }
impl<A, B, R> Service<R> for Then<A, B> impl<A, B> Service for Then<A, B>
where where
A: Service<R>, A: Service,
B: Service<Result<A::Response, A::Error>, Error = A::Error>, B: Service<Request = Result<A::Response, A::Error>, Error = A::Error>,
{ {
type Request = A::Request;
type Response = B::Response; type Response = B::Response;
type Error = B::Error; type Error = B::Error;
type Future = ThenFuture<A, B, R>; type Future = ThenFuture<A, B>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(&mut self) -> Poll<(), Self::Error> {
try_ready!(self.a.poll_ready()); let not_ready = self.a.poll_ready()?.is_not_ready();
self.b.get_mut().poll_ready() if self.b.get_mut().poll_ready()?.is_not_ready() || not_ready {
Ok(Async::NotReady)
} else {
Ok(Async::Ready(()))
}
} }
fn call(&mut self, req: R) -> Self::Future { fn call(&mut self, req: A::Request) -> Self::Future {
ThenFuture::new(self.a.call(req), self.b.clone()) ThenFuture::new(self.a.call(req), self.b.clone())
} }
} }
pub struct ThenFuture<A, B, R> pub struct ThenFuture<A, B>
where where
A: Service<R>, A: Service,
B: Service<Result<A::Response, A::Error>>, B: Service<Request = Result<A::Response, A::Error>>,
{ {
b: Cell<B>, b: Cell<B>,
fut_b: Option<B::Future>, fut_b: Option<B::Future>,
fut_a: Option<A::Future>, fut_a: Option<A::Future>,
} }
impl<A, B, R> ThenFuture<A, B, R> impl<A, B> ThenFuture<A, B>
where where
A: Service<R>, A: Service,
B: Service<Result<A::Response, A::Error>>, B: Service<Request = Result<A::Response, A::Error>>,
{ {
fn new(a: A::Future, b: Cell<B>) -> Self { fn new(a: A::Future, b: Cell<B>) -> Self {
ThenFuture { ThenFuture {
@@ -80,10 +85,10 @@ where
} }
} }
impl<A, B, R> Future for ThenFuture<A, B, R> impl<A, B> Future for ThenFuture<A, B>
where where
A: Service<R>, A: Service,
B: Service<Result<A::Response, A::Error>>, B: Service<Request = Result<A::Response, A::Error>>,
{ {
type Item = B::Response; type Item = B::Response;
type Error = B::Error; type Error = B::Error;
@@ -118,35 +123,42 @@ pub struct ThenNewService<A, B, C> {
impl<A, B, C> ThenNewService<A, B, C> { impl<A, B, C> ThenNewService<A, B, C> {
/// Create new `AndThen` combinator /// Create new `AndThen` combinator
pub fn new<R>(a: A, f: B) -> Self pub fn new<F>(a: A, f: F) -> Self
where where
A: NewService<R, C>, A: NewService<C>,
B: NewService< B: NewService<
Result<A::Response, A::Error>,
C, C,
Request = Result<A::Response, A::Error>,
Error = A::Error, Error = A::Error,
InitError = A::InitError, InitError = A::InitError,
>, >,
F: IntoNewService<B, C>,
{ {
Self { Self {
a, a,
b: f, b: f.into_new_service(),
_t: PhantomData, _t: PhantomData,
} }
} }
} }
impl<A, B, R, C> NewService<R, C> for ThenNewService<A, B, C> impl<A, B, C> NewService<C> for ThenNewService<A, B, C>
where where
A: NewService<R, C>, A: NewService<C>,
B: NewService<Result<A::Response, A::Error>, C, Error = A::Error, InitError = A::InitError>, B: NewService<
C,
Request = Result<A::Response, A::Error>,
Error = A::Error,
InitError = A::InitError,
>,
{ {
type Request = A::Request;
type Response = B::Response; type Response = B::Response;
type Error = A::Error; type Error = A::Error;
type Service = Then<A::Service, B::Service>; type Service = Then<A::Service, B::Service>;
type InitError = A::InitError; type InitError = A::InitError;
type Future = ThenNewServiceFuture<A, B, R, C>; type Future = ThenNewServiceFuture<A, B, C>;
fn new_service(&self, cfg: &C) -> Self::Future { fn new_service(&self, cfg: &C) -> Self::Future {
ThenNewServiceFuture::new(self.a.new_service(cfg), self.b.new_service(cfg)) ThenNewServiceFuture::new(self.a.new_service(cfg), self.b.new_service(cfg))
@@ -167,10 +179,15 @@ where
} }
} }
pub struct ThenNewServiceFuture<A, B, R, C> pub struct ThenNewServiceFuture<A, B, C>
where where
A: NewService<R, C>, A: NewService<C>,
B: NewService<Result<A::Response, A::Error>, C, Error = A::Error, InitError = A::InitError>, B: NewService<
C,
Request = Result<A::Response, A::Error>,
Error = A::Error,
InitError = A::InitError,
>,
{ {
fut_b: B::Future, fut_b: B::Future,
fut_a: A::Future, fut_a: A::Future,
@@ -178,10 +195,15 @@ where
b: Option<B::Service>, b: Option<B::Service>,
} }
impl<A, B, R, C> ThenNewServiceFuture<A, B, R, C> impl<A, B, C> ThenNewServiceFuture<A, B, C>
where where
A: NewService<R, C>, A: NewService<C>,
B: NewService<Result<A::Response, A::Error>, C, Error = A::Error, InitError = A::InitError>, B: NewService<
C,
Request = Result<A::Response, A::Error>,
Error = A::Error,
InitError = A::InitError,
>,
{ {
fn new(fut_a: A::Future, fut_b: B::Future) -> Self { fn new(fut_a: A::Future, fut_b: B::Future) -> Self {
ThenNewServiceFuture { ThenNewServiceFuture {
@@ -193,10 +215,15 @@ where
} }
} }
impl<A, B, R, C> Future for ThenNewServiceFuture<A, B, R, C> impl<A, B, C> Future for ThenNewServiceFuture<A, B, C>
where where
A: NewService<R, C>, A: NewService<C>,
B: NewService<Result<A::Response, A::Error>, C, Error = A::Error, InitError = A::InitError>, B: NewService<
C,
Request = Result<A::Response, A::Error>,
Error = A::Error,
InitError = A::InitError,
>,
{ {
type Item = Then<A::Service, B::Service>; type Item = Then<A::Service, B::Service>;
type Error = A::InitError; type Error = A::InitError;
@@ -236,7 +263,8 @@ mod tests {
#[derive(Clone)] #[derive(Clone)]
struct Srv1(Rc<Cell<usize>>); struct Srv1(Rc<Cell<usize>>);
impl Service<Result<&'static str, &'static str>> for Srv1 { impl Service for Srv1 {
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 = FutureResult<Self::Response, Self::Error>;
@@ -256,7 +284,8 @@ mod tests {
struct Srv2(Rc<Cell<usize>>); struct Srv2(Rc<Cell<usize>>);
impl Service<Result<&'static str, ()>> for Srv2 { impl Service for Srv2 {
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 = FutureResult<Self::Response, ()>;

View File

@@ -3,16 +3,17 @@ use std::sync::Arc;
use futures::{Async, Future, IntoFuture, Poll}; use futures::{Async, Future, IntoFuture, Poll};
use crate::transform_map_init_err::TransformMapInitErr; use crate::transform_err::{TransformFromErr, TransformMapInitErr};
use crate::{NewService, Service}; use crate::{IntoNewService, NewService, Service};
/// `Transform` service factory. /// `Transform` service factory.
/// ///
/// Transform factory creates service that wraps other services. /// Transform factory creates service that wraps other services.
/// /// `Config` is a service factory configuration type.
/// * `S` is a wrapped service. pub trait Transform<S> {
/// * `R` requests handled by this transform service. /// Requests handled by the service.
pub trait Transform<S, R> { type Request;
/// Responses given by the service. /// Responses given by the service.
type Response; type Response;
@@ -20,7 +21,11 @@ pub trait Transform<S, R> {
type Error; type Error;
/// The `TransformService` value created by this factory /// The `TransformService` value created by this factory
type Transform: Service<R, Response = Self::Response, Error = Self::Error>; type Transform: Service<
Request = Self::Request,
Response = Self::Response,
Error = Self::Error,
>;
/// Errors produced while building a service. /// Errors produced while building a service.
type InitError; type InitError;
@@ -31,7 +36,7 @@ pub trait Transform<S, R> {
/// Create and return a new service value asynchronously. /// Create and return a new service value asynchronously.
fn new_transform(&self, service: S) -> Self::Future; fn new_transform(&self, service: S) -> Self::Future;
/// Map this service's factory init error to a different error, /// Map this service's factory error to a different error,
/// returning a new transform service factory. /// returning a new transform service factory.
fn map_init_err<F, E>(self, f: F) -> TransformMapInitErr<Self, S, F, E> fn map_init_err<F, E>(self, f: F) -> TransformMapInitErr<Self, S, F, E>
where where
@@ -40,12 +45,39 @@ pub trait Transform<S, R> {
{ {
TransformMapInitErr::new(self, f) TransformMapInitErr::new(self, f)
} }
/// Map this service's init error to any error implementing `From` for
/// this service`s `Error`.
///
/// Note that this function consumes the receiving transform and returns a
/// wrapped version of it.
fn from_err<E>(self) -> TransformFromErr<Self, S, E>
where
Self: Sized,
E: From<Self::InitError>,
{
TransformFromErr::new(self)
}
// /// Map this service's init error to service's init error
// /// if it is implementing `Into` to this service`s `InitError`.
// ///
// /// Note that this function consumes the receiving transform and returns a
// /// wrapped version of it.
// fn into_err<E>(self) -> TransformIntoErr<Self, S>
// where
// Self: Sized,
// Self::InitError: From<Self::InitError>,
// {
// TransformFromErr::new(self)
// }
} }
impl<T, S, R> Transform<S, R> for Rc<T> impl<T, S> Transform<S> for Rc<T>
where where
T: Transform<S, R>, T: Transform<S>,
{ {
type Request = T::Request;
type Response = T::Response; type Response = T::Response;
type Error = T::Error; type Error = T::Error;
type InitError = T::InitError; type InitError = T::InitError;
@@ -57,10 +89,11 @@ where
} }
} }
impl<T, S, R> Transform<S, R> for Arc<T> impl<T, S> Transform<S> for Arc<T>
where where
T: Transform<S, R>, T: Transform<S>,
{ {
type Request = T::Request;
type Response = T::Response; type Response = T::Response;
type Error = T::Error; type Error = T::Error;
type InitError = T::InitError; type InitError = T::InitError;
@@ -73,81 +106,114 @@ where
} }
/// Trait for types that can be converted to a *transform service* /// Trait for types that can be converted to a *transform service*
pub trait IntoTransform<T, S, R> pub trait IntoTransform<T, S>
where where
T: Transform<S, R>, T: Transform<S>,
{ {
/// Convert to a `TransformService` /// Convert to a `TransformService`
fn into_transform(self) -> T; fn into_transform(self) -> T;
} }
impl<T, S, R> IntoTransform<T, S, R> for T impl<T, S> IntoTransform<T, S> for T
where where
T: Transform<S, R>, T: Transform<S>,
{ {
fn into_transform(self) -> T { fn into_transform(self) -> T {
self self
} }
} }
/// `Apply` transform new service /// Apply transform to service factory. Function returns
#[derive(Clone)] /// services factory that in initialization creates
pub struct ApplyTransform<T, S, R, Req, Cfg> { /// service and applies transform to this service.
a: S, pub fn apply_transform<T, S, C, F, U>(
t: Rc<T>, t: F,
_t: std::marker::PhantomData<(R, Req, Cfg)>, service: U,
) -> impl NewService<
C,
Request = T::Request,
Response = T::Response,
Error = T::Error,
Service = T::Transform,
InitError = S::InitError,
> + Clone
where
S: NewService<C>,
T: Transform<S::Service, InitError = S::InitError>,
F: IntoTransform<T, S::Service>,
U: IntoNewService<S, C>,
{
ApplyTransform::new(t.into_transform(), service.into_new_service())
} }
impl<T, S, R, Req, Cfg> ApplyTransform<T, S, R, Req, Cfg> /// `Apply` transform to new service
pub struct ApplyTransform<T, S, C> {
s: Rc<S>,
t: Rc<T>,
_t: std::marker::PhantomData<C>,
}
impl<T, S, C> ApplyTransform<T, S, C>
where where
S: NewService<Req, Cfg>, S: NewService<C>,
T: Transform<S::Service, R, Error = S::Error, InitError = S::InitError>, T: Transform<S::Service, InitError = S::InitError>,
{ {
/// Create new `ApplyNewService` new service instance /// Create new `ApplyTransform` new service instance
pub fn new<F: IntoTransform<T, S::Service, R>>(t: F, a: S) -> Self { pub fn new<F: IntoTransform<T, S::Service>>(t: F, service: S) -> Self {
Self { Self {
a, s: Rc::new(service),
t: Rc::new(t.into_transform()), t: Rc::new(t.into_transform()),
_t: std::marker::PhantomData, _t: std::marker::PhantomData,
} }
} }
} }
impl<T, S, R, Req, Cfg> NewService<R, Cfg> for ApplyTransform<T, S, R, Req, Cfg> impl<T, S, C> Clone for ApplyTransform<T, S, C> {
fn clone(&self) -> Self {
ApplyTransform {
s: self.s.clone(),
t: self.t.clone(),
_t: std::marker::PhantomData,
}
}
}
impl<T, S, C> NewService<C> for ApplyTransform<T, S, C>
where where
S: NewService<Req, Cfg>, S: NewService<C>,
T: Transform<S::Service, R, Error = S::Error, InitError = S::InitError>, T: Transform<S::Service, InitError = S::InitError>,
{ {
type Request = T::Request;
type Response = T::Response; type Response = T::Response;
type Error = T::Error; type Error = T::Error;
type Service = T::Transform; type Service = T::Transform;
type InitError = T::InitError; type InitError = T::InitError;
type Future = ApplyTransformFuture<T, S, R, Req, Cfg>; type Future = ApplyTransformFuture<T, S, C>;
fn new_service(&self, cfg: &Cfg) -> Self::Future { fn new_service(&self, cfg: &C) -> Self::Future {
ApplyTransformFuture { ApplyTransformFuture {
t_cell: self.t.clone(), t_cell: self.t.clone(),
fut_a: self.a.new_service(cfg).into_future(), fut_a: self.s.new_service(cfg).into_future(),
fut_t: None, fut_t: None,
} }
} }
} }
pub struct ApplyTransformFuture<T, S, R, Req, Cfg> pub struct ApplyTransformFuture<T, S, C>
where where
S: NewService<Req, Cfg>, S: NewService<C>,
T: Transform<S::Service, R, Error = S::Error, InitError = S::InitError>, T: Transform<S::Service, InitError = S::InitError>,
{ {
fut_a: S::Future, fut_a: S::Future,
fut_t: Option<T::Future>, fut_t: Option<<T::Future as IntoFuture>::Future>,
t_cell: Rc<T>, t_cell: Rc<T>,
} }
impl<T, S, R, Req, Cfg> Future for ApplyTransformFuture<T, S, R, Req, Cfg> impl<T, S, C> Future for ApplyTransformFuture<T, S, C>
where where
S: NewService<Req, Cfg>, S: NewService<C>,
T: Transform<S::Service, R, Error = S::Error, InitError = S::InitError>, T: Transform<S::Service, InitError = S::InitError>,
{ {
type Item = T::Transform; type Item = T::Transform;
type Error = T::InitError; type Error = T::InitError;

View File

@@ -0,0 +1,162 @@
use std::marker::PhantomData;
use futures::{Future, Poll};
use super::Transform;
/// Transform for the `map_err` combinator, changing the type of a new
/// transform's init error.
///
/// This is created by the `Transform::map_err` method.
pub struct TransformMapInitErr<T, S, F, E> {
t: T,
f: F,
e: PhantomData<(S, E)>,
}
impl<T, S, F, E> TransformMapInitErr<T, S, F, E> {
/// Create new `TransformMapErr` new transform instance
pub fn new(t: T, f: F) -> Self
where
T: Transform<S>,
F: Fn(T::InitError) -> E,
{
Self {
t,
f,
e: PhantomData,
}
}
}
impl<T, S, F, E> Clone for TransformMapInitErr<T, S, F, E>
where
T: Clone,
F: Clone,
{
fn clone(&self) -> Self {
Self {
t: self.t.clone(),
f: self.f.clone(),
e: PhantomData,
}
}
}
impl<T, S, F, E> Transform<S> for TransformMapInitErr<T, S, F, E>
where
T: Transform<S>,
F: Fn(T::InitError) -> E + Clone,
{
type Request = T::Request;
type Response = T::Response;
type Error = T::Error;
type Transform = T::Transform;
type InitError = E;
type Future = TransformMapInitErrFuture<T, S, F, E>;
fn new_transform(&self, service: S) -> Self::Future {
TransformMapInitErrFuture {
fut: self.t.new_transform(service),
f: self.f.clone(),
}
}
}
pub struct TransformMapInitErrFuture<T, S, F, E>
where
T: Transform<S>,
F: Fn(T::InitError) -> E,
{
fut: T::Future,
f: F,
}
impl<T, S, F, E> Future for TransformMapInitErrFuture<T, S, F, E>
where
T: Transform<S>,
F: Fn(T::InitError) -> E + Clone,
{
type Item = T::Transform;
type Error = E;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
self.fut.poll().map_err(&self.f)
}
}
/// Transform for the `from_err` combinator, changing the type of a new
/// transform's init error.
///
/// This is created by the `Transform::from_err` method.
pub struct TransformFromErr<T, S, E> {
t: T,
e: PhantomData<(S, E)>,
}
impl<T, S, E> TransformFromErr<T, S, E>
where
T: Transform<S>,
E: From<T::InitError>,
{
/// Create new `TransformFromErr` new transform instance
pub fn new(t: T) -> Self {
Self { t, e: PhantomData }
}
}
impl<T, S, E> Clone for TransformFromErr<T, S, E>
where
T: Clone,
{
fn clone(&self) -> Self {
Self {
t: self.t.clone(),
e: PhantomData,
}
}
}
impl<T, S, E> Transform<S> for TransformFromErr<T, S, E>
where
T: Transform<S>,
E: From<T::InitError>,
{
type Request = T::Request;
type Response = T::Response;
type Error = T::Error;
type Transform = T::Transform;
type InitError = E;
type Future = TransformFromErrFuture<T, S, E>;
fn new_transform(&self, service: S) -> Self::Future {
TransformFromErrFuture {
fut: self.t.new_transform(service),
_t: PhantomData,
}
}
}
pub struct TransformFromErrFuture<T, S, E>
where
T: Transform<S>,
E: From<T::InitError>,
{
fut: T::Future,
_t: PhantomData<E>,
}
impl<T, S, E> Future for TransformFromErrFuture<T, S, E>
where
T: Transform<S>,
E: From<T::InitError>,
{
type Item = T::Transform;
type Error = E;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
self.fut.poll().map_err(E::from)
}
}

View File

@@ -1,93 +0,0 @@
use std::marker::PhantomData;
use futures::{Future, Poll};
use super::Transform;
/// NewTransform for the `map_init_err` combinator, changing the type of a new
/// transform's error.
///
/// This is created by the `NewTransform::map_init_err` method.
pub struct TransformMapInitErr<T, S, F, E> {
t: T,
f: F,
e: PhantomData<(S, E)>,
}
impl<T, S, F, E> TransformMapInitErr<T, S, F, E> {
/// Create new `MapInitErr` new transform instance
pub fn new<R>(t: T, f: F) -> Self
where
T: Transform<S, R>,
F: Fn(T::InitError) -> E,
{
Self {
t,
f,
e: PhantomData,
}
}
}
impl<T, S, F, E> Clone for TransformMapInitErr<T, S, F, E>
where
T: Clone,
F: Clone,
{
fn clone(&self) -> Self {
Self {
t: self.t.clone(),
f: self.f.clone(),
e: PhantomData,
}
}
}
impl<T, R, S, F, E> Transform<S, R> for TransformMapInitErr<T, S, F, E>
where
T: Transform<S, R>,
F: Fn(T::InitError) -> E + Clone,
{
type Response = T::Response;
type Error = T::Error;
type Transform = T::Transform;
type InitError = E;
type Future = TransformMapInitErrFuture<T, R, S, F, E>;
fn new_transform(&self, service: S) -> Self::Future {
TransformMapInitErrFuture::new(self.t.new_transform(service), self.f.clone())
}
}
pub struct TransformMapInitErrFuture<T, R, S, F, E>
where
T: Transform<S, R>,
F: Fn(T::InitError) -> E,
{
fut: T::Future,
f: F,
}
impl<T, R, S, F, E> TransformMapInitErrFuture<T, R, S, F, E>
where
T: Transform<S, R>,
F: Fn(T::InitError) -> E,
{
fn new(fut: T::Future, f: F) -> Self {
TransformMapInitErrFuture { f, fut }
}
}
impl<T, R, S, F, E> Future for TransformMapInitErrFuture<T, R, S, F, E>
where
T: Transform<S, R>,
F: Fn(T::InitError) -> E + Clone,
{
type Item = T::Transform;
type Error = E;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
self.fut.poll().map_err(&self.f)
}
}

View File

@@ -33,8 +33,8 @@ ssl = ["openssl", "actix-server/ssl"]
rust-tls = ["rustls", "tokio-rustls", "webpki", "webpki-roots"] rust-tls = ["rustls", "tokio-rustls", "webpki", "webpki-roots"]
[dependencies] [dependencies]
actix-rt = "0.1.0" actix-rt = "0.2.0"
#actix-server = "0.3.0" # actix-server = "0.3.3"
actix-server = { path="../actix-server" } actix-server = { path="../actix-server" }
log = "0.4" log = "0.4"
@@ -54,3 +54,6 @@ rustls = { version = "^0.15", optional = true }
tokio-rustls = { version = "^0.9", optional = true } tokio-rustls = { version = "^0.9", optional = true }
webpki = { version = "0.19", optional = true } webpki = { version = "0.19", optional = true }
webpki-roots = { version = "0.16", optional = true } webpki-roots = { version = "0.16", optional = true }
[dev-dependencies]
actix-service = "0.3.3"

View File

@@ -13,27 +13,24 @@ use tokio_tcp::TcpStream;
/// The `TestServer` type. /// The `TestServer` type.
/// ///
/// `TestServer` is very simple test server that simplify process of writing /// `TestServer` is very simple test server that simplify process of writing
/// integration tests cases for actix applications. /// integration tests for actix-net applications.
/// ///
/// # Examples /// # Examples
/// ///
/// ```rust /// ```rust
/// # extern crate actix_test_server; /// use actix_service::{fn_service, IntoNewService};
/// # use actix_web::*;
/// #
/// # fn my_handler(req: &HttpRequest) -> HttpResponse {
/// # HttpResponse::Ok().into()
/// # }
/// #
/// # fn main() {
/// use actix_test_server::TestServer; /// use actix_test_server::TestServer;
/// ///
/// let mut srv = TestServer::new(|app| app.handler(my_handler)); /// fn main() {
/// let srv = TestServer::with(|| fn_service(
/// |sock| {
/// println!("New connection: {:?}", sock);
/// Ok::<_, ()>(())
/// }
/// ));
/// ///
/// let req = srv.get().finish().unwrap(); /// println!("SOCKET: {:?}", srv.connect());
/// let response = srv.execute(req.send()).unwrap(); /// }
/// assert!(response.status().is_success());
/// # }
/// ``` /// ```
pub struct TestServer; pub struct TestServer;
@@ -57,13 +54,13 @@ impl TestServer {
let local_addr = tcp.local_addr().unwrap(); let local_addr = tcp.local_addr().unwrap();
Server::build() Server::build()
.listen("test", tcp, factory) .listen("test", tcp, factory)?
.workers(1) .workers(1)
.disable_signals() .disable_signals()
.start(); .start();
tx.send((System::current(), local_addr)).unwrap(); tx.send((System::current(), local_addr)).unwrap();
sys.run(); sys.run()
}); });
let (system, addr) = rx.recv().unwrap(); let (system, addr) = rx.recv().unwrap();

View File

@@ -1,8 +1,25 @@
# Changes # Changes
## [0.4.0] - 2019-03-xx ## [0.3.4] - 2019-03-12
* Upgrade actix-service ### Changed
* `TimeoutService`, `InOrderService`, `InFlightService` accepts generic IntoService services.
### Fixed
* Fix `InFlightService::poll_ready()` nested service readiness check
* Fix `InOrderService::poll_ready()` nested service readiness check
## [0.3.3] - 2019-03-09
### Changed
* Revert IntoFuture change
* Add generic config param for IntoFramed and TakeOne new services
## [0.3.2] - 2019-03-04 ## [0.3.2] - 2019-03-04

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "actix-utils" name = "actix-utils"
version = "0.3.2" version = "0.3.4"
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"]
@@ -18,9 +18,8 @@ name = "actix_utils"
path = "src/lib.rs" path = "src/lib.rs"
[dependencies] [dependencies]
#actix-service = "0.3.2" actix-service = "0.3.3"
actix-service = { path="../actix-service" } actix-codec = "0.1.1"
actix-codec = "0.1.0"
bytes = "0.4" bytes = "0.4"
futures = "0.1.24" futures = "0.1.24"
tokio-timer = "0.2.8" tokio-timer = "0.2.8"
@@ -28,4 +27,4 @@ tokio-current-thread = "0.1.4"
log = "0.4" log = "0.4"
[dev-dependencies] [dev-dependencies]
actix-rt = "0.1" actix-rt = "0.2.1"

View File

@@ -13,9 +13,9 @@ pub struct CloneableService<T: 'static> {
} }
impl<T: 'static> CloneableService<T> { impl<T: 'static> CloneableService<T> {
pub fn new<R>(service: T) -> Self pub fn new(service: T) -> Self
where where
T: Service<R>, T: Service,
{ {
Self { Self {
service: Cell::new(service), service: Cell::new(service),
@@ -33,10 +33,11 @@ impl<T: 'static> Clone for CloneableService<T> {
} }
} }
impl<T, R> Service<R> for CloneableService<T> impl<T> Service for CloneableService<T>
where where
T: Service<R> + 'static, T: Service + 'static,
{ {
type Request = T::Request;
type Response = T::Response; type Response = T::Response;
type Error = T::Error; type Error = T::Error;
type Future = T::Future; type Future = T::Future;
@@ -45,7 +46,7 @@ where
self.service.get_mut().poll_ready() self.service.get_mut().poll_ready()
} }
fn call(&mut self, req: R) -> Self::Future { fn call(&mut self, req: T::Request) -> Self::Future {
self.service.get_mut().call(req) self.service.get_mut().call(req)
} }
} }

View File

@@ -21,11 +21,12 @@ impl<A: Clone, B: Clone> Clone for EitherService<A, B> {
} }
} }
impl<A, B, R> Service<R> for EitherService<A, B> impl<A, B> Service for EitherService<A, B>
where where
A: Service<R>, A: Service,
B: Service<R, Response = A::Response, Error = A::Error>, B: Service<Request = A::Request, Response = A::Response, Error = A::Error>,
{ {
type Request = A::Request;
type Response = A::Response; type Response = A::Response;
type Error = A::Error; type Error = A::Error;
type Future = future::Either<A::Future, B::Future>; type Future = future::Either<A::Future, B::Future>;
@@ -37,7 +38,7 @@ where
} }
} }
fn call(&mut self, req: R) -> Self::Future { fn call(&mut self, req: A::Request) -> Self::Future {
match self { match self {
EitherService::A(ref mut inner) => future::Either::A(inner.call(req)), EitherService::A(ref mut inner) => future::Either::A(inner.call(req)),
EitherService::B(ref mut inner) => future::Either::B(inner.call(req)), EitherService::B(ref mut inner) => future::Either::B(inner.call(req)),
@@ -52,33 +53,52 @@ pub enum Either<A, B> {
} }
impl<A, B> Either<A, B> { impl<A, B> Either<A, B> {
pub fn new_a<R, C>(srv: A) -> Self pub fn new_a<C>(srv: A) -> Self
where where
A: NewService<R, C>, A: NewService<C>,
B: NewService<R, C, Response = A::Response, Error = A::Error, InitError = A::InitError>, B: NewService<
C,
Request = A::Request,
Response = A::Response,
Error = A::Error,
InitError = A::InitError,
>,
{ {
Either::A(srv) Either::A(srv)
} }
pub fn new_b<R, C>(srv: B) -> Self pub fn new_b<C>(srv: B) -> Self
where where
A: NewService<R, C>, A: NewService<C>,
B: NewService<R, C, Response = A::Response, Error = A::Error, InitError = A::InitError>, B: NewService<
C,
Request = A::Request,
Response = A::Response,
Error = A::Error,
InitError = A::InitError,
>,
{ {
Either::B(srv) Either::B(srv)
} }
} }
impl<A, B, R, C> NewService<R, C> for Either<A, B> impl<A, B, C> NewService<C> for Either<A, B>
where where
A: NewService<R, C>, A: NewService<C>,
B: NewService<R, C, Response = A::Response, Error = A::Error, InitError = A::InitError>, B: NewService<
C,
Request = A::Request,
Response = A::Response,
Error = A::Error,
InitError = A::InitError,
>,
{ {
type Request = A::Request;
type Response = A::Response; type Response = A::Response;
type Error = A::Error; type Error = A::Error;
type InitError = A::InitError; type InitError = A::InitError;
type Service = EitherService<A::Service, B::Service>; type Service = EitherService<A::Service, B::Service>;
type Future = EitherNewService<A, B, R, C>; type Future = EitherNewService<A, B, C>;
fn new_service(&self, cfg: &C) -> Self::Future { fn new_service(&self, cfg: &C) -> Self::Future {
match self { match self {
@@ -98,15 +118,21 @@ impl<A: Clone, B: Clone> Clone for Either<A, B> {
} }
#[doc(hidden)] #[doc(hidden)]
pub enum EitherNewService<A: NewService<R, C>, B: NewService<R, C>, R, C> { pub enum EitherNewService<A: NewService<C>, B: NewService<C>, C> {
A(<A::Future as IntoFuture>::Future), A(<A::Future as IntoFuture>::Future),
B(<B::Future as IntoFuture>::Future), B(<B::Future as IntoFuture>::Future),
} }
impl<A, B, R, C> Future for EitherNewService<A, B, R, C> impl<A, B, C> Future for EitherNewService<A, B, C>
where where
A: NewService<R, C>, A: NewService<C>,
B: NewService<R, C, Response = A::Response, Error = A::Error, InitError = A::InitError>, B: NewService<
C,
Request = A::Request,
Response = A::Response,
Error = A::Error,
InitError = A::InitError,
>,
{ {
type Item = EitherService<A::Service, B::Service>; type Item = EitherService<A::Service, B::Service>;
type Error = A::InitError; type Error = A::InitError;

View File

@@ -23,15 +23,15 @@ pub struct FramedNewService<S, T, U, C> {
impl<S, T, U, C> FramedNewService<S, T, U, C> impl<S, T, U, C> FramedNewService<S, T, U, C>
where where
C: Clone, C: Clone,
S: NewService<Request<U>, C, Response = Response<U>>, S: NewService<C, Request = Request<U>, Response = Response<U>>,
S::Error: 'static, S::Error: 'static,
<S::Service as Service<Request<U>>>::Future: 'static, <S::Service as Service>::Future: 'static,
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
U: Decoder + Encoder, U: Decoder + Encoder,
<U as Encoder>::Item: 'static, <U as Encoder>::Item: 'static,
<U as Encoder>::Error: std::fmt::Debug, <U as Encoder>::Error: std::fmt::Debug,
{ {
pub fn new<F1: IntoNewService<S, Request<U>, C>>(factory: F1) -> Self { pub fn new<F1: IntoNewService<S, C>>(factory: F1) -> Self {
Self { Self {
factory: factory.into_new_service(), factory: factory.into_new_service(),
_t: PhantomData, _t: PhantomData,
@@ -51,17 +51,18 @@ where
} }
} }
impl<S, T, U, C> NewService<Framed<T, U>, C> for FramedNewService<S, T, U, C> impl<S, T, U, C> NewService<C> for FramedNewService<S, T, U, C>
where where
C: Clone, C: Clone,
S: NewService<Request<U>, C, Response = Response<U>> + Clone, S: NewService<C, Request = Request<U>, Response = Response<U>> + Clone,
S::Error: 'static, S::Error: 'static,
<S::Service as Service<Request<U>>>::Future: 'static, <S::Service as Service>::Future: 'static,
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
U: Decoder + Encoder, U: Decoder + Encoder,
<U as Encoder>::Item: 'static, <U as Encoder>::Item: 'static,
<U as Encoder>::Error: std::fmt::Debug, <U as Encoder>::Error: std::fmt::Debug,
{ {
type Request = Framed<T, U>;
type Response = FramedTransport<S::Service, T, U>; type Response = FramedTransport<S::Service, T, U>;
type Error = S::InitError; type Error = S::InitError;
type InitError = S::InitError; type InitError = S::InitError;
@@ -97,17 +98,18 @@ where
} }
} }
impl<S, T, U, C> Service<Framed<T, U>> for FramedService<S, T, U, C> impl<S, T, U, C> Service for FramedService<S, T, U, C>
where where
S: NewService<Request<U>, C, Response = Response<U>>, S: NewService<C, Request = Request<U>, Response = Response<U>>,
S::Error: 'static, S::Error: 'static,
<S::Service as Service<Request<U>>>::Future: 'static, <S::Service as Service>::Future: 'static,
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
U: Decoder + Encoder, U: Decoder + Encoder,
<U as Encoder>::Item: 'static, <U as Encoder>::Item: 'static,
<U as Encoder>::Error: std::fmt::Debug, <U as Encoder>::Error: std::fmt::Debug,
C: Clone, C: Clone,
{ {
type Request = Framed<T, U>;
type Response = FramedTransport<S::Service, T, U>; type Response = FramedTransport<S::Service, T, U>;
type Error = S::InitError; type Error = S::InitError;
type Future = FramedServiceResponseFuture<S, T, U, C>; type Future = FramedServiceResponseFuture<S, T, U, C>;
@@ -127,9 +129,9 @@ where
#[doc(hidden)] #[doc(hidden)]
pub struct FramedServiceResponseFuture<S, T, U, C> pub struct FramedServiceResponseFuture<S, T, U, C>
where where
S: NewService<Request<U>, C, Response = Response<U>>, S: NewService<C, Request = Request<U>, Response = Response<U>>,
S::Error: 'static, S::Error: 'static,
<S::Service as Service<Request<U>>>::Future: 'static, <S::Service as Service>::Future: 'static,
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
U: Decoder + Encoder, U: Decoder + Encoder,
<U as Encoder>::Item: 'static, <U as Encoder>::Item: 'static,
@@ -141,9 +143,9 @@ where
impl<S, T, U, C> Future for FramedServiceResponseFuture<S, T, U, C> impl<S, T, U, C> Future for FramedServiceResponseFuture<S, T, U, C>
where where
S: NewService<Request<U>, C, Response = Response<U>>, S: NewService<C, Request = Request<U>, Response = Response<U>>,
S::Error: 'static, S::Error: 'static,
<S::Service as Service<Request<U>>>::Future: 'static, <S::Service as Service>::Future: 'static,
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
U: Decoder + Encoder, U: Decoder + Encoder,
<U as Encoder>::Item: 'static, <U as Encoder>::Item: 'static,
@@ -180,7 +182,7 @@ impl<E, U: Encoder + Decoder> From<E> for FramedTransportError<E, U> {
/// and pass then to the service. /// and pass then to the service.
pub struct FramedTransport<S, T, U> pub struct FramedTransport<S, T, U>
where where
S: Service<Request<U>, Response = Response<U>>, S: Service<Request = Request<U>, Response = Response<U>>,
S::Error: 'static, S::Error: 'static,
S::Future: 'static, S::Future: 'static,
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
@@ -194,7 +196,7 @@ where
inner: Cell<FramedTransportInner<<U as Encoder>::Item, S::Error>>, inner: Cell<FramedTransportInner<<U as Encoder>::Item, S::Error>>,
} }
enum TransportState<S: Service<Request<U>>, U: Encoder + Decoder> { enum TransportState<S: Service, U: Encoder + Decoder> {
Processing, Processing,
Error(FramedTransportError<S::Error, U>), Error(FramedTransportError<S::Error, U>),
FramedError(FramedTransportError<S::Error, U>), FramedError(FramedTransportError<S::Error, U>),
@@ -208,7 +210,7 @@ struct FramedTransportInner<I, E> {
impl<S, T, U> FramedTransport<S, T, U> impl<S, T, U> FramedTransport<S, T, U>
where where
S: Service<Request<U>, Response = Response<U>>, S: Service<Request = Request<U>, Response = Response<U>>,
S::Error: 'static, S::Error: 'static,
S::Future: 'static, S::Future: 'static,
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
@@ -219,7 +221,7 @@ where
fn poll_read(&mut self) -> bool { fn poll_read(&mut self) -> bool {
loop { loop {
match self.service.poll_ready() { match self.service.poll_ready() {
Ok(Async::Ready(_)) => loop { Ok(Async::Ready(_)) => {
let item = match self.framed.poll() { let item = match self.framed.poll() {
Ok(Async::Ready(Some(el))) => el, Ok(Async::Ready(Some(el))) => el,
Err(err) => { Err(err) => {
@@ -242,7 +244,7 @@ where
inner.task.notify(); inner.task.notify();
Ok(()) Ok(())
})); }));
}, }
Ok(Async::NotReady) => return false, Ok(Async::NotReady) => return false,
Err(err) => { Err(err) => {
self.state = TransportState::Error(FramedTransportError::Service(err)); self.state = TransportState::Error(FramedTransportError::Service(err));
@@ -300,7 +302,7 @@ where
impl<S, T, U> FramedTransport<S, T, U> impl<S, T, U> FramedTransport<S, T, U>
where where
S: Service<Request<U>, Response = Response<U>>, S: Service<Request = Request<U>, Response = Response<U>>,
S::Error: 'static, S::Error: 'static,
S::Future: 'static, S::Future: 'static,
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
@@ -308,7 +310,7 @@ where
<U as Encoder>::Item: 'static, <U as Encoder>::Item: 'static,
<U as Encoder>::Error: std::fmt::Debug, <U as Encoder>::Error: std::fmt::Debug,
{ {
pub fn new<F: IntoService<S, Request<U>>>(framed: Framed<T, U>, service: F) -> Self { pub fn new<F: IntoService<S>>(framed: Framed<T, U>, service: F) -> Self {
FramedTransport { FramedTransport {
framed, framed,
service: service.into_service(), service: service.into_service(),
@@ -346,7 +348,7 @@ where
impl<S, T, U> Future for FramedTransport<S, T, U> impl<S, T, U> Future for FramedTransport<S, T, U>
where where
S: Service<Request<U>, Response = Response<U>>, S: Service<Request = Request<U>, Response = Response<U>>,
S::Error: 'static, S::Error: 'static,
S::Future: 'static, S::Future: 'static,
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
@@ -406,19 +408,20 @@ where
} }
} }
impl<T, U, F> NewService<T, ()> for IntoFramed<T, U, F> impl<T, C, U, F> NewService<C> for IntoFramed<T, U, F>
where where
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
F: Fn() -> U + Send + Clone + 'static, F: Fn() -> U + Send + Clone + 'static,
U: Encoder + Decoder, U: Encoder + Decoder,
{ {
type Request = T;
type Response = Framed<T, U>; type Response = Framed<T, U>;
type Error = (); type Error = ();
type InitError = (); type InitError = ();
type Service = IntoFramedService<T, U, F>; type Service = IntoFramedService<T, U, F>;
type Future = FutureResult<Self::Service, Self::InitError>; type Future = FutureResult<Self::Service, Self::InitError>;
fn new_service(&self, _: &()) -> Self::Future { fn new_service(&self, _: &C) -> Self::Future {
ok(IntoFramedService { ok(IntoFramedService {
factory: self.factory.clone(), factory: self.factory.clone(),
_t: PhantomData, _t: PhantomData,
@@ -436,12 +439,13 @@ where
_t: PhantomData<(T,)>, _t: PhantomData<(T,)>,
} }
impl<T, U, F> Service<T> for IntoFramedService<T, U, F> impl<T, U, F> Service for IntoFramedService<T, U, F>
where where
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
F: Fn() -> U + Send + Clone + 'static, F: Fn() -> U + Send + Clone + 'static,
U: Encoder + Decoder, U: Encoder + Decoder,
{ {
type Request = T;
type Response = Framed<T, U>; type Response = Framed<T, U>;
type Error = (); type Error = ();
type Future = FutureResult<Self::Response, Self::Error>; type Future = FutureResult<Self::Response, Self::Error>;

View File

@@ -1,4 +1,4 @@
use actix_service::{Service, Transform, Void}; use actix_service::{IntoService, Service, Transform, Void};
use futures::future::{ok, FutureResult}; use futures::future::{ok, FutureResult};
use futures::{Async, Future, Poll}; use futures::{Async, Future, Poll};
@@ -24,7 +24,8 @@ impl Default for InFlight {
} }
} }
impl<S: Service<R>, R> Transform<S, R> for InFlight { impl<S: Service> Transform<S> for InFlight {
type Request = S::Request;
type Response = S::Response; type Response = S::Response;
type Error = S::Error; type Error = S::Error;
type InitError = Void; type InitError = Void;
@@ -41,27 +42,34 @@ pub struct InFlightService<S> {
service: S, service: S,
} }
impl<S> InFlightService<S> { impl<S> InFlightService<S>
pub fn new(max: usize, service: S) -> Self { where
S: Service,
{
pub fn new<U>(max: usize, service: U) -> Self
where
U: IntoService<S>,
{
Self { Self {
service,
count: Counter::new(max), count: Counter::new(max),
service: service.into_service(),
} }
} }
} }
impl<T, R> Service<R> for InFlightService<T> impl<T> Service for InFlightService<T>
where where
T: Service<R>, T: Service,
{ {
type Request = T::Request;
type Response = T::Response; type Response = T::Response;
type Error = T::Error; type Error = T::Error;
type Future = InFlightServiceResponse<T, R>; type Future = InFlightServiceResponse<T>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.service.poll_ready()?; if let Async::NotReady = self.service.poll_ready()? {
Ok(Async::NotReady)
if !self.count.available() { } else if !self.count.available() {
log::trace!("InFlight limit exceeded"); log::trace!("InFlight limit exceeded");
Ok(Async::NotReady) Ok(Async::NotReady)
} else { } else {
@@ -69,7 +77,7 @@ where
} }
} }
fn call(&mut self, req: R) -> Self::Future { fn call(&mut self, req: T::Request) -> Self::Future {
InFlightServiceResponse { InFlightServiceResponse {
fut: self.service.call(req), fut: self.service.call(req),
_guard: self.count.get(), _guard: self.count.get(),
@@ -78,12 +86,12 @@ where
} }
#[doc(hidden)] #[doc(hidden)]
pub struct InFlightServiceResponse<T: Service<R>, R> { pub struct InFlightServiceResponse<T: Service> {
fut: T::Future, fut: T::Future,
_guard: CounterGuard, _guard: CounterGuard,
} }
impl<T: Service<R>, R> Future for InFlightServiceResponse<T, R> { impl<T: Service> Future for InFlightServiceResponse<T> {
type Item = T::Response; type Item = T::Response;
type Error = T::Error; type Error = T::Error;
@@ -105,7 +113,8 @@ mod tests {
struct SleepService(Duration); struct SleepService(Duration);
impl Service<()> for SleepService { impl Service for SleepService {
type Request = ();
type Response = (); type Response = ();
type Error = (); type Error = ();
type Future = Box<Future<Item = (), Error = ()>>; type Future = Box<Future<Item = (), Error = ()>>;

View File

@@ -43,10 +43,11 @@ where
} }
} }
impl<R, E, F> NewService<R, ()> for KeepAlive<R, E, F> impl<R, E, F> NewService<()> for KeepAlive<R, E, F>
where where
F: Fn() -> E + Clone, F: Fn() -> E + Clone,
{ {
type Request = R;
type Response = R; type Response = R;
type Error = E; type Error = E;
type InitError = Void; type InitError = Void;
@@ -88,10 +89,11 @@ where
} }
} }
impl<R, E, F> Service<R> for KeepAliveService<R, E, F> impl<R, E, F> Service for KeepAliveService<R, E, F>
where where
F: Fn() -> E, F: Fn() -> E,
{ {
type Request = R;
type Response = R; type Response = R;
type Error = E; type Error = E;
type Future = FutureResult<R, E>; type Future = FutureResult<R, E>;

View File

@@ -3,7 +3,7 @@ use std::fmt;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::rc::Rc; use std::rc::Rc;
use actix_service::{Service, Transform, Void}; use actix_service::{IntoService, Service, Transform, Void};
use futures::future::{ok, FutureResult}; use futures::future::{ok, FutureResult};
use futures::task::AtomicTask; use futures::task::AtomicTask;
use futures::unsync::oneshot; use futures::unsync::oneshot;
@@ -52,39 +52,46 @@ pub struct InOrder<S> {
_t: PhantomData<S>, _t: PhantomData<S>,
} }
impl<S> InOrder<S> { impl<S> InOrder<S>
pub fn new<R>() -> Self
where
S: Service<R>,
S::Response: 'static,
S::Future: 'static,
S::Error: 'static,
{
Self { _t: PhantomData }
}
pub fn service<R>(service: S) -> InOrderService<S, R>
where
S: Service<R>,
S::Response: 'static,
S::Future: 'static,
S::Error: 'static,
{
InOrderService::new(service)
}
}
impl<S, R> Transform<S, R> for InOrder<S>
where where
S: Service<R>, S: Service,
S::Response: 'static, S::Response: 'static,
S::Future: 'static, S::Future: 'static,
S::Error: 'static, S::Error: 'static,
{ {
pub fn new() -> Self {
Self { _t: PhantomData }
}
pub fn service(service: S) -> InOrderService<S> {
InOrderService::new(service)
}
}
impl<S> Default for InOrder<S>
where
S: Service,
S::Response: 'static,
S::Future: 'static,
S::Error: 'static,
{
fn default() -> Self {
Self::new()
}
}
impl<S> Transform<S> for InOrder<S>
where
S: Service,
S::Response: 'static,
S::Future: 'static,
S::Error: 'static,
{
type Request = S::Request;
type Response = S::Response; type Response = S::Response;
type Error = InOrderError<S::Error>; type Error = InOrderError<S::Error>;
type InitError = Void; type InitError = Void;
type Transform = InOrderService<S, R>; type Transform = InOrderService<S>;
type Future = FutureResult<Self::Transform, Self::InitError>; type Future = FutureResult<Self::Transform, Self::InitError>;
fn new_transform(&self, service: S) -> Self::Future { fn new_transform(&self, service: S) -> Self::Future {
@@ -92,46 +99,47 @@ where
} }
} }
pub struct InOrderService<S: Service<R>, R> { pub struct InOrderService<S: Service> {
service: S, service: S,
task: Rc<AtomicTask>, task: Rc<AtomicTask>,
acks: VecDeque<Record<S::Response, S::Error>>, acks: VecDeque<Record<S::Response, S::Error>>,
} }
impl<S, R> InOrderService<S, R> impl<S> InOrderService<S>
where where
S: Service<R>, S: Service,
S::Response: 'static, S::Response: 'static,
S::Future: 'static, S::Future: 'static,
S::Error: 'static, S::Error: 'static,
{ {
pub fn new(service: S) -> Self { pub fn new<U>(service: U) -> Self
where
U: IntoService<S>,
{
Self { Self {
service, service: service.into_service(),
acks: VecDeque::new(), acks: VecDeque::new(),
task: Rc::new(AtomicTask::new()), task: Rc::new(AtomicTask::new()),
} }
} }
} }
impl<S, R> Service<R> for InOrderService<S, R> impl<S> Service for InOrderService<S>
where where
S: Service<R>, S: Service,
S::Response: 'static, S::Response: 'static,
S::Future: 'static, S::Future: 'static,
S::Error: 'static, S::Error: 'static,
{ {
type Request = S::Request;
type Response = S::Response; type Response = S::Response;
type Error = InOrderError<S::Error>; type Error = InOrderError<S::Error>;
type Future = InOrderServiceResponse<S, R>; type Future = InOrderServiceResponse<S>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(&mut self) -> Poll<(), Self::Error> {
// poll_ready could be called from different task // poll_ready could be called from different task
self.task.register(); self.task.register();
// check nested service
self.service.poll_ready().map_err(InOrderError::Service)?;
// check acks // check acks
while !self.acks.is_empty() { while !self.acks.is_empty() {
let rec = self.acks.front_mut().unwrap(); let rec = self.acks.front_mut().unwrap();
@@ -145,10 +153,15 @@ where
} }
} }
Ok(Async::Ready(())) // check nested service
if let Async::NotReady = self.service.poll_ready().map_err(InOrderError::Service)? {
Ok(Async::NotReady)
} else {
Ok(Async::Ready(()))
}
} }
fn call(&mut self, request: R) -> Self::Future { fn call(&mut self, request: S::Request) -> Self::Future {
let (tx1, rx1) = oneshot::channel(); let (tx1, rx1) = oneshot::channel();
let (tx2, rx2) = oneshot::channel(); let (tx2, rx2) = oneshot::channel();
self.acks.push_back(Record { rx: rx1, tx: tx2 }); self.acks.push_back(Record { rx: rx1, tx: tx2 });
@@ -165,11 +178,11 @@ where
} }
#[doc(hidden)] #[doc(hidden)]
pub struct InOrderServiceResponse<S: Service<R>, R> { pub struct InOrderServiceResponse<S: Service> {
rx: oneshot::Receiver<Result<S::Response, S::Error>>, rx: oneshot::Receiver<Result<S::Response, S::Error>>,
} }
impl<S: Service<R>, R> Future for InOrderServiceResponse<S, R> { impl<S: Service> Future for InOrderServiceResponse<S> {
type Item = S::Response; type Item = S::Response;
type Error = InOrderError<S::Error>; type Error = InOrderError<S::Error>;
@@ -196,7 +209,8 @@ mod tests {
struct Srv; struct Srv;
impl Service<oneshot::Receiver<usize>> for Srv { impl Service for Srv {
type Request = oneshot::Receiver<usize>;
type Response = usize; type Response = usize;
type Error = (); type Error = ();
type Future = Box<Future<Item = usize, Error = ()>>; type Future = Box<Future<Item = usize, Error = ()>>;
@@ -210,11 +224,11 @@ mod tests {
} }
} }
struct SrvPoll<S: Service<oneshot::Receiver<usize>>> { struct SrvPoll<S: Service> {
s: S, s: S,
} }
impl<S: Service<oneshot::Receiver<usize>>> Future for SrvPoll<S> { impl<S: Service> Future for SrvPoll<S> {
type Item = (); type Item = ();
type Error = (); type Error = ();

View File

@@ -38,12 +38,12 @@ impl<S, T, E, C> StreamNewService<S, T, E, C>
where where
C: Clone, C: Clone,
S: IntoStream, S: IntoStream,
T: NewService<Request<S>, C, Response = (), Error = E, InitError = E>, T: NewService<C, Request = Request<S>, Response = (), Error = E, InitError = E>,
T::Future: 'static, T::Future: 'static,
T::Service: 'static, T::Service: 'static,
<T::Service as Service<Request<S>>>::Future: 'static, <T::Service as Service>::Future: 'static,
{ {
pub fn new<F: IntoNewService<T, Request<S>, C>>(factory: F) -> Self { pub fn new<F: IntoNewService<T, C>>(factory: F) -> Self {
Self { Self {
factory: Rc::new(factory.into_new_service()), factory: Rc::new(factory.into_new_service()),
_t: PhantomData, _t: PhantomData,
@@ -60,15 +60,16 @@ impl<S, T, E, C> Clone for StreamNewService<S, T, E, C> {
} }
} }
impl<S, T, E, C> NewService<S, C> for StreamNewService<S, T, E, C> impl<S, T, E, C> NewService<C> for StreamNewService<S, T, E, C>
where where
C: Clone, C: Clone,
S: IntoStream + 'static, S: IntoStream + 'static,
T: NewService<Request<S>, C, Response = (), Error = E, InitError = E>, T: NewService<C, Request = Request<S>, Response = (), Error = E, InitError = E>,
T::Future: 'static, T::Future: 'static,
T::Service: 'static, T::Service: 'static,
<T::Service as Service<Request<S>>>::Future: 'static, <T::Service as Service>::Future: 'static,
{ {
type Request = S;
type Response = (); type Response = ();
type Error = E; type Error = E;
type InitError = E; type InitError = E;
@@ -90,15 +91,16 @@ pub struct StreamService<S, T, E, C = ()> {
_t: PhantomData<(S, E)>, _t: PhantomData<(S, E)>,
} }
impl<S, T, E, C> Service<S> for StreamService<S, T, E, C> impl<S, T, E, C> Service for StreamService<S, T, E, C>
where where
S: IntoStream + 'static, S: IntoStream + 'static,
T: NewService<Request<S>, C, Response = (), Error = E, InitError = E>, T: NewService<C, Request = Request<S>, Response = (), Error = E, InitError = E>,
T::Future: 'static, T::Future: 'static,
T::Service: 'static, T::Service: 'static,
<T::Service as Service<Request<S>>>::Future: 'static, <T::Service as Service>::Future: 'static,
C: Clone, C: Clone,
{ {
type Request = S;
type Response = (); type Response = ();
type Error = E; type Error = E;
type Future = Box<Future<Item = (), Error = E>>; type Future = Box<Future<Item = (), Error = E>>;
@@ -119,7 +121,7 @@ where
pub struct StreamDispatcher<S, T> pub struct StreamDispatcher<S, T>
where where
S: IntoStream + 'static, S: IntoStream + 'static,
T: Service<Request<S>, Response = ()> + 'static, T: Service<Request = Request<S>, Response = ()> + 'static,
T::Future: 'static, T::Future: 'static,
{ {
stream: S, stream: S,
@@ -131,13 +133,13 @@ where
impl<S, T> StreamDispatcher<S, T> impl<S, T> StreamDispatcher<S, T>
where where
S: Stream, S: Stream,
T: Service<Request<S>, Response = ()>, T: Service<Request = Request<S>, Response = ()>,
T::Future: 'static, T::Future: 'static,
{ {
pub fn new<F1, F2>(stream: F1, service: F2) -> Self pub fn new<F1, F2>(stream: F1, service: F2) -> Self
where where
F1: IntoStream<Stream = S, Item = S::Item, Error = S::Error>, F1: IntoStream<Stream = S, Item = S::Item, Error = S::Error>,
F2: IntoService<T, Request<S>>, F2: IntoService<T>,
{ {
let (err_tx, err_rx) = mpsc::unbounded(); let (err_tx, err_rx) = mpsc::unbounded();
StreamDispatcher { StreamDispatcher {
@@ -152,7 +154,7 @@ where
impl<S, T> Future for StreamDispatcher<S, T> impl<S, T> Future for StreamDispatcher<S, T>
where where
S: Stream, S: Stream,
T: Service<Request<S>, Response = ()>, T: Service<Request = Request<S>, Response = ()>,
T::Future: 'static, T::Future: 'static,
{ {
type Item = (); type Item = ();
@@ -230,14 +232,15 @@ impl<T> Clone for TakeItem<T> {
} }
} }
impl<T: Stream> NewService<T, ()> for TakeItem<T> { impl<T: Stream, C> NewService<C> for TakeItem<T> {
type Request = T;
type Response = (Option<T::Item>, T); type Response = (Option<T::Item>, T);
type Error = T::Error; type Error = T::Error;
type InitError = (); type InitError = ();
type Service = TakeItemService<T>; type Service = TakeItemService<T>;
type Future = FutureResult<Self::Service, Self::InitError>; type Future = FutureResult<Self::Service, Self::InitError>;
fn new_service(&self, _: &()) -> Self::Future { fn new_service(&self, _: &C) -> Self::Future {
ok(TakeItemService { _t: PhantomData }) ok(TakeItemService { _t: PhantomData })
} }
} }
@@ -253,7 +256,8 @@ impl<T> Clone for TakeItemService<T> {
} }
} }
impl<T: Stream> Service<T> for TakeItemService<T> { impl<T: Stream> Service for TakeItemService<T> {
type Request = T;
type Response = (Option<T::Item>, T); type Response = (Option<T::Item>, T);
type Error = T::Error; type Error = T::Error;
type Future = TakeItemServiceResponse<T>; type Future = TakeItemServiceResponse<T>;

View File

@@ -42,6 +42,7 @@ impl Default for LowResTime {
} }
impl NewService<()> for LowResTime { impl NewService<()> for LowResTime {
type Request = ();
type Response = Instant; type Response = Instant;
type Error = Void; type Error = Void;
type InitError = Void; type InitError = Void;
@@ -87,7 +88,8 @@ impl LowResTimeService {
} }
} }
impl Service<()> for LowResTimeService { impl Service for LowResTimeService {
type Request = ();
type Response = Instant; type Response = Instant;
type Error = Void; type Error = Void;
type Future = FutureResult<Self::Response, Self::Error>; type Future = FutureResult<Self::Response, Self::Error>;

View File

@@ -6,7 +6,7 @@ use std::fmt;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::time::Duration; use std::time::Duration;
use actix_service::{Service, Transform}; use actix_service::{IntoService, Service, Transform};
use futures::future::{ok, FutureResult}; use futures::future::{ok, FutureResult};
use futures::{Async, Future, Poll}; use futures::{Async, Future, Poll};
use tokio_timer::{clock, Delay}; use tokio_timer::{clock, Delay};
@@ -80,10 +80,11 @@ impl<E> Clone for Timeout<E> {
} }
} }
impl<S, R, E> Transform<S, R> for Timeout<E> impl<S, E> Transform<S> for Timeout<E>
where where
S: Service<R>, S: Service,
{ {
type Request = S::Request;
type Response = S::Response; type Response = S::Response;
type Error = TimeoutError<S::Error>; type Error = TimeoutError<S::Error>;
type InitError = E; type InitError = E;
@@ -105,25 +106,35 @@ pub struct TimeoutService<S> {
timeout: Duration, timeout: Duration,
} }
impl<S> TimeoutService<S> { impl<S> TimeoutService<S>
pub fn new(timeout: Duration, service: S) -> Self { where
TimeoutService { service, timeout } S: Service,
{
pub fn new<U>(timeout: Duration, service: U) -> Self
where
U: IntoService<S>,
{
TimeoutService {
timeout,
service: service.into_service(),
}
} }
} }
impl<S, R> Service<R> for TimeoutService<S> impl<S> Service for TimeoutService<S>
where where
S: Service<R>, S: Service,
{ {
type Request = S::Request;
type Response = S::Response; type Response = S::Response;
type Error = TimeoutError<S::Error>; type Error = TimeoutError<S::Error>;
type Future = TimeoutServiceResponse<S, R>; type Future = TimeoutServiceResponse<S>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.service.poll_ready().map_err(TimeoutError::Service) self.service.poll_ready().map_err(TimeoutError::Service)
} }
fn call(&mut self, request: R) -> Self::Future { fn call(&mut self, request: S::Request) -> Self::Future {
TimeoutServiceResponse { TimeoutServiceResponse {
fut: self.service.call(request), fut: self.service.call(request),
sleep: Delay::new(clock::now() + self.timeout), sleep: Delay::new(clock::now() + self.timeout),
@@ -133,14 +144,14 @@ where
/// `TimeoutService` response future /// `TimeoutService` response future
#[derive(Debug)] #[derive(Debug)]
pub struct TimeoutServiceResponse<T: Service<R>, R> { pub struct TimeoutServiceResponse<T: Service> {
fut: T::Future, fut: T::Future,
sleep: Delay, sleep: Delay,
} }
impl<T, R> Future for TimeoutServiceResponse<T, R> impl<T> Future for TimeoutServiceResponse<T>
where where
T: Service<R>, T: Service,
{ {
type Item = T::Response; type Item = T::Response;
type Error = TimeoutError<T::Error>; type Error = TimeoutError<T::Error>;
@@ -175,7 +186,8 @@ mod tests {
struct SleepService(Duration); struct SleepService(Duration);
impl Service<()> for SleepService { impl Service for SleepService {
type Request = ();
type Response = (); type Response = ();
type Error = (); type Error = ();
type Future = Box<Future<Item = (), Error = ()>>; type Future = Box<Future<Item = (), Error = ()>>;

View File

@@ -5,12 +5,12 @@ use std::sync::{
atomic::{AtomicUsize, Ordering}, atomic::{AtomicUsize, Ordering},
Arc, Arc,
}; };
use std::{env, fmt}; use std::{env, fmt, io};
use actix_codec::{AsyncRead, AsyncWrite}; use actix_codec::{AsyncRead, AsyncWrite};
use actix_rt::System; use actix_rt::System;
use actix_server::Server; use actix_server::{Io, Server};
use actix_service::{IntoNewService, NewService}; use actix_service::{fn_service, NewService};
use futures::{future, Future}; use futures::{future, Future};
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod}; use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
use tokio_openssl::SslAcceptorExt; use tokio_openssl::SslAcceptorExt;
@@ -23,7 +23,7 @@ fn logger<T: AsyncRead + AsyncWrite + fmt::Debug>(
future::ok(stream) future::ok(stream)
} }
fn main() { fn main() -> io::Result<()> {
env::set_var("RUST_LOG", "actix_net=trace"); env::set_var("RUST_LOG", "actix_net=trace");
env_logger::init(); env_logger::init();
@@ -54,16 +54,14 @@ fn main() {
let acceptor = acceptor.clone(); let acceptor = acceptor.clone();
// service for converting incoming TcpStream to a SslStream<TcpStream> // service for converting incoming TcpStream to a SslStream<TcpStream>
(move |stream| { fn_service(move |stream: Io<tokio_tcp::TcpStream>| {
SslAcceptorExt::accept_async(&acceptor, stream) SslAcceptorExt::accept_async(&acceptor, stream.into_parts().0)
.map_err(|e| println!("Openssl error: {}", e)) .map_err(|e| println!("Openssl error: {}", e))
}) })
// convert closure to a `NewService`
.into_new_service()
// .and_then() combinator uses other service to convert incoming `Request` to a // .and_then() combinator uses other service to convert incoming `Request` to a
// `Response` and then uses that response as an input for next // `Response` and then uses that response as an input for next
// service. in this case, on success we use `logger` service // service. in this case, on success we use `logger` service
.and_then(logger) .and_then(fn_service(logger))
// Next service counts number of connections // Next service counts number of connections
.and_then(move |_| { .and_then(move |_| {
let num = num.fetch_add(1, Ordering::Relaxed); let num = num.fetch_add(1, Ordering::Relaxed);
@@ -75,5 +73,5 @@ fn main() {
.unwrap() .unwrap()
.start(); .start();
sys.run(); sys.run()
} }

View File

@@ -1,13 +1,13 @@
use std::io;
use std::sync::{ use std::sync::{
atomic::{AtomicUsize, Ordering}, atomic::{AtomicUsize, Ordering},
Arc, Arc,
}; };
use actix_codec::{AsyncRead, AsyncWrite};
use actix_rt::System; use actix_rt::System;
use actix_server::{ssl, Server}; use actix_server::{ssl, Server};
use actix_service::NewService; use actix_service::NewService;
use futures::{future, Future}; use futures::future;
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod}; use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
#[derive(Debug)] #[derive(Debug)]
@@ -15,16 +15,7 @@ struct ServiceState {
num: Arc<AtomicUsize>, num: Arc<AtomicUsize>,
} }
fn service<T: AsyncRead + AsyncWrite>( fn main() -> io::Result<()> {
st: &mut ServiceState,
_: T,
) -> impl Future<Item = (), Error = ()> {
let num = st.num.fetch_add(1, Ordering::Relaxed);
println!("got ssl connection {:?}", num);
future::ok(())
}
fn main() {
let sys = System::new("test"); let sys = System::new("test");
// load ssl keys // load ssl keys
@@ -53,9 +44,8 @@ fn main() {
println!("got ssl connection {:?}", num); println!("got ssl connection {:?}", num);
future::ok(()) future::ok(())
}) })
}) })?
.unwrap()
.start(); .start();
sys.run(); sys.run()
} }

5
router/CHANGES.txt Normal file
View File

@@ -0,0 +1,5 @@
# Changes
## [0.1.0] - 2019-03-09
* Initial release

View File

@@ -14,26 +14,13 @@ const MAX_DYNAMIC_SEGMENTS: usize = 16;
/// Resource definition can contain only 16 dynamic segments /// Resource definition can contain only 16 dynamic segments
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ResourceDef { pub struct ResourceDef {
id: u16,
tp: PatternType, tp: PatternType,
rtp: ResourceType,
name: String, name: String,
pattern: String, pattern: String,
elements: Vec<PatternElement>, elements: Vec<PatternElement>,
} }
#[derive(Debug, Copy, Clone, PartialEq)]
/// Resource type
pub enum ResourceType {
/// Normal resource
Normal,
/// Resource for application default handler
Default,
/// External resource
External,
/// Unknown resource type
Unset,
}
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
enum PatternElement { enum PatternElement {
Str(String), Str(String),
@@ -75,13 +62,14 @@ impl ResourceDef {
ResourceDef::with_prefix(&insert_slash(path), true) ResourceDef::with_prefix(&insert_slash(path), true)
} }
/// Construct external resource def /// Resource id
/// pub fn id(&self) -> u16 {
/// Panics if path pattern is malformed. self.id
pub fn external(path: &str) -> Self { }
let mut resource = ResourceDef::with_prefix(path, false);
resource.rtp = ResourceType::External; /// Set resource id
resource pub fn set_id(&mut self, id: u16) {
self.id = id;
} }
/// Parse path pattern and create new `Pattern` instance with custom prefix /// Parse path pattern and create new `Pattern` instance with custom prefix
@@ -109,12 +97,22 @@ impl ResourceDef {
ResourceDef { ResourceDef {
tp, tp,
elements, elements,
id: 0,
name: String::new(), name: String::new(),
rtp: ResourceType::Normal,
pattern: path.to_owned(), pattern: path.to_owned(),
} }
} }
/// Resource pattern name
pub fn name(&self) -> &str {
&self.name
}
/// Mutable reference to a name of a resource definition.
pub fn name_mut(&mut self) -> &mut String {
&mut self.name
}
/// Path pattern of the resource /// Path pattern of the resource
pub fn pattern(&self) -> &str { pub fn pattern(&self) -> &str {
&self.pattern &self.pattern
@@ -129,6 +127,57 @@ impl ResourceDef {
} }
} }
/// Is prefix path a match against this resource?
pub fn is_prefix_match(&self, path: &str) -> Option<usize> {
let plen = path.len();
let path = if path.is_empty() { "/" } else { path };
match self.tp {
PatternType::Static(ref s) => {
if s == path {
Some(plen)
} else {
None
}
}
PatternType::Dynamic(ref re, _, len) => {
if let Some(captures) = re.captures(path) {
let mut pos = 0;
let mut passed = false;
for capture in captures.iter() {
if let Some(ref m) = capture {
if !passed {
passed = true;
continue;
}
pos = m.end();
}
}
Some(pos + len)
} else {
None
}
}
PatternType::Prefix(ref s) => {
let len = if path == s {
s.len()
} else if path.starts_with(s)
&& (s.ends_with('/') || path.split_at(s.len()).1.starts_with('/'))
{
if s.ends_with('/') {
s.len() - 1
} else {
s.len()
}
} else {
return None;
};
Some(min(plen, len))
}
}
}
/// Is the given path and parameters a match against this pattern? /// Is the given path and parameters a match against this pattern?
pub fn match_path<T: ResourcePath>(&self, path: &mut Path<T>) -> bool { pub fn match_path<T: ResourcePath>(&self, path: &mut Path<T>) -> bool {
match self.tp { match self.tp {
@@ -191,34 +240,32 @@ impl ResourceDef {
} }
} }
// /// Build resource path. /// Build resource path from elements. Returns `true` on success.
// pub fn resource_path<U, I>( pub fn resource_path<U, I>(&self, path: &mut String, elements: &mut U) -> bool
// &self, path: &mut String, elements: &mut U, where
// ) -> Result<(), UrlGenerationError> U: Iterator<Item = I>,
// where I: AsRef<str>,
// U: Iterator<Item = I>, {
// I: AsRef<str>, match self.tp {
// { PatternType::Prefix(ref p) => path.push_str(p),
// match self.tp { PatternType::Static(ref p) => path.push_str(p),
// PatternType::Prefix(ref p) => path.push_str(p), PatternType::Dynamic(..) => {
// PatternType::Static(ref p) => path.push_str(p), for el in &self.elements {
// PatternType::Dynamic(..) => { match *el {
// for el in &self.elements { PatternElement::Str(ref s) => path.push_str(s),
// match *el { PatternElement::Var(_) => {
// PatternElement::Str(ref s) => path.push_str(s), if let Some(val) = elements.next() {
// PatternElement::Var(_) => { path.push_str(val.as_ref())
// if let Some(val) = elements.next() { } else {
// path.push_str(val.as_ref()) return false;
// } else { }
// return Err(UrlGenerationError::NotEnoughElements); }
// } }
// } }
// } }
// } };
// } true
// }; }
// Ok(())
// }
fn parse_param(pattern: &str) -> (PatternElement, String, &str) { fn parse_param(pattern: &str) -> (PatternElement, String, &str) {
const DEFAULT_PATTERN: &str = "[^/]+"; const DEFAULT_PATTERN: &str = "[^/]+";
@@ -349,6 +396,11 @@ mod tests {
assert!(!re.is_match("/name/")); assert!(!re.is_match("/name/"));
assert!(!re.is_match("/name~")); assert!(!re.is_match("/name~"));
assert_eq!(re.is_prefix_match("/name"), Some(5));
assert_eq!(re.is_prefix_match("/name1"), None);
assert_eq!(re.is_prefix_match("/name/"), None);
assert_eq!(re.is_prefix_match("/name~"), None);
let re = ResourceDef::new("/name/"); let re = ResourceDef::new("/name/");
assert!(re.is_match("/name/")); assert!(re.is_match("/name/"));
assert!(!re.is_match("/name")); assert!(!re.is_match("/name"));
@@ -423,6 +475,12 @@ mod tests {
assert!(re.is_match("/name1")); assert!(re.is_match("/name1"));
assert!(re.is_match("/name~")); assert!(re.is_match("/name~"));
assert_eq!(re.is_prefix_match("/name"), Some(5));
assert_eq!(re.is_prefix_match("/name/"), Some(5));
assert_eq!(re.is_prefix_match("/name/test/test"), Some(5));
assert_eq!(re.is_prefix_match("/name1"), None);
assert_eq!(re.is_prefix_match("/name~"), None);
let re = ResourceDef::prefix("/name/"); let re = ResourceDef::prefix("/name/");
assert!(re.is_match("/name/")); assert!(re.is_match("/name/"));
assert!(re.is_match("/name/gs")); assert!(re.is_match("/name/gs"));
@@ -441,6 +499,10 @@ mod tests {
assert!(re.is_match("/name/gs")); assert!(re.is_match("/name/gs"));
assert!(!re.is_match("/name")); assert!(!re.is_match("/name"));
assert_eq!(re.is_prefix_match("/name/"), Some(6));
assert_eq!(re.is_prefix_match("/name/gs"), Some(6));
assert_eq!(re.is_prefix_match("/name"), None);
let mut path = Path::new("/test2/"); let mut path = Path::new("/test2/");
assert!(re.match_path(&mut path)); assert!(re.match_path(&mut path));
assert_eq!(&path["name"], "test2"); assert_eq!(&path["name"], "test2");

View File

@@ -1,170 +1,97 @@
use std::collections::HashMap; use crate::{Resource, ResourceDef, ResourcePath};
use std::rc::Rc;
use crate::resource::ResourceDef;
use crate::{Resource, ResourcePath};
#[derive(Debug, Copy, Clone, PartialEq)] #[derive(Debug, Copy, Clone, PartialEq)]
pub(crate) enum ResourceId { pub struct ResourceId(pub u16);
Default,
Normal(u16),
}
/// Information about current resource /// Information about current resource
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ResourceInfo { pub struct ResourceInfo {
rmap: Rc<ResourceMap>,
resource: ResourceId, resource: ResourceId,
} }
#[derive(Default, Debug)]
pub(crate) struct ResourceMap {
root: Option<ResourceDef>,
named: HashMap<String, ResourceDef>,
patterns: Vec<ResourceDef>,
}
/// Resource router. /// Resource router.
pub struct Router<T, U = ()> { pub struct Router<T, U = ()>(Vec<(ResourceDef, T, Option<U>)>);
rmap: Rc<ResourceMap>,
named: HashMap<String, ResourceDef>,
resources: Vec<(T, Option<U>)>,
}
impl<T, U> Router<T, U> { impl<T, U> Router<T, U> {
pub fn build() -> RouterBuilder<T, U> { pub fn build() -> RouterBuilder<T, U> {
RouterBuilder { RouterBuilder {
rmap: ResourceMap::default(),
named: HashMap::new(),
resources: Vec::new(), resources: Vec::new(),
} }
} }
pub fn recognize<R: Resource<P>, P: ResourcePath>( pub fn recognize<R, P>(&self, path: &mut R) -> Option<(&T, ResourceId)>
&self, where
res: &mut R, R: Resource<P>,
) -> Option<(&T, ResourceInfo)> { P: ResourcePath,
for (idx, resource) in self.rmap.patterns.iter().enumerate() { {
if resource.match_path(res.resource_path()) { for item in self.0.iter() {
let info = ResourceInfo { if item.0.match_path(path.resource_path()) {
rmap: self.rmap.clone(), return Some((&item.1, ResourceId(item.0.id())));
resource: ResourceId::Normal(idx as u16),
};
return Some((&self.resources[idx].0, info));
} }
} }
None None
} }
pub fn recognize_mut<R: Resource<P>, P: ResourcePath>( pub fn recognize_mut<R, P>(&mut self, res: &mut R) -> Option<(&mut T, ResourceId)>
&mut self, where
res: &mut R, R: Resource<P>,
) -> Option<(&mut T, ResourceInfo)> { P: ResourcePath,
for (idx, resource) in self.rmap.patterns.iter().enumerate() { {
if resource.match_path(res.resource_path()) { for item in self.0.iter_mut() {
let info = ResourceInfo { if item.0.match_path(res.resource_path()) {
rmap: self.rmap.clone(), return Some((&mut item.1, ResourceId(item.0.id())));
resource: ResourceId::Normal(idx as u16),
};
return Some((&mut self.resources[idx].0, info));
} }
} }
None None
} }
pub fn recognize_mut_checked<R: Resource<P>, P: ResourcePath, F>( pub fn recognize_mut_checked<R, P, F>(
&mut self, &mut self,
res: &mut R, res: &mut R,
check: F, check: F,
) -> Option<(&mut T, ResourceInfo)> ) -> Option<(&mut T, ResourceId)>
where where
F: Fn(&R, &Option<U>) -> bool, F: Fn(&R, &Option<U>) -> bool,
R: Resource<P>,
P: ResourcePath,
{ {
for (idx, resource) in self.rmap.patterns.iter().enumerate() { for item in self.0.iter_mut() {
if resource.match_path(res.resource_path()) && check(res, &self.resources[idx].1) { if item.0.match_path(res.resource_path()) && check(res, &item.2) {
let info = ResourceInfo { return Some((&mut item.1, ResourceId(item.0.id())));
rmap: self.rmap.clone(),
resource: ResourceId::Normal(idx as u16),
};
return Some((&mut self.resources[idx].0, info));
} }
} }
None None
} }
} }
impl<'a, T, U> IntoIterator for &'a Router<T, U> {
type Item = &'a (T, Option<U>);
type IntoIter = std::slice::Iter<'a, (T, Option<U>)>;
fn into_iter(self) -> Self::IntoIter {
self.resources.iter()
}
}
impl<'a, T, U> IntoIterator for &'a mut Router<T, U> {
type Item = &'a mut (T, Option<U>);
type IntoIter = std::slice::IterMut<'a, (T, Option<U>)>;
fn into_iter(self) -> Self::IntoIter {
self.resources.iter_mut()
}
}
impl ResourceMap {
fn register(&mut self, pattern: ResourceDef) {
self.patterns.push(pattern);
}
fn register_named(&mut self, name: String, pattern: ResourceDef) {
self.patterns.push(pattern.clone());
self.named.insert(name, pattern);
}
fn has_resource(&self, path: &str) -> bool {
unimplemented!()
}
}
pub struct RouterBuilder<T, U = ()> { pub struct RouterBuilder<T, U = ()> {
rmap: ResourceMap, resources: Vec<(ResourceDef, T, Option<U>)>,
named: HashMap<String, ResourceDef>,
resources: Vec<(T, Option<U>)>,
} }
impl<T, U> RouterBuilder<T, U> { impl<T, U> RouterBuilder<T, U> {
/// Register resource for specified path. /// Register resource for specified path.
pub fn path(&mut self, path: &str, resource: T) { pub fn path(&mut self, path: &str, resource: T) -> &mut (ResourceDef, T, Option<U>) {
self.rmap.register(ResourceDef::new(path)); self.resources
self.resources.push((resource, None)); .push((ResourceDef::new(path), resource, None));
self.resources.last_mut().unwrap()
} }
/// Register resource for specified path prefix. /// Register resource for specified path prefix.
pub fn prefix(&mut self, prefix: &str, resource: T) { pub fn prefix(&mut self, prefix: &str, resource: T) -> &mut (ResourceDef, T, Option<U>) {
self.rmap.register(ResourceDef::prefix(prefix)); self.resources
self.resources.push((resource, None)); .push((ResourceDef::prefix(prefix), resource, None));
self.resources.last_mut().unwrap()
} }
/// Register resource for ResourceDef /// Register resource for ResourceDef
pub fn rdef(&mut self, rdef: ResourceDef, resource: T) { pub fn rdef(&mut self, rdef: ResourceDef, resource: T) -> &mut (ResourceDef, T, Option<U>) {
self.rmap.register(rdef); self.resources.push((rdef, resource, None));
self.resources.push((resource, None)); self.resources.last_mut().unwrap()
}
/// Method attachs user data to lastly added resource.
///
/// This panics if no resources were added.
pub fn set_user_data(&mut self, userdata: Option<U>) {
self.resources.last_mut().unwrap().1 = userdata;
} }
/// Finish configuration and create router instance. /// Finish configuration and create router instance.
pub fn finish(self) -> Router<T, U> { pub fn finish(self) -> Router<T, U> {
Router { Router(self.resources)
rmap: Rc::new(self.rmap),
named: self.named,
resources: self.resources,
}
} }
} }
@@ -176,14 +103,14 @@ mod tests {
#[test] #[test]
fn test_recognizer_1() { fn test_recognizer_1() {
let mut router = Router::<usize>::build(); let mut router = Router::<usize>::build();
router.path("/name", 10); router.path("/name", 10).0.set_id(0);
router.path("/name/{val}", 11); router.path("/name/{val}", 11).0.set_id(1);
router.path("/name/{val}/index.html", 12); router.path("/name/{val}/index.html", 12).0.set_id(2);
router.path("/file/{file}.{ext}", 13); router.path("/file/{file}.{ext}", 13).0.set_id(3);
router.path("/v{val}/{val2}/index.html", 14); router.path("/v{val}/{val2}/index.html", 14).0.set_id(4);
router.path("/v/{tail:.*}", 15); router.path("/v/{tail:.*}", 15).0.set_id(5);
router.path("/test2/{test}.html", 16); router.path("/test2/{test}.html", 16).0.set_id(6);
router.path("/{test}/index.html", 17); router.path("/{test}/index.html", 17).0.set_id(7);
let mut router = router.finish(); let mut router = router.finish();
let mut path = Path::new("/unknown"); let mut path = Path::new("/unknown");
@@ -192,52 +119,52 @@ mod tests {
let mut path = Path::new("/name"); let mut path = Path::new("/name");
let (h, info) = router.recognize_mut(&mut path).unwrap(); let (h, info) = router.recognize_mut(&mut path).unwrap();
assert_eq!(*h, 10); assert_eq!(*h, 10);
assert_eq!(info.resource, ResourceId::Normal(0)); assert_eq!(info, ResourceId(0));
assert!(path.is_empty()); assert!(path.is_empty());
let mut path = Path::new("/name/value"); let mut path = Path::new("/name/value");
let (h, info) = router.recognize_mut(&mut path).unwrap(); let (h, info) = router.recognize_mut(&mut path).unwrap();
assert_eq!(*h, 11); assert_eq!(*h, 11);
assert_eq!(info.resource, ResourceId::Normal(1)); assert_eq!(info, ResourceId(1));
assert_eq!(path.get("val").unwrap(), "value"); assert_eq!(path.get("val").unwrap(), "value");
assert_eq!(&path["val"], "value"); assert_eq!(&path["val"], "value");
let mut path = Path::new("/name/value2/index.html"); let mut path = Path::new("/name/value2/index.html");
let (h, info) = router.recognize_mut(&mut path).unwrap(); let (h, info) = router.recognize_mut(&mut path).unwrap();
assert_eq!(*h, 12); assert_eq!(*h, 12);
assert_eq!(info.resource, ResourceId::Normal(2)); assert_eq!(info, ResourceId(2));
assert_eq!(path.get("val").unwrap(), "value2"); assert_eq!(path.get("val").unwrap(), "value2");
let mut path = Path::new("/file/file.gz"); let mut path = Path::new("/file/file.gz");
let (h, info) = router.recognize_mut(&mut path).unwrap(); let (h, info) = router.recognize_mut(&mut path).unwrap();
assert_eq!(*h, 13); assert_eq!(*h, 13);
assert_eq!(info.resource, ResourceId::Normal(3)); assert_eq!(info, ResourceId(3));
assert_eq!(path.get("file").unwrap(), "file"); assert_eq!(path.get("file").unwrap(), "file");
assert_eq!(path.get("ext").unwrap(), "gz"); assert_eq!(path.get("ext").unwrap(), "gz");
let mut path = Path::new("/vtest/ttt/index.html"); let mut path = Path::new("/vtest/ttt/index.html");
let (h, info) = router.recognize_mut(&mut path).unwrap(); let (h, info) = router.recognize_mut(&mut path).unwrap();
assert_eq!(*h, 14); assert_eq!(*h, 14);
assert_eq!(info.resource, ResourceId::Normal(4)); assert_eq!(info, ResourceId(4));
assert_eq!(path.get("val").unwrap(), "test"); assert_eq!(path.get("val").unwrap(), "test");
assert_eq!(path.get("val2").unwrap(), "ttt"); assert_eq!(path.get("val2").unwrap(), "ttt");
let mut path = Path::new("/v/blah-blah/index.html"); let mut path = Path::new("/v/blah-blah/index.html");
let (h, info) = router.recognize_mut(&mut path).unwrap(); let (h, info) = router.recognize_mut(&mut path).unwrap();
assert_eq!(*h, 15); assert_eq!(*h, 15);
assert_eq!(info.resource, ResourceId::Normal(5)); assert_eq!(info, ResourceId(5));
assert_eq!(path.get("tail").unwrap(), "blah-blah/index.html"); assert_eq!(path.get("tail").unwrap(), "blah-blah/index.html");
let mut path = Path::new("/test2/index.html"); let mut path = Path::new("/test2/index.html");
let (h, info) = router.recognize_mut(&mut path).unwrap(); let (h, info) = router.recognize_mut(&mut path).unwrap();
assert_eq!(*h, 16); assert_eq!(*h, 16);
assert_eq!(info.resource, ResourceId::Normal(6)); assert_eq!(info, ResourceId(6));
assert_eq!(path.get("test").unwrap(), "index"); assert_eq!(path.get("test").unwrap(), "index");
let mut path = Path::new("/bbb/index.html"); let mut path = Path::new("/bbb/index.html");
let (h, info) = router.recognize_mut(&mut path).unwrap(); let (h, info) = router.recognize_mut(&mut path).unwrap();
assert_eq!(*h, 17); assert_eq!(*h, 17);
assert_eq!(info.resource, ResourceId::Normal(7)); assert_eq!(info, ResourceId(7));
assert_eq!(path.get("test").unwrap(), "bbb"); assert_eq!(path.get("test").unwrap(), "bbb");
} }
@@ -260,8 +187,8 @@ mod tests {
#[test] #[test]
fn test_recognizer_with_prefix() { fn test_recognizer_with_prefix() {
let mut router = Router::<usize>::build(); let mut router = Router::<usize>::build();
router.path("/name", 10); router.path("/name", 10).0.set_id(0);
router.path("/name/{val}", 11); router.path("/name/{val}", 11).0.set_id(1);
let mut router = router.finish(); let mut router = router.finish();
let mut path = Path::new("/name"); let mut path = Path::new("/name");
@@ -275,9 +202,9 @@ mod tests {
let mut path = Path::new("/test/name/value"); let mut path = Path::new("/test/name/value");
path.skip(5); path.skip(5);
let (h, info) = router.recognize_mut(&mut path).unwrap(); let (h, id) = router.recognize_mut(&mut path).unwrap();
assert_eq!(*h, 11); assert_eq!(*h, 11);
assert_eq!(info.resource, ResourceId::Normal(1)); assert_eq!(id, ResourceId(1));
assert_eq!(path.get("val").unwrap(), "value"); assert_eq!(path.get("val").unwrap(), "value");
assert_eq!(&path["val"], "value"); assert_eq!(&path["val"], "value");
@@ -306,134 +233,4 @@ mod tests {
assert_eq!(*h, 11); assert_eq!(*h, 11);
assert_eq!(&path["val"], "ttt"); assert_eq!(&path["val"], "ttt");
} }
// #[test]
// fn test_request_resource() {
// let mut router = Router::<()>::default();
// let mut resource = Resource::new(ResourcePattern::new("/index.json"));
// resource.name("r1");
// router.register_resource(resource);
// let mut resource = Resource::new(ResourcePattern::new("/test.json"));
// resource.name("r2");
// router.register_resource(resource);
// let req = TestRequest::with_uri("/index.json").finish();
// let info = router.recognize(&req, &(), 0);
// assert_eq!(info.resource, ResourceId::Normal(0));
// assert_eq!(info.name(), "r1");
// let req = TestRequest::with_uri("/test.json").finish();
// let info = router.recognize(&req, &(), 0);
// assert_eq!(info.resource, ResourceId::Normal(1));
// assert_eq!(info.name(), "r2");
// }
// #[test]
// fn test_has_resource() {
// let mut router = Router::<()>::default();
// let scope = Scope::new("/test").resource("/name", |_| "done");
// router.register_scope(scope);
// {
// let info = router.default_route_info();
// assert!(!info.has_resource("/test"));
// assert!(info.has_resource("/test/name"));
// }
// let scope = Scope::new("/test2").nested("/test10", |s| s.resource("/name", |_| "done"));
// router.register_scope(scope);
// let info = router.default_route_info();
// assert!(info.has_resource("/test2/test10/name"));
// }
// #[test]
// fn test_url_for() {
// let mut router = Router::<()>::new(ResourcePattern::prefix(""));
// let mut resource = Resource::new(ResourcePattern::new("/tttt"));
// resource.name("r0");
// router.register_resource(resource);
// let scope = Scope::new("/test").resource("/name", |r| {
// r.name("r1");
// });
// router.register_scope(scope);
// let scope =
// Scope::new("/test2").nested("/test10", |s| s.resource("/name", |r| r.name("r2")));
// router.register_scope(scope);
// router.finish();
// let req = TestRequest::with_uri("/test").request();
// {
// let info = router.default_route_info();
// let res = info
// .url_for(&req, "r0", Vec::<&'static str>::new())
// .unwrap();
// assert_eq!(res.as_str(), "http://localhost:8080/tttt");
// let res = info
// .url_for(&req, "r1", Vec::<&'static str>::new())
// .unwrap();
// assert_eq!(res.as_str(), "http://localhost:8080/test/name");
// let res = info
// .url_for(&req, "r2", Vec::<&'static str>::new())
// .unwrap();
// assert_eq!(res.as_str(), "http://localhost:8080/test2/test10/name");
// }
// let req = TestRequest::with_uri("/test/name").request();
// let info = router.recognize(&req, &(), 0);
// assert_eq!(info.resource, ResourceId::Normal(1));
// let res = info
// .url_for(&req, "r0", Vec::<&'static str>::new())
// .unwrap();
// assert_eq!(res.as_str(), "http://localhost:8080/tttt");
// let res = info
// .url_for(&req, "r1", Vec::<&'static str>::new())
// .unwrap();
// assert_eq!(res.as_str(), "http://localhost:8080/test/name");
// let res = info
// .url_for(&req, "r2", Vec::<&'static str>::new())
// .unwrap();
// assert_eq!(res.as_str(), "http://localhost:8080/test2/test10/name");
// }
// #[test]
// fn test_url_for_dynamic() {
// let mut router = Router::<()>::new(ResourcePattern::prefix(""));
// let mut resource = Resource::new(ResourcePattern::new("/{name}/test/index.{ext}"));
// resource.name("r0");
// router.register_resource(resource);
// let scope = Scope::new("/{name1}").nested("/{name2}", |s| {
// s.resource("/{name3}/test/index.{ext}", |r| r.name("r2"))
// });
// router.register_scope(scope);
// router.finish();
// let req = TestRequest::with_uri("/test").request();
// {
// let info = router.default_route_info();
// let res = info.url_for(&req, "r0", vec!["sec1", "html"]).unwrap();
// assert_eq!(res.as_str(), "http://localhost:8080/sec1/test/index.html");
// let res = info
// .url_for(&req, "r2", vec!["sec1", "sec2", "sec3", "html"])
// .unwrap();
// assert_eq!(
// res.as_str(),
// "http://localhost:8080/sec1/sec2/sec3/test/index.html"
// );
// }
// }
} }