mirror of
https://github.com/fafhrd91/actix-net
synced 2025-06-28 21:10:37 +02:00
Migrate actix-net to std::future (#64)
* Migrate actix-codec, actix-rt, and actix-threadpool to std::future * update to latest tokio alpha and futures-rs * Migrate actix-service to std::future, This is a squash of ~8 commits, since it included a lot of experimentation. To see the commits, look into the semtexzv/std-future-service-tmp branch. * update futures-rs and tokio * Migrate actix-threadpool to std::future (#59) * Migrate actix-threadpool to std::future * Cosmetic refactor - turn log::error! into log::warn! as it doesn't throw any error - add Clone and Copy impls for Cancelled making it cheap to operate with - apply rustfmt * Bump up crate version to 0.2.0 and pre-fill its changelog * Disable patching 'actix-threadpool' crate in global workspace as unnecessary * Revert patching and fix 'actix-rt' * Migrate actix-rt to std::future (#47) * remove Pin from Service::poll_ready(); simplify combinators api; make code compile * disable tests * update travis config * refactor naming * drop IntoFuture trait * Migrate actix-server to std::future (#50) Still not finished, this is more WIP, this is an aggregation of several commits, which can be found in semtexzv/std-future-server-tmp branch * update actix-server * rename Factor to ServiceFactory * start server worker in start mehtod * update actix-utils * remove IntoTransform trait * Migrate actix-server::ssl::nativetls to std futures (#61) * Refactor 'nativetls' module * Migrate 'actix-server-config' to std futures - remove "uds" feature - disable features by default * Switch NativeTlsAcceptor to use 'tokio-tls' crate * Bikeshed features names and remove unnecessary dependencies for 'actix-server-config' crate * update openssl impl * migrate actix-connect to std::future * migrate actix-ioframe to std::future * update version to alpha.1 * fix boxed service * migrate server rustls support * migratte openssl and rustls connecttors * store the thread's handle with arbiter (#62) * update ssl connect tests * restore service tests * update readme
This commit is contained in:
@ -1,6 +1,10 @@
|
||||
use futures::{Async, Future, Poll};
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use super::{IntoNewService, NewService, Service};
|
||||
use pin_project::pin_project;
|
||||
|
||||
use super::{Service, ServiceFactory};
|
||||
use crate::cell::Cell;
|
||||
|
||||
/// Service for the `and_then` combinator, chaining a computation onto the end
|
||||
@ -45,12 +49,12 @@ where
|
||||
type Error = A::Error;
|
||||
type Future = AndThenFuture<A, B>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
let not_ready = self.a.poll_ready()?.is_not_ready();
|
||||
if self.b.get_mut().poll_ready()?.is_not_ready() || not_ready {
|
||||
Ok(Async::NotReady)
|
||||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
let not_ready = !self.a.poll_ready(cx)?.is_ready();
|
||||
if !self.b.get_mut().poll_ready(cx)?.is_ready() || not_ready {
|
||||
Poll::Pending
|
||||
} else {
|
||||
Ok(Async::Ready(()))
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,13 +63,16 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[pin_project]
|
||||
pub struct AndThenFuture<A, B>
|
||||
where
|
||||
A: Service,
|
||||
B: Service<Request = A::Response, Error = A::Error>,
|
||||
{
|
||||
b: Cell<B>,
|
||||
#[pin]
|
||||
fut_b: Option<B::Future>,
|
||||
#[pin]
|
||||
fut_a: Option<A::Future>,
|
||||
}
|
||||
|
||||
@ -88,22 +95,33 @@ where
|
||||
A: Service,
|
||||
B: Service<Request = A::Response, Error = A::Error>,
|
||||
{
|
||||
type Item = B::Response;
|
||||
type Error = A::Error;
|
||||
type Output = Result<B::Response, A::Error>;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
if let Some(ref mut fut) = self.fut_b {
|
||||
return fut.poll();
|
||||
}
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let mut this = self.project();
|
||||
|
||||
match self.fut_a.as_mut().expect("Bug in actix-service").poll() {
|
||||
Ok(Async::Ready(resp)) => {
|
||||
let _ = self.fut_a.take();
|
||||
self.fut_b = Some(self.b.get_mut().call(resp));
|
||||
self.poll()
|
||||
loop {
|
||||
let mut fut_a = this.fut_a.as_mut();
|
||||
let mut fut_b = this.fut_b.as_mut();
|
||||
|
||||
if let Some(fut) = fut_b.as_mut().as_pin_mut() {
|
||||
return fut.poll(cx);
|
||||
}
|
||||
|
||||
match fut_a
|
||||
.as_mut()
|
||||
.as_pin_mut()
|
||||
.expect("Bug in actix-service")
|
||||
.poll(cx)
|
||||
{
|
||||
Poll::Ready(Ok(resp)) => {
|
||||
fut_a.set(None);
|
||||
let new_fut = this.b.get_mut().call(resp);
|
||||
fut_b.set(Some(new_fut));
|
||||
}
|
||||
Poll::Ready(Err(e)) => return Poll::Ready(Err(e)),
|
||||
Poll::Pending => return Poll::Pending,
|
||||
}
|
||||
Ok(Async::NotReady) => Ok(Async::NotReady),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -111,8 +129,8 @@ where
|
||||
/// `AndThenNewService` new service combinator
|
||||
pub struct AndThenNewService<A, B>
|
||||
where
|
||||
A: NewService,
|
||||
B: NewService,
|
||||
A: ServiceFactory,
|
||||
B: ServiceFactory,
|
||||
{
|
||||
a: A,
|
||||
b: B,
|
||||
@ -120,8 +138,8 @@ where
|
||||
|
||||
impl<A, B> AndThenNewService<A, B>
|
||||
where
|
||||
A: NewService,
|
||||
B: NewService<
|
||||
A: ServiceFactory,
|
||||
B: ServiceFactory<
|
||||
Config = A::Config,
|
||||
Request = A::Response,
|
||||
Error = A::Error,
|
||||
@ -129,18 +147,15 @@ where
|
||||
>,
|
||||
{
|
||||
/// Create new `AndThen` combinator
|
||||
pub fn new<F: IntoNewService<B>>(a: A, f: F) -> Self {
|
||||
Self {
|
||||
a,
|
||||
b: f.into_new_service(),
|
||||
}
|
||||
pub fn new(a: A, b: B) -> Self {
|
||||
Self { a, b }
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B> NewService for AndThenNewService<A, B>
|
||||
impl<A, B> ServiceFactory for AndThenNewService<A, B>
|
||||
where
|
||||
A: NewService,
|
||||
B: NewService<
|
||||
A: ServiceFactory,
|
||||
B: ServiceFactory<
|
||||
Config = A::Config,
|
||||
Request = A::Response,
|
||||
Error = A::Error,
|
||||
@ -163,8 +178,8 @@ where
|
||||
|
||||
impl<A, B> Clone for AndThenNewService<A, B>
|
||||
where
|
||||
A: NewService + Clone,
|
||||
B: NewService + Clone,
|
||||
A: ServiceFactory + Clone,
|
||||
B: ServiceFactory + Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
@ -174,21 +189,25 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[pin_project]
|
||||
pub struct AndThenNewServiceFuture<A, B>
|
||||
where
|
||||
A: NewService,
|
||||
B: NewService<Request = A::Response>,
|
||||
A: ServiceFactory,
|
||||
B: ServiceFactory<Request = A::Response>,
|
||||
{
|
||||
#[pin]
|
||||
fut_b: B::Future,
|
||||
#[pin]
|
||||
fut_a: A::Future,
|
||||
|
||||
a: Option<A::Service>,
|
||||
b: Option<B::Service>,
|
||||
}
|
||||
|
||||
impl<A, B> AndThenNewServiceFuture<A, B>
|
||||
where
|
||||
A: NewService,
|
||||
B: NewService<Request = A::Response>,
|
||||
A: ServiceFactory,
|
||||
B: ServiceFactory<Request = A::Response>,
|
||||
{
|
||||
fn new(fut_a: A::Future, fut_b: B::Future) -> Self {
|
||||
AndThenNewServiceFuture {
|
||||
@ -202,56 +221,55 @@ where
|
||||
|
||||
impl<A, B> Future for AndThenNewServiceFuture<A, B>
|
||||
where
|
||||
A: NewService,
|
||||
B: NewService<Request = A::Response, Error = A::Error, InitError = A::InitError>,
|
||||
A: ServiceFactory,
|
||||
B: ServiceFactory<Request = A::Response, Error = A::Error, InitError = A::InitError>,
|
||||
{
|
||||
type Item = AndThen<A::Service, B::Service>;
|
||||
type Error = A::InitError;
|
||||
type Output = Result<AndThen<A::Service, B::Service>, A::InitError>;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
if self.a.is_none() {
|
||||
if let Async::Ready(service) = self.fut_a.poll()? {
|
||||
self.a = Some(service);
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
if this.a.is_none() {
|
||||
if let Poll::Ready(service) = this.fut_a.poll(cx)? {
|
||||
*this.a = Some(service);
|
||||
}
|
||||
}
|
||||
|
||||
if self.b.is_none() {
|
||||
if let Async::Ready(service) = self.fut_b.poll()? {
|
||||
self.b = Some(service);
|
||||
if this.b.is_none() {
|
||||
if let Poll::Ready(service) = this.fut_b.poll(cx)? {
|
||||
*this.b = Some(service);
|
||||
}
|
||||
}
|
||||
|
||||
if self.a.is_some() && self.b.is_some() {
|
||||
Ok(Async::Ready(AndThen::new(
|
||||
self.a.take().unwrap(),
|
||||
self.b.take().unwrap(),
|
||||
if this.a.is_some() && this.b.is_some() {
|
||||
Poll::Ready(Ok(AndThen::new(
|
||||
this.a.take().unwrap(),
|
||||
this.b.take().unwrap(),
|
||||
)))
|
||||
} else {
|
||||
Ok(Async::NotReady)
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use futures::future::{ok, FutureResult};
|
||||
use futures::{Async, Poll};
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use super::*;
|
||||
use crate::{NewService, Service, ServiceExt};
|
||||
use futures::future::{lazy, ok, ready, Ready};
|
||||
|
||||
use crate::{factory_fn, pipeline, pipeline_factory, Service, ServiceFactory};
|
||||
|
||||
struct Srv1(Rc<Cell<usize>>);
|
||||
|
||||
impl Service for Srv1 {
|
||||
type Request = &'static str;
|
||||
type Response = &'static str;
|
||||
type Error = ();
|
||||
type Future = FutureResult<Self::Response, ()>;
|
||||
type Future = Ready<Result<Self::Response, ()>>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.0.set(self.0.get() + 1);
|
||||
Ok(Async::Ready(()))
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, req: &'static str) -> Self::Future {
|
||||
@ -266,11 +284,11 @@ mod tests {
|
||||
type Request = &'static str;
|
||||
type Response = (&'static str, &'static str);
|
||||
type Error = ();
|
||||
type Future = FutureResult<Self::Response, ()>;
|
||||
type Future = Ready<Result<Self::Response, ()>>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
self.0.set(self.0.get() + 1);
|
||||
Ok(Async::Ready(()))
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, req: &'static str) -> Self::Future {
|
||||
@ -278,39 +296,35 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_poll_ready() {
|
||||
#[tokio::test]
|
||||
async fn test_poll_ready() {
|
||||
let cnt = Rc::new(Cell::new(0));
|
||||
let mut srv = Srv1(cnt.clone()).and_then(Srv2(cnt.clone()));
|
||||
let res = srv.poll_ready();
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), Async::Ready(()));
|
||||
let mut srv = pipeline(Srv1(cnt.clone())).and_then(Srv2(cnt.clone()));
|
||||
let res = lazy(|cx| srv.poll_ready(cx)).await;
|
||||
assert_eq!(res, Poll::Ready(Ok(())));
|
||||
assert_eq!(cnt.get(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_call() {
|
||||
#[tokio::test]
|
||||
async fn test_call() {
|
||||
let cnt = Rc::new(Cell::new(0));
|
||||
let mut srv = Srv1(cnt.clone()).and_then(Srv2(cnt));
|
||||
let res = srv.call("srv1").poll();
|
||||
let mut srv = pipeline(Srv1(cnt.clone())).and_then(Srv2(cnt));
|
||||
let res = srv.call("srv1").await;
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), Async::Ready(("srv1", "srv2")));
|
||||
assert_eq!(res.unwrap(), (("srv1", "srv2")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_service() {
|
||||
#[tokio::test]
|
||||
async fn test_new_service() {
|
||||
let cnt = Rc::new(Cell::new(0));
|
||||
let cnt2 = cnt.clone();
|
||||
let blank = move || Ok::<_, ()>(Srv1(cnt2.clone()));
|
||||
let new_srv = blank
|
||||
.into_new_service()
|
||||
.and_then(move || Ok(Srv2(cnt.clone())));
|
||||
if let Async::Ready(mut srv) = new_srv.new_service(&()).poll().unwrap() {
|
||||
let res = srv.call("srv1").poll();
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), Async::Ready(("srv1", "srv2")));
|
||||
} else {
|
||||
panic!()
|
||||
}
|
||||
let new_srv =
|
||||
pipeline_factory(factory_fn(move || ready(Ok::<_, ()>(Srv1(cnt2.clone())))))
|
||||
.and_then(move || ready(Ok(Srv2(cnt.clone()))));
|
||||
|
||||
let mut srv = new_srv.new_service(&()).await.unwrap();
|
||||
let res = srv.call("srv1").await;
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), ("srv1", "srv2"));
|
||||
}
|
||||
}
|
||||
|
@ -1,186 +0,0 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use futures::{Async, Future, Poll};
|
||||
|
||||
use crate::and_then::AndThen;
|
||||
use crate::from_err::FromErr;
|
||||
use crate::{NewService, Transform};
|
||||
|
||||
/// `Apply` new service combinator
|
||||
pub struct AndThenTransform<T, A, B> {
|
||||
a: A,
|
||||
b: B,
|
||||
t: Rc<T>,
|
||||
}
|
||||
|
||||
impl<T, A, B> AndThenTransform<T, A, B>
|
||||
where
|
||||
A: NewService,
|
||||
B: NewService<Config = A::Config, InitError = A::InitError>,
|
||||
T: Transform<B::Service, Request = A::Response, InitError = A::InitError>,
|
||||
T::Error: From<A::Error>,
|
||||
{
|
||||
/// Create new `ApplyNewService` new service instance
|
||||
pub fn new(t: T, a: A, b: B) -> Self {
|
||||
Self {
|
||||
a,
|
||||
b,
|
||||
t: Rc::new(t),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A, B> Clone for AndThenTransform<T, A, B>
|
||||
where
|
||||
A: Clone,
|
||||
B: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
a: self.a.clone(),
|
||||
b: self.b.clone(),
|
||||
t: self.t.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A, B> NewService for AndThenTransform<T, A, B>
|
||||
where
|
||||
A: NewService,
|
||||
B: NewService<Config = A::Config, InitError = A::InitError>,
|
||||
T: Transform<B::Service, Request = A::Response, InitError = A::InitError>,
|
||||
T::Error: From<A::Error>,
|
||||
{
|
||||
type Request = A::Request;
|
||||
type Response = T::Response;
|
||||
type Error = T::Error;
|
||||
|
||||
type Config = A::Config;
|
||||
type InitError = T::InitError;
|
||||
type Service = AndThen<FromErr<A::Service, T::Error>, T::Transform>;
|
||||
type Future = AndThenTransformFuture<T, A, B>;
|
||||
|
||||
fn new_service(&self, cfg: &A::Config) -> Self::Future {
|
||||
AndThenTransformFuture {
|
||||
a: None,
|
||||
t: None,
|
||||
t_cell: self.t.clone(),
|
||||
fut_a: self.a.new_service(cfg),
|
||||
fut_b: self.b.new_service(cfg),
|
||||
fut_t: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AndThenTransformFuture<T, A, B>
|
||||
where
|
||||
A: NewService,
|
||||
B: NewService<InitError = A::InitError>,
|
||||
T: Transform<B::Service, Request = A::Response, InitError = A::InitError>,
|
||||
T::Error: From<A::Error>,
|
||||
{
|
||||
fut_a: A::Future,
|
||||
fut_b: B::Future,
|
||||
fut_t: Option<T::Future>,
|
||||
a: Option<A::Service>,
|
||||
t: Option<T::Transform>,
|
||||
t_cell: Rc<T>,
|
||||
}
|
||||
|
||||
impl<T, A, B> Future for AndThenTransformFuture<T, A, B>
|
||||
where
|
||||
A: NewService,
|
||||
B: NewService<InitError = A::InitError>,
|
||||
T: Transform<B::Service, Request = A::Response, InitError = A::InitError>,
|
||||
T::Error: From<A::Error>,
|
||||
{
|
||||
type Item = AndThen<FromErr<A::Service, T::Error>, T::Transform>;
|
||||
type Error = T::InitError;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
if self.fut_t.is_none() {
|
||||
if let Async::Ready(service) = self.fut_b.poll()? {
|
||||
self.fut_t = Some(self.t_cell.new_transform(service));
|
||||
}
|
||||
}
|
||||
|
||||
if self.a.is_none() {
|
||||
if let Async::Ready(service) = self.fut_a.poll()? {
|
||||
self.a = Some(service);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref mut fut) = self.fut_t {
|
||||
if let Async::Ready(transform) = fut.poll()? {
|
||||
self.t = Some(transform);
|
||||
}
|
||||
}
|
||||
|
||||
if self.a.is_some() && self.t.is_some() {
|
||||
Ok(Async::Ready(AndThen::new(
|
||||
FromErr::new(self.a.take().unwrap()),
|
||||
self.t.take().unwrap(),
|
||||
)))
|
||||
} else {
|
||||
Ok(Async::NotReady)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use futures::future::{ok, FutureResult};
|
||||
use futures::{Async, Future, Poll};
|
||||
|
||||
use crate::{IntoNewService, IntoService, NewService, Service, ServiceExt};
|
||||
|
||||
#[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_apply() {
|
||||
let blank = |req| Ok(req);
|
||||
|
||||
let mut srv = blank
|
||||
.into_service()
|
||||
.apply_fn(Srv, |req: &'static str, srv: &mut Srv| {
|
||||
srv.call(()).map(move |res| (req, res))
|
||||
});
|
||||
assert!(srv.poll_ready().is_ok());
|
||||
let res = srv.call("srv").poll();
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), Async::Ready(("srv", ())));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_service() {
|
||||
let blank = || Ok::<_, ()>((|req| Ok(req)).into_service());
|
||||
|
||||
let new_srv = blank.into_new_service().apply(
|
||||
|req: &'static str, srv: &mut Srv| srv.call(()).map(move |res| (req, res)),
|
||||
|| Ok(Srv),
|
||||
);
|
||||
if let Async::Ready(mut srv) = new_srv.new_service(&()).poll().unwrap() {
|
||||
assert!(srv.poll_ready().is_ok());
|
||||
let res = srv.call("srv").poll();
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), Async::Ready(("srv", ())));
|
||||
} else {
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,307 +0,0 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use futures::{Async, Future, IntoFuture, Poll};
|
||||
|
||||
use super::{IntoNewService, IntoService, NewService, Service};
|
||||
use crate::cell::Cell;
|
||||
|
||||
/// `Apply` service combinator
|
||||
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,
|
||||
b: Cell<B>,
|
||||
f: Cell<F>,
|
||||
r: PhantomData<(Out,)>,
|
||||
}
|
||||
|
||||
impl<A, B, F, Out> 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>,
|
||||
{
|
||||
/// Create new `Apply` combinator
|
||||
pub fn new<A1: IntoService<A>, B1: IntoService<B>>(a: A1, b: B1, f: F) -> Self {
|
||||
Self {
|
||||
f: Cell::new(f),
|
||||
a: a.into_service(),
|
||||
b: Cell::new(b.into_service()),
|
||||
r: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, F, Out> Clone for AndThenApply<A, B, F, Out>
|
||||
where
|
||||
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 {
|
||||
AndThenApply {
|
||||
a: self.a.clone(),
|
||||
b: self.b.clone(),
|
||||
f: self.f.clone(),
|
||||
r: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, F, Out> Service for 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>,
|
||||
{
|
||||
type Request = A::Request;
|
||||
type Response = Out::Item;
|
||||
type Error = A::Error;
|
||||
type Future = AndThenApplyFuture<A, B, F, Out>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
let not_ready = self.a.poll_ready()?.is_not_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: A::Request) -> Self::Future {
|
||||
AndThenApplyFuture {
|
||||
b: self.b.clone(),
|
||||
f: self.f.clone(),
|
||||
fut_b: None,
|
||||
fut_a: Some(self.a.call(req)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AndThenApplyFuture<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>,
|
||||
{
|
||||
b: Cell<B>,
|
||||
f: Cell<F>,
|
||||
fut_a: Option<A::Future>,
|
||||
fut_b: Option<Out::Future>,
|
||||
}
|
||||
|
||||
impl<A, B, F, Out> Future for AndThenApplyFuture<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>,
|
||||
{
|
||||
type Item = Out::Item;
|
||||
type Error = A::Error;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
if let Some(ref mut fut) = self.fut_b {
|
||||
return fut.poll().map_err(|e| e.into());
|
||||
}
|
||||
|
||||
match self.fut_a.as_mut().expect("Bug in actix-service").poll() {
|
||||
Ok(Async::Ready(resp)) => {
|
||||
let _ = self.fut_a.take();
|
||||
self.fut_b =
|
||||
Some((&mut *self.f.get_mut())(resp, self.b.get_mut()).into_future());
|
||||
self.poll()
|
||||
}
|
||||
Ok(Async::NotReady) => Ok(Async::NotReady),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `ApplyNewService` new service combinator
|
||||
pub struct AndThenApplyNewService<A, B, F, Out> {
|
||||
a: A,
|
||||
b: B,
|
||||
f: Cell<F>,
|
||||
r: PhantomData<Out>,
|
||||
}
|
||||
|
||||
impl<A, B, F, Out> AndThenApplyNewService<A, B, F, Out>
|
||||
where
|
||||
A: NewService,
|
||||
B: NewService<Config = A::Config, Error = A::Error, InitError = A::InitError>,
|
||||
F: FnMut(A::Response, &mut B::Service) -> Out,
|
||||
Out: IntoFuture,
|
||||
Out::Error: Into<A::Error>,
|
||||
{
|
||||
/// Create new `ApplyNewService` new service instance
|
||||
pub fn new<A1: IntoNewService<A>, B1: IntoNewService<B>>(a: A1, b: B1, f: F) -> Self {
|
||||
Self {
|
||||
f: Cell::new(f),
|
||||
a: a.into_new_service(),
|
||||
b: b.into_new_service(),
|
||||
r: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, F, Out> Clone for AndThenApplyNewService<A, B, F, Out>
|
||||
where
|
||||
A: Clone,
|
||||
B: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
a: self.a.clone(),
|
||||
b: self.b.clone(),
|
||||
f: self.f.clone(),
|
||||
r: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, F, Out> NewService for AndThenApplyNewService<A, B, F, Out>
|
||||
where
|
||||
A: NewService,
|
||||
B: NewService<Config = A::Config, Error = A::Error, InitError = A::InitError>,
|
||||
F: FnMut(A::Response, &mut B::Service) -> Out,
|
||||
Out: IntoFuture,
|
||||
Out::Error: Into<A::Error>,
|
||||
{
|
||||
type Request = A::Request;
|
||||
type Response = Out::Item;
|
||||
type Error = A::Error;
|
||||
type Service = AndThenApply<A::Service, B::Service, F, Out>;
|
||||
type Config = A::Config;
|
||||
type InitError = A::InitError;
|
||||
type Future = AndThenApplyNewServiceFuture<A, B, F, Out>;
|
||||
|
||||
fn new_service(&self, cfg: &A::Config) -> Self::Future {
|
||||
AndThenApplyNewServiceFuture {
|
||||
a: None,
|
||||
b: None,
|
||||
f: self.f.clone(),
|
||||
fut_a: self.a.new_service(cfg).into_future(),
|
||||
fut_b: self.b.new_service(cfg).into_future(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AndThenApplyNewServiceFuture<A, B, F, Out>
|
||||
where
|
||||
A: NewService,
|
||||
B: NewService<Error = A::Error, InitError = A::InitError>,
|
||||
F: FnMut(A::Response, &mut B::Service) -> Out,
|
||||
Out: IntoFuture,
|
||||
Out::Error: Into<A::Error>,
|
||||
{
|
||||
fut_b: B::Future,
|
||||
fut_a: A::Future,
|
||||
f: Cell<F>,
|
||||
a: Option<A::Service>,
|
||||
b: Option<B::Service>,
|
||||
}
|
||||
|
||||
impl<A, B, F, Out> Future for AndThenApplyNewServiceFuture<A, B, F, Out>
|
||||
where
|
||||
A: NewService,
|
||||
B: NewService<Error = A::Error, InitError = A::InitError>,
|
||||
F: FnMut(A::Response, &mut B::Service) -> Out,
|
||||
Out: IntoFuture,
|
||||
Out::Error: Into<A::Error>,
|
||||
{
|
||||
type Item = AndThenApply<A::Service, B::Service, F, Out>;
|
||||
type Error = A::InitError;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
if self.a.is_none() {
|
||||
if let Async::Ready(service) = self.fut_a.poll()? {
|
||||
self.a = Some(service);
|
||||
}
|
||||
}
|
||||
|
||||
if self.b.is_none() {
|
||||
if let Async::Ready(service) = self.fut_b.poll()? {
|
||||
self.b = Some(service);
|
||||
}
|
||||
}
|
||||
|
||||
if self.a.is_some() && self.b.is_some() {
|
||||
Ok(Async::Ready(AndThenApply {
|
||||
f: self.f.clone(),
|
||||
a: self.a.take().unwrap(),
|
||||
b: Cell::new(self.b.take().unwrap()),
|
||||
r: PhantomData,
|
||||
}))
|
||||
} else {
|
||||
Ok(Async::NotReady)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use futures::future::{ok, FutureResult};
|
||||
use futures::{Async, Future, Poll};
|
||||
|
||||
use crate::blank::{Blank, BlankNewService};
|
||||
use crate::{NewService, Service, ServiceExt};
|
||||
|
||||
#[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_call() {
|
||||
let mut srv = Blank::new().apply_fn(Srv, |req: &'static str, srv| {
|
||||
srv.call(()).map(move |res| (req, res))
|
||||
});
|
||||
assert!(srv.poll_ready().is_ok());
|
||||
let res = srv.call("srv").poll();
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), Async::Ready(("srv", ())));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_service() {
|
||||
let new_srv = BlankNewService::new_unit().apply_fn(
|
||||
|| Ok(Srv),
|
||||
|req: &'static str, srv| srv.call(()).map(move |res| (req, res)),
|
||||
);
|
||||
if let Async::Ready(mut srv) = new_srv.new_service(&()).poll().unwrap() {
|
||||
assert!(srv.poll_ready().is_ok());
|
||||
let res = srv.call("srv").poll();
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), Async::Ready(("srv", ())));
|
||||
} else {
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,175 +1,158 @@
|
||||
use pin_project::pin_project;
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use futures::{Async, Future, IntoFuture, Poll};
|
||||
|
||||
use super::{IntoNewService, IntoService, NewService, Service};
|
||||
use super::{IntoService, IntoServiceFactory, Service, ServiceFactory};
|
||||
|
||||
/// Apply tranform function to a service
|
||||
pub fn apply_fn<T, F, In, Out, U>(service: U, f: F) -> Apply<T, F, In, Out>
|
||||
pub fn apply_fn<T, F, R, In, Out, Err, U>(
|
||||
service: U,
|
||||
f: F,
|
||||
) -> impl Service<Request = In, Response = Out, Error = Err>
|
||||
where
|
||||
T: Service,
|
||||
F: FnMut(In, &mut T) -> Out,
|
||||
Out: IntoFuture,
|
||||
Out::Error: From<T::Error>,
|
||||
T: Service<Error = Err>,
|
||||
F: FnMut(In, &mut T) -> R,
|
||||
R: Future<Output = Result<Out, Err>>,
|
||||
U: IntoService<T>,
|
||||
{
|
||||
Apply::new(service.into_service(), f)
|
||||
}
|
||||
|
||||
/// Create factory for `apply` service.
|
||||
pub fn new_apply_fn<T, F, In, Out, U>(service: U, f: F) -> ApplyNewService<T, F, In, Out>
|
||||
pub fn apply_fn_factory<T, F, R, In, Out, Err, U>(
|
||||
service: U,
|
||||
f: F,
|
||||
) -> impl ServiceFactory<
|
||||
Config = T::Config,
|
||||
Request = In,
|
||||
Response = Out,
|
||||
Error = Err,
|
||||
InitError = T::InitError,
|
||||
>
|
||||
where
|
||||
T: NewService,
|
||||
F: FnMut(In, &mut T::Service) -> Out + Clone,
|
||||
Out: IntoFuture,
|
||||
Out::Error: From<T::Error>,
|
||||
U: IntoNewService<T>,
|
||||
T: ServiceFactory<Error = Err>,
|
||||
F: FnMut(In, &mut T::Service) -> R + Clone,
|
||||
R: Future<Output = Result<Out, Err>>,
|
||||
U: IntoServiceFactory<T>,
|
||||
{
|
||||
ApplyNewService::new(service.into_new_service(), f)
|
||||
ApplyNewService::new(service.into_factory(), f)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
/// `Apply` service combinator
|
||||
pub struct Apply<T, F, In, Out>
|
||||
#[pin_project]
|
||||
struct Apply<T, F, R, In, Out, Err>
|
||||
where
|
||||
T: Service,
|
||||
T: Service<Error = Err>,
|
||||
{
|
||||
#[pin]
|
||||
service: T,
|
||||
f: F,
|
||||
r: PhantomData<(In, Out)>,
|
||||
r: PhantomData<(In, Out, R)>,
|
||||
}
|
||||
|
||||
impl<T, F, In, Out> Apply<T, F, In, Out>
|
||||
impl<T, F, R, In, Out, Err> Apply<T, F, R, In, Out, Err>
|
||||
where
|
||||
T: Service,
|
||||
F: FnMut(In, &mut T) -> Out,
|
||||
Out: IntoFuture,
|
||||
Out::Error: From<T::Error>,
|
||||
T: Service<Error = Err>,
|
||||
F: FnMut(In, &mut T) -> R,
|
||||
R: Future<Output = Result<Out, Err>>,
|
||||
{
|
||||
/// Create new `Apply` combinator
|
||||
pub(crate) fn new<I: IntoService<T>>(service: I, f: F) -> Self {
|
||||
fn new(service: T, f: F) -> Self {
|
||||
Self {
|
||||
service: service.into_service(),
|
||||
service,
|
||||
f,
|
||||
r: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, F, In, Out> Clone for Apply<T, F, In, Out>
|
||||
impl<T, F, R, In, Out, Err> Service for Apply<T, F, R, In, Out, Err>
|
||||
where
|
||||
T: Service + Clone,
|
||||
F: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Apply {
|
||||
service: self.service.clone(),
|
||||
f: self.f.clone(),
|
||||
r: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, F, In, Out> Service for Apply<T, F, In, Out>
|
||||
where
|
||||
T: Service,
|
||||
F: FnMut(In, &mut T) -> Out,
|
||||
Out: IntoFuture,
|
||||
Out::Error: From<T::Error>,
|
||||
T: Service<Error = Err>,
|
||||
F: FnMut(In, &mut T) -> R,
|
||||
R: Future<Output = Result<Out, Err>>,
|
||||
{
|
||||
type Request = In;
|
||||
type Response = Out::Item;
|
||||
type Error = Out::Error;
|
||||
type Future = Out::Future;
|
||||
type Response = Out;
|
||||
type Error = Err;
|
||||
type Future = R;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
self.service.poll_ready().map_err(|e| e.into())
|
||||
fn poll_ready(&mut self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(futures::ready!(self.service.poll_ready(ctx)))
|
||||
}
|
||||
|
||||
fn call(&mut self, req: In) -> Self::Future {
|
||||
(self.f)(req, &mut self.service).into_future()
|
||||
(self.f)(req, &mut self.service)
|
||||
}
|
||||
}
|
||||
|
||||
/// `ApplyNewService` new service combinator
|
||||
pub struct ApplyNewService<T, F, In, Out>
|
||||
struct ApplyNewService<T, F, R, In, Out, Err>
|
||||
where
|
||||
T: NewService,
|
||||
T: ServiceFactory<Error = Err>,
|
||||
{
|
||||
service: T,
|
||||
f: F,
|
||||
r: PhantomData<(In, Out)>,
|
||||
r: PhantomData<(R, In, Out)>,
|
||||
}
|
||||
|
||||
impl<T, F, In, Out> ApplyNewService<T, F, In, Out>
|
||||
impl<T, F, R, In, Out, Err> ApplyNewService<T, F, R, In, Out, Err>
|
||||
where
|
||||
T: NewService,
|
||||
F: FnMut(In, &mut T::Service) -> Out + Clone,
|
||||
Out: IntoFuture,
|
||||
Out::Error: From<T::Error>,
|
||||
T: ServiceFactory<Error = Err>,
|
||||
F: FnMut(In, &mut T::Service) -> R + Clone,
|
||||
R: Future<Output = Result<Out, Err>>,
|
||||
{
|
||||
/// Create new `ApplyNewService` new service instance
|
||||
pub(crate) fn new<F1: IntoNewService<T>>(service: F1, f: F) -> Self {
|
||||
fn new(service: T, f: F) -> Self {
|
||||
Self {
|
||||
f,
|
||||
service: service.into_new_service(),
|
||||
service,
|
||||
r: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, F, In, Out> Clone for ApplyNewService<T, F, In, Out>
|
||||
impl<T, F, R, In, Out, Err> ServiceFactory for ApplyNewService<T, F, R, In, Out, Err>
|
||||
where
|
||||
T: NewService + Clone,
|
||||
F: FnMut(In, &mut T::Service) -> Out + Clone,
|
||||
Out: IntoFuture,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
service: self.service.clone(),
|
||||
f: self.f.clone(),
|
||||
r: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, F, In, Out> NewService for ApplyNewService<T, F, In, Out>
|
||||
where
|
||||
T: NewService,
|
||||
F: FnMut(In, &mut T::Service) -> Out + Clone,
|
||||
Out: IntoFuture,
|
||||
Out::Error: From<T::Error>,
|
||||
T: ServiceFactory<Error = Err>,
|
||||
F: FnMut(In, &mut T::Service) -> R + Clone,
|
||||
R: Future<Output = Result<Out, Err>>,
|
||||
{
|
||||
type Request = In;
|
||||
type Response = Out::Item;
|
||||
type Error = Out::Error;
|
||||
type Response = Out;
|
||||
type Error = Err;
|
||||
|
||||
type Config = T::Config;
|
||||
type Service = Apply<T::Service, F, In, Out>;
|
||||
type Service = Apply<T::Service, F, R, In, Out, Err>;
|
||||
type InitError = T::InitError;
|
||||
type Future = ApplyNewServiceFuture<T, F, In, Out>;
|
||||
type Future = ApplyNewServiceFuture<T, F, R, In, Out, Err>;
|
||||
|
||||
fn new_service(&self, cfg: &T::Config) -> Self::Future {
|
||||
ApplyNewServiceFuture::new(self.service.new_service(cfg), self.f.clone())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ApplyNewServiceFuture<T, F, In, Out>
|
||||
#[pin_project]
|
||||
struct ApplyNewServiceFuture<T, F, R, In, Out, Err>
|
||||
where
|
||||
T: NewService,
|
||||
F: FnMut(In, &mut T::Service) -> Out + Clone,
|
||||
Out: IntoFuture,
|
||||
T: ServiceFactory<Error = Err>,
|
||||
F: FnMut(In, &mut T::Service) -> R + Clone,
|
||||
R: Future<Output = Result<Out, Err>>,
|
||||
{
|
||||
#[pin]
|
||||
fut: T::Future,
|
||||
f: Option<F>,
|
||||
r: PhantomData<(In, Out)>,
|
||||
}
|
||||
|
||||
impl<T, F, In, Out> ApplyNewServiceFuture<T, F, In, Out>
|
||||
impl<T, F, R, In, Out, Err> ApplyNewServiceFuture<T, F, R, In, Out, Err>
|
||||
where
|
||||
T: NewService,
|
||||
F: FnMut(In, &mut T::Service) -> Out + Clone,
|
||||
Out: IntoFuture,
|
||||
T: ServiceFactory<Error = Err>,
|
||||
F: FnMut(In, &mut T::Service) -> R + Clone,
|
||||
R: Future<Output = Result<Out, Err>>,
|
||||
{
|
||||
fn new(fut: T::Future, f: F) -> Self {
|
||||
ApplyNewServiceFuture {
|
||||
@ -180,43 +163,44 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, F, In, Out> Future for ApplyNewServiceFuture<T, F, In, Out>
|
||||
impl<T, F, R, In, Out, Err> Future for ApplyNewServiceFuture<T, F, R, In, Out, Err>
|
||||
where
|
||||
T: NewService,
|
||||
F: FnMut(In, &mut T::Service) -> Out + Clone,
|
||||
Out: IntoFuture,
|
||||
Out::Error: From<T::Error>,
|
||||
T: ServiceFactory<Error = Err>,
|
||||
F: FnMut(In, &mut T::Service) -> R + Clone,
|
||||
R: Future<Output = Result<Out, Err>>,
|
||||
{
|
||||
type Item = Apply<T::Service, F, In, Out>;
|
||||
type Error = T::InitError;
|
||||
type Output = Result<Apply<T::Service, F, R, In, Out, Err>, T::InitError>;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
if let Async::Ready(service) = self.fut.poll()? {
|
||||
Ok(Async::Ready(Apply::new(service, self.f.take().unwrap())))
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
if let Poll::Ready(svc) = this.fut.poll(cx)? {
|
||||
Poll::Ready(Ok(Apply::new(svc, this.f.take().unwrap())))
|
||||
} else {
|
||||
Ok(Async::NotReady)
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use futures::future::{ok, FutureResult};
|
||||
use futures::{Async, Future, Poll};
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use futures::future::{lazy, ok, Ready};
|
||||
|
||||
use super::*;
|
||||
use crate::{IntoService, NewService, Service, ServiceExt};
|
||||
use crate::{pipeline, pipeline_factory, Service, ServiceFactory};
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Srv;
|
||||
|
||||
impl Service for Srv {
|
||||
type Request = ();
|
||||
type Response = ();
|
||||
type Error = ();
|
||||
type Future = FutureResult<(), ()>;
|
||||
type Future = Ready<Result<(), ()>>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
Ok(Async::Ready(()))
|
||||
fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, _: ()) -> Self::Future {
|
||||
@ -224,34 +208,42 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_call() {
|
||||
let blank = |req| Ok(req);
|
||||
#[tokio::test]
|
||||
async fn test_call() {
|
||||
let mut srv = pipeline(apply_fn(Srv, |req: &'static str, srv| {
|
||||
let fut = srv.call(());
|
||||
async move {
|
||||
let res = fut.await.unwrap();
|
||||
Ok((req, res))
|
||||
}
|
||||
}));
|
||||
|
||||
let mut srv = blank
|
||||
.into_service()
|
||||
.apply_fn(Srv, |req: &'static str, srv| {
|
||||
srv.call(()).map(move |res| (req, res))
|
||||
});
|
||||
assert!(srv.poll_ready().is_ok());
|
||||
let res = srv.call("srv").poll();
|
||||
assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
|
||||
|
||||
let res = srv.call("srv").await;
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), Async::Ready(("srv", ())));
|
||||
assert_eq!(res.unwrap(), (("srv", ())));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_service() {
|
||||
let new_srv = ApplyNewService::new(
|
||||
|| Ok::<_, ()>(Srv),
|
||||
|req: &'static str, srv| srv.call(()).map(move |res| (req, res)),
|
||||
);
|
||||
if let Async::Ready(mut srv) = new_srv.new_service(&()).poll().unwrap() {
|
||||
assert!(srv.poll_ready().is_ok());
|
||||
let res = srv.call("srv").poll();
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), Async::Ready(("srv", ())));
|
||||
} else {
|
||||
panic!()
|
||||
}
|
||||
#[tokio::test]
|
||||
async fn test_new_service() {
|
||||
let new_srv = pipeline_factory(apply_fn_factory(
|
||||
|| ok::<_, ()>(Srv),
|
||||
|req: &'static str, srv| {
|
||||
let fut = srv.call(());
|
||||
async move {
|
||||
let res = fut.await.unwrap();
|
||||
Ok((req, res))
|
||||
}
|
||||
},
|
||||
));
|
||||
|
||||
let mut srv = new_srv.new_service(&()).await.unwrap();
|
||||
|
||||
assert_eq!(lazy(|cx| srv.poll_ready(cx)).await, Poll::Ready(Ok(())));
|
||||
|
||||
let res = srv.call("srv").await;
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), (("srv", ())));
|
||||
}
|
||||
}
|
||||
|
@ -1,43 +1,45 @@
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use futures::future::Future;
|
||||
use futures::{try_ready, Async, IntoFuture, Poll};
|
||||
use futures::ready;
|
||||
use pin_project::pin_project;
|
||||
|
||||
use crate::cell::Cell;
|
||||
use crate::{IntoService, NewService, Service};
|
||||
use crate::{IntoService, Service, ServiceFactory};
|
||||
|
||||
/// Convert `Fn(&Config, &mut Service) -> Future<Service>` fn to a NewService
|
||||
pub fn apply_cfg<F, C, T, R, S>(
|
||||
pub fn apply_cfg<F, C, T, R, S, E>(
|
||||
srv: T,
|
||||
f: F,
|
||||
) -> impl NewService<
|
||||
) -> impl ServiceFactory<
|
||||
Config = C,
|
||||
Request = S::Request,
|
||||
Response = S::Response,
|
||||
Error = S::Error,
|
||||
Service = S,
|
||||
InitError = R::Error,
|
||||
InitError = E,
|
||||
> + Clone
|
||||
where
|
||||
F: FnMut(&C, &mut T) -> R,
|
||||
T: Service,
|
||||
R: IntoFuture,
|
||||
R::Item: IntoService<S>,
|
||||
R: Future<Output = Result<S, E>>,
|
||||
S: Service,
|
||||
{
|
||||
ApplyConfigService {
|
||||
f: Cell::new(f),
|
||||
srv: Cell::new(srv.into_service()),
|
||||
srv: Cell::new(srv),
|
||||
_t: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert `Fn(&Config, &mut Service) -> Future<Service>` fn to a NewService
|
||||
/// Service get constructor from NewService.
|
||||
pub fn new_apply_cfg<F, C, T, R, S>(
|
||||
pub fn apply_cfg_factory<F, C, T, R, S>(
|
||||
srv: T,
|
||||
f: F,
|
||||
) -> impl NewService<
|
||||
) -> impl ServiceFactory<
|
||||
Config = C,
|
||||
Request = S::Request,
|
||||
Response = S::Response,
|
||||
@ -48,10 +50,9 @@ pub fn new_apply_cfg<F, C, T, R, S>(
|
||||
where
|
||||
C: Clone,
|
||||
F: FnMut(&C, &mut T::Service) -> R,
|
||||
T: NewService<Config = ()>,
|
||||
T: ServiceFactory<Config = ()>,
|
||||
T::InitError: From<T::Error>,
|
||||
R: IntoFuture<Error = T::InitError>,
|
||||
R::Item: IntoService<S>,
|
||||
R: Future<Output = Result<S, T::InitError>>,
|
||||
S: Service,
|
||||
{
|
||||
ApplyConfigNewService {
|
||||
@ -61,26 +62,26 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert `Fn(&Config) -> Future<Service>` fn to NewService
|
||||
struct ApplyConfigService<F, C, T, R, S>
|
||||
/// Convert `Fn(&Config) -> Future<Service>` fn to NewService\
|
||||
#[pin_project]
|
||||
struct ApplyConfigService<F, C, T, R, S, E>
|
||||
where
|
||||
F: FnMut(&C, &mut T) -> R,
|
||||
T: Service,
|
||||
R: IntoFuture,
|
||||
R::Item: IntoService<S>,
|
||||
R: Future<Output = Result<S, E>>,
|
||||
S: Service,
|
||||
{
|
||||
f: Cell<F>,
|
||||
#[pin]
|
||||
srv: Cell<T>,
|
||||
_t: PhantomData<(C, R, S)>,
|
||||
}
|
||||
|
||||
impl<F, C, T, R, S> Clone for ApplyConfigService<F, C, T, R, S>
|
||||
impl<F, C, T, R, S, E> Clone for ApplyConfigService<F, C, T, R, S, E>
|
||||
where
|
||||
F: FnMut(&C, &mut T) -> R,
|
||||
T: Service,
|
||||
R: IntoFuture,
|
||||
R::Item: IntoService<S>,
|
||||
R: Future<Output = Result<S, E>>,
|
||||
S: Service,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
@ -92,12 +93,11 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, C, T, R, S> NewService for ApplyConfigService<F, C, T, R, S>
|
||||
impl<F, C, T, R, S, E> ServiceFactory for ApplyConfigService<F, C, T, R, S, E>
|
||||
where
|
||||
F: FnMut(&C, &mut T) -> R,
|
||||
T: Service,
|
||||
R: IntoFuture,
|
||||
R::Item: IntoService<S>,
|
||||
R: Future<Output = Result<S, E>>,
|
||||
S: Service,
|
||||
{
|
||||
type Config = C;
|
||||
@ -106,39 +106,37 @@ where
|
||||
type Error = S::Error;
|
||||
type Service = S;
|
||||
|
||||
type InitError = R::Error;
|
||||
type Future = FnNewServiceConfigFut<R, S>;
|
||||
type InitError = E;
|
||||
type Future = FnNewServiceConfigFut<R, S, E>;
|
||||
|
||||
fn new_service(&self, cfg: &C) -> Self::Future {
|
||||
FnNewServiceConfigFut {
|
||||
fut: unsafe { (self.f.get_mut_unsafe())(cfg, self.srv.get_mut_unsafe()) }
|
||||
.into_future(),
|
||||
fut: unsafe { (self.f.get_mut_unsafe())(cfg, self.srv.get_mut_unsafe()) },
|
||||
_t: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct FnNewServiceConfigFut<R, S>
|
||||
#[pin_project]
|
||||
struct FnNewServiceConfigFut<R, S, E>
|
||||
where
|
||||
R: IntoFuture,
|
||||
R::Item: IntoService<S>,
|
||||
R: Future<Output = Result<S, E>>,
|
||||
S: Service,
|
||||
{
|
||||
fut: R::Future,
|
||||
#[pin]
|
||||
fut: R,
|
||||
_t: PhantomData<(S,)>,
|
||||
}
|
||||
|
||||
impl<R, S> Future for FnNewServiceConfigFut<R, S>
|
||||
impl<R, S, E> Future for FnNewServiceConfigFut<R, S, E>
|
||||
where
|
||||
R: IntoFuture,
|
||||
R::Item: IntoService<S>,
|
||||
R: Future<Output = Result<S, E>>,
|
||||
S: Service,
|
||||
{
|
||||
type Item = S;
|
||||
type Error = R::Error;
|
||||
type Output = Result<S, E>;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
Ok(Async::Ready(try_ready!(self.fut.poll()).into_service()))
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
Poll::Ready(Ok(ready!(self.project().fut.poll(cx))?.into_service()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,9 +145,8 @@ struct ApplyConfigNewService<F, C, T, R, S>
|
||||
where
|
||||
C: Clone,
|
||||
F: FnMut(&C, &mut T::Service) -> R,
|
||||
T: NewService<Config = ()>,
|
||||
R: IntoFuture<Error = T::InitError>,
|
||||
R::Item: IntoService<S>,
|
||||
T: ServiceFactory<Config = ()>,
|
||||
R: Future<Output = Result<S, T::InitError>>,
|
||||
S: Service,
|
||||
{
|
||||
f: Cell<F>,
|
||||
@ -161,9 +158,8 @@ impl<F, C, T, R, S> Clone for ApplyConfigNewService<F, C, T, R, S>
|
||||
where
|
||||
C: Clone,
|
||||
F: FnMut(&C, &mut T::Service) -> R,
|
||||
T: NewService<Config = ()>,
|
||||
R: IntoFuture<Error = T::InitError>,
|
||||
R::Item: IntoService<S>,
|
||||
T: ServiceFactory<Config = ()>,
|
||||
R: Future<Output = Result<S, T::InitError>>,
|
||||
S: Service,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
@ -175,14 +171,13 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, C, T, R, S> NewService for ApplyConfigNewService<F, C, T, R, S>
|
||||
impl<F, C, T, R, S> ServiceFactory for ApplyConfigNewService<F, C, T, R, S>
|
||||
where
|
||||
C: Clone,
|
||||
F: FnMut(&C, &mut T::Service) -> R,
|
||||
T: NewService<Config = ()>,
|
||||
T: ServiceFactory<Config = ()>,
|
||||
T::InitError: From<T::Error>,
|
||||
R: IntoFuture<Error = T::InitError>,
|
||||
R::Item: IntoService<S>,
|
||||
R: Future<Output = Result<S, T::InitError>>,
|
||||
S: Service,
|
||||
{
|
||||
type Config = C;
|
||||
@ -191,7 +186,7 @@ where
|
||||
type Error = S::Error;
|
||||
type Service = S;
|
||||
|
||||
type InitError = R::Error;
|
||||
type InitError = T::InitError;
|
||||
type Future = ApplyConfigNewServiceFut<F, C, T, R, S>;
|
||||
|
||||
fn new_service(&self, cfg: &C) -> Self::Future {
|
||||
@ -206,21 +201,23 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[pin_project]
|
||||
struct ApplyConfigNewServiceFut<F, C, T, R, S>
|
||||
where
|
||||
C: Clone,
|
||||
F: FnMut(&C, &mut T::Service) -> R,
|
||||
T: NewService<Config = ()>,
|
||||
T: ServiceFactory<Config = ()>,
|
||||
T::InitError: From<T::Error>,
|
||||
R: IntoFuture<Error = T::InitError>,
|
||||
R::Item: IntoService<S>,
|
||||
R: Future<Output = Result<S, T::InitError>>,
|
||||
S: Service,
|
||||
{
|
||||
cfg: C,
|
||||
f: Cell<F>,
|
||||
srv: Option<T::Service>,
|
||||
#[pin]
|
||||
srv_fut: Option<T::Future>,
|
||||
fut: Option<R::Future>,
|
||||
#[pin]
|
||||
fut: Option<R>,
|
||||
_t: PhantomData<(S,)>,
|
||||
}
|
||||
|
||||
@ -228,39 +225,40 @@ impl<F, C, T, R, S> Future for ApplyConfigNewServiceFut<F, C, T, R, S>
|
||||
where
|
||||
C: Clone,
|
||||
F: FnMut(&C, &mut T::Service) -> R,
|
||||
T: NewService<Config = ()>,
|
||||
T: ServiceFactory<Config = ()>,
|
||||
T::InitError: From<T::Error>,
|
||||
R: IntoFuture<Error = T::InitError>,
|
||||
R::Item: IntoService<S>,
|
||||
R: Future<Output = Result<S, T::InitError>>,
|
||||
S: Service,
|
||||
{
|
||||
type Item = S;
|
||||
type Error = R::Error;
|
||||
type Output = Result<S, T::InitError>;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
if let Some(ref mut fut) = self.srv_fut {
|
||||
match fut.poll()? {
|
||||
Async::NotReady => return Ok(Async::NotReady),
|
||||
Async::Ready(srv) => {
|
||||
let _ = self.srv_fut.take();
|
||||
self.srv = Some(srv);
|
||||
return self.poll();
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let mut this = self.project();
|
||||
'poll: loop {
|
||||
if let Some(fut) = this.srv_fut.as_mut().as_pin_mut() {
|
||||
match fut.poll(cx)? {
|
||||
Poll::Pending => return Poll::Pending,
|
||||
Poll::Ready(srv) => {
|
||||
this.srv_fut.set(None);
|
||||
*this.srv = Some(srv);
|
||||
continue 'poll;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref mut fut) = self.fut {
|
||||
Ok(Async::Ready(try_ready!(fut.poll()).into_service()))
|
||||
} else if let Some(ref mut srv) = self.srv {
|
||||
match srv.poll_ready()? {
|
||||
Async::NotReady => Ok(Async::NotReady),
|
||||
Async::Ready(_) => {
|
||||
self.fut = Some(self.f.get_mut()(&self.cfg, srv).into_future());
|
||||
return self.poll();
|
||||
if let Some(fut) = this.fut.as_mut().as_pin_mut() {
|
||||
return Poll::Ready(Ok(ready!(fut.poll(cx))?.into_service()));
|
||||
} else if let Some(ref mut srv) = this.srv {
|
||||
match srv.poll_ready(cx)? {
|
||||
Poll::Ready(_) => {
|
||||
this.fut.set(Some(this.f.get_mut()(&this.cfg, srv)));
|
||||
continue 'poll;
|
||||
}
|
||||
Poll::Pending => return Poll::Pending,
|
||||
}
|
||||
} else {
|
||||
return Poll::Pending;
|
||||
}
|
||||
} else {
|
||||
Ok(Async::NotReady)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,84 +0,0 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use futures::future::{ok, FutureResult};
|
||||
use futures::{Async, Poll};
|
||||
|
||||
use super::{NewService, Service};
|
||||
|
||||
/// Empty service
|
||||
#[derive(Clone)]
|
||||
pub struct Blank<R, E> {
|
||||
_t: PhantomData<(R, E)>,
|
||||
}
|
||||
|
||||
impl<R, E> Blank<R, E> {
|
||||
pub fn err<E1>(self) -> Blank<R, E1> {
|
||||
Blank { _t: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Blank<R, ()> {
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
pub fn new<E>() -> Blank<R, E> {
|
||||
Blank { _t: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, E> Default for Blank<R, E> {
|
||||
fn default() -> Blank<R, E> {
|
||||
Blank { _t: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, E> Service for Blank<R, E> {
|
||||
type Request = R;
|
||||
type Response = R;
|
||||
type Error = E;
|
||||
type Future = FutureResult<R, E>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
Ok(Async::Ready(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, req: R) -> Self::Future {
|
||||
ok(req)
|
||||
}
|
||||
}
|
||||
|
||||
/// Empty service factory
|
||||
pub struct BlankNewService<R, E1, E2 = ()> {
|
||||
_t: PhantomData<(R, E1, E2)>,
|
||||
}
|
||||
|
||||
impl<R, E1, E2> BlankNewService<R, E1, E2> {
|
||||
pub fn new() -> BlankNewService<R, E1, E2> {
|
||||
BlankNewService { _t: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, E1> BlankNewService<R, E1, ()> {
|
||||
pub fn new_unit() -> BlankNewService<R, E1, ()> {
|
||||
BlankNewService { _t: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, E1, E2> Default for BlankNewService<R, E1, E2> {
|
||||
fn default() -> BlankNewService<R, E1, E2> {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, E1, E2> NewService for BlankNewService<R, E1, E2> {
|
||||
type Request = R;
|
||||
type Response = R;
|
||||
type Error = E1;
|
||||
|
||||
type Config = ();
|
||||
type Service = Blank<R, E1>;
|
||||
type InitError = E2;
|
||||
type Future = FutureResult<Self::Service, Self::InitError>;
|
||||
|
||||
fn new_service(&self, _: &()) -> Self::Future {
|
||||
ok(Blank::default())
|
||||
}
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
use futures::future::{err, ok, Either, FutureResult};
|
||||
use futures::{Async, Future, IntoFuture, Poll};
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use crate::{NewService, Service};
|
||||
use futures::future::{FutureExt, LocalBoxFuture};
|
||||
|
||||
use crate::{Service, ServiceFactory};
|
||||
|
||||
pub type BoxedService<Req, Res, Err> = Box<
|
||||
dyn Service<
|
||||
@ -12,17 +13,16 @@ pub type BoxedService<Req, Res, Err> = Box<
|
||||
>,
|
||||
>;
|
||||
|
||||
pub type BoxedServiceResponse<Res, Err> =
|
||||
Either<FutureResult<Res, Err>, Box<dyn Future<Item = Res, Error = Err>>>;
|
||||
pub type BoxedServiceResponse<Res, Err> = LocalBoxFuture<'static, Result<Res, Err>>;
|
||||
|
||||
pub struct BoxedNewService<C, Req, Res, Err, InitErr>(Inner<C, Req, Res, Err, InitErr>);
|
||||
|
||||
/// Create boxed new service
|
||||
pub fn new_service<T>(
|
||||
service: T,
|
||||
pub fn factory<T>(
|
||||
factory: T,
|
||||
) -> BoxedNewService<T::Config, T::Request, T::Response, T::Error, T::InitError>
|
||||
where
|
||||
T: NewService + 'static,
|
||||
T: ServiceFactory + 'static,
|
||||
T::Request: 'static,
|
||||
T::Response: 'static,
|
||||
T::Service: 'static,
|
||||
@ -30,8 +30,8 @@ where
|
||||
T::Error: 'static,
|
||||
T::InitError: 'static,
|
||||
{
|
||||
BoxedNewService(Box::new(NewServiceWrapper {
|
||||
service,
|
||||
BoxedNewService(Box::new(FactoryWrapper {
|
||||
factory,
|
||||
_t: std::marker::PhantomData,
|
||||
}))
|
||||
}
|
||||
@ -46,18 +46,18 @@ where
|
||||
}
|
||||
|
||||
type Inner<C, Req, Res, Err, InitErr> = Box<
|
||||
dyn NewService<
|
||||
dyn ServiceFactory<
|
||||
Config = C,
|
||||
Request = Req,
|
||||
Response = Res,
|
||||
Error = Err,
|
||||
InitError = InitErr,
|
||||
Service = BoxedService<Req, Res, Err>,
|
||||
Future = Box<dyn Future<Item = BoxedService<Req, Res, Err>, Error = InitErr>>,
|
||||
Future = LocalBoxFuture<'static, Result<BoxedService<Req, Res, Err>, InitErr>>,
|
||||
>,
|
||||
>;
|
||||
|
||||
impl<C, Req, Res, Err, InitErr> NewService for BoxedNewService<C, Req, Res, Err, InitErr>
|
||||
impl<C, Req, Res, Err, InitErr> ServiceFactory for BoxedNewService<C, Req, Res, Err, InitErr>
|
||||
where
|
||||
Req: 'static,
|
||||
Res: 'static,
|
||||
@ -70,25 +70,32 @@ where
|
||||
type InitError = InitErr;
|
||||
type Config = C;
|
||||
type Service = BoxedService<Req, Res, Err>;
|
||||
type Future = Box<dyn Future<Item = Self::Service, Error = Self::InitError>>;
|
||||
|
||||
type Future = LocalBoxFuture<'static, Result<Self::Service, InitErr>>;
|
||||
|
||||
fn new_service(&self, cfg: &C) -> Self::Future {
|
||||
self.0.new_service(cfg)
|
||||
}
|
||||
}
|
||||
|
||||
struct NewServiceWrapper<C, T: NewService> {
|
||||
service: T,
|
||||
struct FactoryWrapper<C, T: ServiceFactory> {
|
||||
factory: T,
|
||||
_t: std::marker::PhantomData<C>,
|
||||
}
|
||||
|
||||
impl<C, T, Req, Res, Err, InitErr> NewService for NewServiceWrapper<C, T>
|
||||
impl<C, T, Req, Res, Err, InitErr> ServiceFactory for FactoryWrapper<C, T>
|
||||
where
|
||||
Req: 'static,
|
||||
Res: 'static,
|
||||
Err: 'static,
|
||||
InitErr: 'static,
|
||||
T: NewService<Config = C, Request = Req, Response = Res, Error = Err, InitError = InitErr>,
|
||||
T: ServiceFactory<
|
||||
Config = C,
|
||||
Request = Req,
|
||||
Response = Res,
|
||||
Error = Err,
|
||||
InitError = InitErr,
|
||||
>,
|
||||
T::Future: 'static,
|
||||
T::Service: 'static,
|
||||
<T::Service as Service>::Future: 'static,
|
||||
@ -99,15 +106,13 @@ where
|
||||
type InitError = InitErr;
|
||||
type Config = C;
|
||||
type Service = BoxedService<Req, Res, Err>;
|
||||
type Future = Box<dyn Future<Item = Self::Service, Error = Self::InitError>>;
|
||||
type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;
|
||||
|
||||
fn new_service(&self, cfg: &C) -> Self::Future {
|
||||
Box::new(
|
||||
self.service
|
||||
.new_service(cfg)
|
||||
.into_future()
|
||||
.map(ServiceWrapper::boxed),
|
||||
)
|
||||
self.factory
|
||||
.new_service(cfg)
|
||||
.map(|res| res.map(ServiceWrapper::boxed))
|
||||
.boxed_local()
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,21 +136,13 @@ where
|
||||
type Request = Req;
|
||||
type Response = Res;
|
||||
type Error = Err;
|
||||
type Future = Either<
|
||||
FutureResult<Self::Response, Self::Error>,
|
||||
Box<dyn Future<Item = Self::Response, Error = Self::Error>>,
|
||||
>;
|
||||
type Future = LocalBoxFuture<'static, Result<Res, Err>>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
self.0.poll_ready()
|
||||
fn poll_ready(&mut self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.0.poll_ready(ctx)
|
||||
}
|
||||
|
||||
fn call(&mut self, req: Self::Request) -> Self::Future {
|
||||
let mut fut = self.0.call(req);
|
||||
match fut.poll() {
|
||||
Ok(Async::Ready(res)) => Either::A(ok(res)),
|
||||
Err(e) => Either::A(err(e)),
|
||||
Ok(Async::NotReady) => Either::B(Box::new(fut)),
|
||||
}
|
||||
self.0.call(req).boxed_local()
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
//! Custom cell impl
|
||||
//! Custom cell impl, internal use only
|
||||
use std::{cell::UnsafeCell, fmt, rc::Rc};
|
||||
|
||||
pub(crate) struct Cell<T> {
|
||||
|
@ -1,248 +1,245 @@
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use futures::future::{ok, Future, FutureResult};
|
||||
use futures::{try_ready, Async, IntoFuture, Poll};
|
||||
use futures::future::{ok, Ready};
|
||||
use pin_project::pin_project;
|
||||
|
||||
use crate::{IntoNewService, IntoService, NewService, Service};
|
||||
use crate::{IntoService, IntoServiceFactory, Service, ServiceFactory};
|
||||
|
||||
/// Create `NewService` for function that can act as a Service
|
||||
pub fn service_fn<F, Req, Out, Cfg>(f: F) -> NewServiceFn<F, Req, Out, Cfg>
|
||||
/// Create `ServiceFactory` for function that can act as a `Service`
|
||||
pub fn service_fn<F, Fut, Req, Res, Err, Cfg>(
|
||||
f: F,
|
||||
) -> impl ServiceFactory<Config = Cfg, Request = Req, Response = Res, Error = Err, InitError = ()>
|
||||
+ Clone
|
||||
where
|
||||
F: FnMut(Req) -> Out + Clone,
|
||||
Out: IntoFuture,
|
||||
F: FnMut(Req) -> Fut + Clone,
|
||||
Fut: Future<Output = Result<Res, Err>>,
|
||||
{
|
||||
NewServiceFn::new(f)
|
||||
}
|
||||
|
||||
/// Create `NewService` for function that can produce services
|
||||
pub fn new_service_fn<F, C, R, S, E>(f: F) -> FnNewServiceNoConfig<F, C, R, S, E>
|
||||
pub fn service_fn2<F, Fut, Req, Res, Err>(
|
||||
f: F,
|
||||
) -> impl Service<Request = Req, Response = Res, Error = Err>
|
||||
where
|
||||
F: FnMut(Req) -> Fut,
|
||||
Fut: Future<Output = Result<Res, Err>>,
|
||||
{
|
||||
ServiceFn::new(f)
|
||||
}
|
||||
|
||||
/// Create `ServiceFactory` for function that can produce services
|
||||
pub fn factory_fn<S, F, Cfg, Fut, Err>(
|
||||
f: F,
|
||||
) -> impl ServiceFactory<
|
||||
Config = Cfg,
|
||||
Service = S,
|
||||
Request = S::Request,
|
||||
Response = S::Response,
|
||||
Error = S::Error,
|
||||
InitError = Err,
|
||||
Future = Fut,
|
||||
>
|
||||
where
|
||||
F: Fn() -> R,
|
||||
R: IntoFuture<Item = S, Error = E>,
|
||||
R::Item: IntoService<S>,
|
||||
S: Service,
|
||||
F: Fn() -> Fut,
|
||||
Fut: Future<Output = Result<S, Err>>,
|
||||
{
|
||||
FnNewServiceNoConfig::new(f)
|
||||
}
|
||||
|
||||
/// Create `NewService` for function that can produce services with configuration
|
||||
pub fn new_service_cfg<F, C, R, S, E>(f: F) -> FnNewServiceConfig<F, C, R, S, E>
|
||||
/// Create `ServiceFactory` for function that can produce services with configuration
|
||||
pub fn factory_fn_cfg<F, Fut, Cfg, Srv, Err>(
|
||||
f: F,
|
||||
) -> impl ServiceFactory<
|
||||
Config = Cfg,
|
||||
Service = Srv,
|
||||
Request = Srv::Request,
|
||||
Response = Srv::Response,
|
||||
Error = Srv::Error,
|
||||
InitError = Err,
|
||||
>
|
||||
where
|
||||
F: Fn(&C) -> R,
|
||||
R: IntoFuture<Error = E>,
|
||||
R::Item: IntoService<S>,
|
||||
S: Service,
|
||||
F: Fn(&Cfg) -> Fut,
|
||||
Fut: Future<Output = Result<Srv, Err>>,
|
||||
Srv: Service,
|
||||
{
|
||||
FnNewServiceConfig::new(f)
|
||||
}
|
||||
|
||||
pub struct ServiceFn<F, Req, Out>
|
||||
pub struct ServiceFn<F, Fut, Req, Res, Err>
|
||||
where
|
||||
F: FnMut(Req) -> Out,
|
||||
Out: IntoFuture,
|
||||
F: FnMut(Req) -> Fut,
|
||||
Fut: Future<Output = Result<Res, Err>>,
|
||||
{
|
||||
f: F,
|
||||
_t: PhantomData<Req>,
|
||||
}
|
||||
|
||||
impl<F, Req, Out> ServiceFn<F, Req, Out>
|
||||
impl<F, Fut, Req, Res, Err> ServiceFn<F, Fut, Req, Res, Err>
|
||||
where
|
||||
F: FnMut(Req) -> Out,
|
||||
Out: IntoFuture,
|
||||
F: FnMut(Req) -> Fut,
|
||||
Fut: Future<Output = Result<Res, Err>>,
|
||||
{
|
||||
pub(crate) fn new(f: F) -> Self {
|
||||
ServiceFn { f, _t: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, Req, Out> Clone for ServiceFn<F, Req, Out>
|
||||
impl<F, Fut, Req, Res, Err> Clone for ServiceFn<F, Fut, Req, Res, Err>
|
||||
where
|
||||
F: FnMut(Req) -> Out + Clone,
|
||||
Out: IntoFuture,
|
||||
F: FnMut(Req) -> Fut + Clone,
|
||||
Fut: Future<Output = Result<Res, Err>>,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
ServiceFn::new(self.f.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, Req, Out> Service for ServiceFn<F, Req, Out>
|
||||
impl<F, Fut, Req, Res, Err> Service for ServiceFn<F, Fut, Req, Res, Err>
|
||||
where
|
||||
F: FnMut(Req) -> Out,
|
||||
Out: IntoFuture,
|
||||
F: FnMut(Req) -> Fut,
|
||||
Fut: Future<Output = Result<Res, Err>>,
|
||||
{
|
||||
type Request = Req;
|
||||
type Response = Out::Item;
|
||||
type Error = Out::Error;
|
||||
type Future = Out::Future;
|
||||
type Response = Res;
|
||||
type Error = Err;
|
||||
type Future = Fut;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
Ok(Async::Ready(()))
|
||||
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, req: Req) -> Self::Future {
|
||||
(self.f)(req).into_future()
|
||||
(self.f)(req)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, Req, Out> IntoService<ServiceFn<F, Req, Out>> for F
|
||||
impl<F, Fut, Req, Res, Err> IntoService<ServiceFn<F, Fut, Req, Res, Err>> for F
|
||||
where
|
||||
F: FnMut(Req) -> Out,
|
||||
Out: IntoFuture,
|
||||
F: FnMut(Req) -> Fut,
|
||||
Fut: Future<Output = Result<Res, Err>>,
|
||||
{
|
||||
fn into_service(self) -> ServiceFn<F, Req, Out> {
|
||||
fn into_service(self) -> ServiceFn<F, Fut, Req, Res, Err> {
|
||||
ServiceFn::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NewServiceFn<F, Req, Out, Cfg>
|
||||
struct NewServiceFn<F, Fut, Req, Res, Err, Cfg>
|
||||
where
|
||||
F: FnMut(Req) -> Out,
|
||||
Out: IntoFuture,
|
||||
F: FnMut(Req) -> Fut,
|
||||
Fut: Future<Output = Result<Res, Err>>,
|
||||
{
|
||||
f: F,
|
||||
_t: PhantomData<(Req, Cfg)>,
|
||||
}
|
||||
|
||||
impl<F, Req, Out, Cfg> NewServiceFn<F, Req, Out, Cfg>
|
||||
impl<F, Fut, Req, Res, Err, Cfg> NewServiceFn<F, Fut, Req, Res, Err, Cfg>
|
||||
where
|
||||
F: FnMut(Req) -> Out + Clone,
|
||||
Out: IntoFuture,
|
||||
F: FnMut(Req) -> Fut + Clone,
|
||||
Fut: Future<Output = Result<Res, Err>>,
|
||||
{
|
||||
pub(crate) fn new(f: F) -> Self {
|
||||
fn new(f: F) -> Self {
|
||||
NewServiceFn { f, _t: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, Req, Out, Cfg> Clone for NewServiceFn<F, Req, Out, Cfg>
|
||||
impl<F, Fut, Req, Res, Err, Cfg> Clone for NewServiceFn<F, Fut, Req, Res, Err, Cfg>
|
||||
where
|
||||
F: FnMut(Req) -> Out + Clone,
|
||||
Out: IntoFuture,
|
||||
F: FnMut(Req) -> Fut + Clone,
|
||||
Fut: Future<Output = Result<Res, Err>>,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
NewServiceFn::new(self.f.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, Req, Out, Cfg> NewService for NewServiceFn<F, Req, Out, Cfg>
|
||||
impl<F, Fut, Req, Res, Err, Cfg> ServiceFactory for NewServiceFn<F, Fut, Req, Res, Err, Cfg>
|
||||
where
|
||||
F: FnMut(Req) -> Out + Clone,
|
||||
Out: IntoFuture,
|
||||
F: FnMut(Req) -> Fut + Clone,
|
||||
Fut: Future<Output = Result<Res, Err>>,
|
||||
{
|
||||
type Request = Req;
|
||||
type Response = Out::Item;
|
||||
type Error = Out::Error;
|
||||
type Response = Res;
|
||||
type Error = Err;
|
||||
|
||||
type Config = Cfg;
|
||||
type Service = ServiceFn<F, Req, Out>;
|
||||
type Service = ServiceFn<F, Fut, Req, Res, Err>;
|
||||
type InitError = ();
|
||||
type Future = FutureResult<Self::Service, Self::InitError>;
|
||||
type Future = Ready<Result<Self::Service, Self::InitError>>;
|
||||
|
||||
fn new_service(&self, _: &Cfg) -> Self::Future {
|
||||
ok(ServiceFn::new(self.f.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, Req, Out, Cfg> IntoService<ServiceFn<F, Req, Out>> for NewServiceFn<F, Req, Out, Cfg>
|
||||
where
|
||||
F: FnMut(Req) -> Out + Clone,
|
||||
Out: IntoFuture,
|
||||
{
|
||||
fn into_service(self) -> ServiceFn<F, Req, Out> {
|
||||
ServiceFn::new(self.f.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, Req, Out, Cfg> IntoNewService<NewServiceFn<F, Req, Out, Cfg>> for F
|
||||
where
|
||||
F: Fn(Req) -> Out + Clone,
|
||||
Out: IntoFuture,
|
||||
{
|
||||
fn into_new_service(self) -> NewServiceFn<F, Req, Out, Cfg> {
|
||||
NewServiceFn::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert `Fn(&Config) -> Future<Service>` fn to NewService
|
||||
pub struct FnNewServiceConfig<F, C, R, S, E>
|
||||
struct FnNewServiceConfig<F, Fut, Cfg, Srv, Err>
|
||||
where
|
||||
F: Fn(&C) -> R,
|
||||
R: IntoFuture<Error = E>,
|
||||
R::Item: IntoService<S>,
|
||||
S: Service,
|
||||
F: Fn(&Cfg) -> Fut,
|
||||
Fut: Future<Output = Result<Srv, Err>>,
|
||||
Srv: Service,
|
||||
{
|
||||
f: F,
|
||||
_t: PhantomData<(C, R, S, E)>,
|
||||
_t: PhantomData<(Fut, Cfg, Srv, Err)>,
|
||||
}
|
||||
|
||||
impl<F, C, R, S, E> FnNewServiceConfig<F, C, R, S, E>
|
||||
impl<F, Fut, Cfg, Srv, Err> FnNewServiceConfig<F, Fut, Cfg, Srv, Err>
|
||||
where
|
||||
F: Fn(&C) -> R,
|
||||
R: IntoFuture<Error = E>,
|
||||
R::Item: IntoService<S>,
|
||||
S: Service,
|
||||
F: Fn(&Cfg) -> Fut,
|
||||
Fut: Future<Output = Result<Srv, Err>>,
|
||||
Srv: Service,
|
||||
{
|
||||
pub fn new(f: F) -> Self {
|
||||
FnNewServiceConfig { f, _t: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, C, R, S, E> NewService for FnNewServiceConfig<F, C, R, S, E>
|
||||
impl<F, Fut, Cfg, Srv, Err> ServiceFactory for FnNewServiceConfig<F, Fut, Cfg, Srv, Err>
|
||||
where
|
||||
F: Fn(&C) -> R,
|
||||
R: IntoFuture<Error = E>,
|
||||
R::Item: IntoService<S>,
|
||||
S: Service,
|
||||
F: Fn(&Cfg) -> Fut,
|
||||
Fut: Future<Output = Result<Srv, Err>>,
|
||||
Srv: Service,
|
||||
{
|
||||
type Request = S::Request;
|
||||
type Response = S::Response;
|
||||
type Error = S::Error;
|
||||
type Request = Srv::Request;
|
||||
type Response = Srv::Response;
|
||||
type Error = Srv::Error;
|
||||
|
||||
type Config = C;
|
||||
type Service = S;
|
||||
type InitError = E;
|
||||
type Future = FnNewServiceConfigFut<R, S, E>;
|
||||
type Config = Cfg;
|
||||
type Service = Srv;
|
||||
type InitError = Err;
|
||||
type Future = FnNewServiceConfigFut<Fut, Srv, Err>;
|
||||
|
||||
fn new_service(&self, cfg: &C) -> Self::Future {
|
||||
fn new_service(&self, cfg: &Cfg) -> Self::Future {
|
||||
FnNewServiceConfigFut {
|
||||
fut: (self.f)(cfg).into_future(),
|
||||
fut: (self.f)(cfg),
|
||||
_t: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FnNewServiceConfigFut<R, S, E>
|
||||
#[pin_project]
|
||||
struct FnNewServiceConfigFut<R, S, E>
|
||||
where
|
||||
R: IntoFuture<Error = E>,
|
||||
R::Item: IntoService<S>,
|
||||
R: Future<Output = Result<S, E>>,
|
||||
S: Service,
|
||||
{
|
||||
fut: R::Future,
|
||||
#[pin]
|
||||
fut: R,
|
||||
_t: PhantomData<(S,)>,
|
||||
}
|
||||
|
||||
impl<R, S, E> Future for FnNewServiceConfigFut<R, S, E>
|
||||
where
|
||||
R: IntoFuture<Error = E>,
|
||||
R::Item: IntoService<S>,
|
||||
R: Future<Output = Result<S, E>>,
|
||||
S: Service,
|
||||
{
|
||||
type Item = S;
|
||||
type Error = R::Error;
|
||||
type Output = Result<S, E>;
|
||||
|
||||
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
|
||||
F: Fn(&C) -> R + Clone,
|
||||
R: IntoFuture<Error = E>,
|
||||
R::Item: IntoService<S>,
|
||||
S: Service,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self::new(self.f.clone())
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
Poll::Ready(Ok(futures::ready!(self.project().fut.poll(cx))?))
|
||||
}
|
||||
}
|
||||
|
||||
@ -250,7 +247,7 @@ where
|
||||
pub struct FnNewServiceNoConfig<F, C, R, S, E>
|
||||
where
|
||||
F: Fn() -> R,
|
||||
R: IntoFuture<Item = S, Error = E>,
|
||||
R: Future<Output = Result<S, E>>,
|
||||
S: Service,
|
||||
{
|
||||
f: F,
|
||||
@ -260,18 +257,18 @@ where
|
||||
impl<F, C, R, S, E> FnNewServiceNoConfig<F, C, R, S, E>
|
||||
where
|
||||
F: Fn() -> R,
|
||||
R: IntoFuture<Item = S, Error = E>,
|
||||
R: Future<Output = Result<S, E>>,
|
||||
S: Service,
|
||||
{
|
||||
pub fn new(f: F) -> Self {
|
||||
fn new(f: F) -> Self {
|
||||
FnNewServiceNoConfig { f, _t: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, C, R, S, E> NewService for FnNewServiceNoConfig<F, C, R, S, E>
|
||||
impl<F, C, R, S, E> ServiceFactory for FnNewServiceNoConfig<F, C, R, S, E>
|
||||
where
|
||||
F: Fn() -> R,
|
||||
R: IntoFuture<Item = S, Error = E>,
|
||||
R: Future<Output = Result<S, E>>,
|
||||
S: Service,
|
||||
{
|
||||
type Request = S::Request;
|
||||
@ -280,17 +277,17 @@ where
|
||||
type Service = S;
|
||||
type Config = C;
|
||||
type InitError = E;
|
||||
type Future = R::Future;
|
||||
type Future = R;
|
||||
|
||||
fn new_service(&self, _: &C) -> Self::Future {
|
||||
(self.f)().into_future()
|
||||
(self.f)()
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, C, R, S, E> Clone for FnNewServiceNoConfig<F, C, R, S, E>
|
||||
where
|
||||
F: Fn() -> R + Clone,
|
||||
R: IntoFuture<Item = S, Error = E>,
|
||||
R: Future<Output = Result<S, E>>,
|
||||
S: Service,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
@ -298,13 +295,13 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, C, R, S, E> IntoNewService<FnNewServiceNoConfig<F, C, R, S, E>> for F
|
||||
impl<F, C, R, S, E> IntoServiceFactory<FnNewServiceNoConfig<F, C, R, S, E>> for F
|
||||
where
|
||||
F: Fn() -> R,
|
||||
R: IntoFuture<Item = S, Error = E>,
|
||||
R: Future<Output = Result<S, E>>,
|
||||
S: Service,
|
||||
{
|
||||
fn into_new_service(self) -> FnNewServiceNoConfig<F, C, R, S, E> {
|
||||
fn into_factory(self) -> FnNewServiceNoConfig<F, C, R, S, E> {
|
||||
FnNewServiceNoConfig::new(self)
|
||||
}
|
||||
}
|
||||
|
@ -1,80 +0,0 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use futures::future::{ok, FutureResult};
|
||||
use futures::IntoFuture;
|
||||
|
||||
use crate::apply::Apply;
|
||||
use crate::{IntoTransform, Service, Transform};
|
||||
|
||||
/// Use function as transform service
|
||||
pub fn transform_fn<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
|
||||
F: FnMut(In, &mut S) -> Out + Clone,
|
||||
Out: IntoFuture,
|
||||
{
|
||||
f: F,
|
||||
_t: PhantomData<(S, In, Out, Err)>,
|
||||
}
|
||||
|
||||
impl<F, S, In, Out, Err> FnTransform<F, S, In, Out, Err>
|
||||
where
|
||||
F: FnMut(In, &mut S) -> Out + Clone,
|
||||
Out: IntoFuture,
|
||||
{
|
||||
pub fn new(f: F) -> Self {
|
||||
FnTransform { f, _t: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, S, In, Out, Err> Transform<S> for FnTransform<F, S, In, Out, Err>
|
||||
where
|
||||
S: Service,
|
||||
F: FnMut(In, &mut S) -> Out + Clone,
|
||||
Out: IntoFuture,
|
||||
Out::Error: From<S::Error>,
|
||||
{
|
||||
type Request = In;
|
||||
type Response = Out::Item;
|
||||
type Error = Out::Error;
|
||||
type Transform = Apply<S, F, In, Out>;
|
||||
type InitError = Err;
|
||||
type Future = FutureResult<Self::Transform, Self::InitError>;
|
||||
|
||||
fn new_transform(&self, service: S) -> Self::Future {
|
||||
ok(Apply::new(service, self.f.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, S, In, Out, Err> IntoTransform<FnTransform<F, S, In, Out, Err>, S> for F
|
||||
where
|
||||
S: Service,
|
||||
F: FnMut(In, &mut S) -> Out + Clone,
|
||||
Out: IntoFuture,
|
||||
Out::Error: From<S::Error>,
|
||||
{
|
||||
fn into_transform(self) -> FnTransform<F, S, In, Out, Err> {
|
||||
FnTransform::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, S, In, Out, Err> Clone for FnTransform<F, S, In, Out, Err>
|
||||
where
|
||||
F: FnMut(In, &mut S) -> Out + Clone,
|
||||
Out: IntoFuture,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self::new(self.f.clone())
|
||||
}
|
||||
}
|
@ -1,220 +0,0 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use futures::{Async, Future, Poll};
|
||||
|
||||
use super::{NewService, Service};
|
||||
|
||||
/// Service for the `from_err` combinator, changing the error type of a service.
|
||||
///
|
||||
/// This is created by the `ServiceExt::from_err` method.
|
||||
pub struct FromErr<A, E> {
|
||||
service: A,
|
||||
f: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<A, E> FromErr<A, E> {
|
||||
pub(crate) fn new(service: A) -> Self
|
||||
where
|
||||
A: Service,
|
||||
E: From<A::Error>,
|
||||
{
|
||||
FromErr {
|
||||
service,
|
||||
f: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, E> Clone for FromErr<A, E>
|
||||
where
|
||||
A: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
FromErr {
|
||||
service: self.service.clone(),
|
||||
f: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, E> Service for FromErr<A, E>
|
||||
where
|
||||
A: Service,
|
||||
E: From<A::Error>,
|
||||
{
|
||||
type Request = A::Request;
|
||||
type Response = A::Response;
|
||||
type Error = E;
|
||||
type Future = FromErrFuture<A, E>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), E> {
|
||||
self.service.poll_ready().map_err(E::from)
|
||||
}
|
||||
|
||||
fn call(&mut self, req: A::Request) -> Self::Future {
|
||||
FromErrFuture {
|
||||
fut: self.service.call(req),
|
||||
f: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FromErrFuture<A: Service, E> {
|
||||
fut: A::Future,
|
||||
f: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<A, E> Future for FromErrFuture<A, E>
|
||||
where
|
||||
A: Service,
|
||||
E: From<A::Error>,
|
||||
{
|
||||
type Item = A::Response;
|
||||
type Error = E;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
self.fut.poll().map_err(E::from)
|
||||
}
|
||||
}
|
||||
|
||||
/// NewService for the `from_err` combinator, changing the type of a new
|
||||
/// service's error.
|
||||
///
|
||||
/// This is created by the `NewServiceExt::from_err` method.
|
||||
pub struct FromErrNewService<A, E> {
|
||||
a: A,
|
||||
e: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<A, E> FromErrNewService<A, E> {
|
||||
/// Create new `FromErr` new service instance
|
||||
pub fn new(a: A) -> Self
|
||||
where
|
||||
A: NewService,
|
||||
E: From<A::Error>,
|
||||
{
|
||||
Self { a, e: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, E> Clone for FromErrNewService<A, E>
|
||||
where
|
||||
A: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
a: self.a.clone(),
|
||||
e: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, E> NewService for FromErrNewService<A, E>
|
||||
where
|
||||
A: NewService,
|
||||
E: From<A::Error>,
|
||||
{
|
||||
type Request = A::Request;
|
||||
type Response = A::Response;
|
||||
type Error = E;
|
||||
|
||||
type Config = A::Config;
|
||||
type Service = FromErr<A::Service, E>;
|
||||
type InitError = A::InitError;
|
||||
type Future = FromErrNewServiceFuture<A, E>;
|
||||
|
||||
fn new_service(&self, cfg: &A::Config) -> Self::Future {
|
||||
FromErrNewServiceFuture {
|
||||
fut: self.a.new_service(cfg),
|
||||
e: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FromErrNewServiceFuture<A, E>
|
||||
where
|
||||
A: NewService,
|
||||
E: From<A::Error>,
|
||||
{
|
||||
fut: A::Future,
|
||||
e: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<A, E> Future for FromErrNewServiceFuture<A, E>
|
||||
where
|
||||
A: NewService,
|
||||
E: From<A::Error>,
|
||||
{
|
||||
type Item = FromErr<A::Service, E>;
|
||||
type Error = A::InitError;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
if let Async::Ready(service) = self.fut.poll()? {
|
||||
Ok(Async::Ready(FromErr::new(service)))
|
||||
} else {
|
||||
Ok(Async::NotReady)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use futures::future::{err, FutureResult};
|
||||
|
||||
use super::*;
|
||||
use crate::{IntoNewService, NewService, Service, ServiceExt};
|
||||
|
||||
struct Srv;
|
||||
impl Service for Srv {
|
||||
type Request = ();
|
||||
type Response = ();
|
||||
type Error = ();
|
||||
type Future = FutureResult<(), ()>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
Err(())
|
||||
}
|
||||
|
||||
fn call(&mut self, _: ()) -> Self::Future {
|
||||
err(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct Error;
|
||||
|
||||
impl From<()> for Error {
|
||||
fn from(_: ()) -> Self {
|
||||
Error
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_poll_ready() {
|
||||
let mut srv = Srv.from_err::<Error>();
|
||||
let res = srv.poll_ready();
|
||||
assert!(res.is_err());
|
||||
assert_eq!(res.err().unwrap(), Error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_call() {
|
||||
let mut srv = Srv.from_err::<Error>();
|
||||
let res = srv.call(()).poll();
|
||||
assert!(res.is_err());
|
||||
assert_eq!(res.err().unwrap(), Error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_service() {
|
||||
let blank = || Ok::<_, ()>(Srv);
|
||||
let new_srv = blank.into_new_service().from_err::<Error>();
|
||||
if let Async::Ready(mut srv) = new_srv.new_service(&()).poll().unwrap() {
|
||||
let res = srv.call(()).poll();
|
||||
assert!(res.is_err());
|
||||
assert_eq!(res.err().unwrap(), Error);
|
||||
} else {
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
}
|
204
actix-service/src/into.rs
Normal file
204
actix-service/src/into.rs
Normal file
@ -0,0 +1,204 @@
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use crate::map::{Map, MapNewService};
|
||||
use crate::map_err::{MapErr, MapErrNewService};
|
||||
use crate::map_init_err::MapInitErr;
|
||||
use crate::{IntoService, IntoServiceFactory, Service, ServiceFactory};
|
||||
|
||||
#[inline]
|
||||
/// Convert object of type `U` to a service `T`
|
||||
pub fn into_service<T, U>(service: U) -> ServiceMapper<T>
|
||||
where
|
||||
U: IntoService<T>,
|
||||
T: Service,
|
||||
{
|
||||
ServiceMapper {
|
||||
service: service.into_service(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_factory<T, F>(factory: F) -> ServiceFactoryMapper<T>
|
||||
where
|
||||
T: ServiceFactory,
|
||||
F: IntoServiceFactory<T>,
|
||||
{
|
||||
ServiceFactoryMapper {
|
||||
factory: factory.into_factory(),
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ServiceMapper<T> {
|
||||
service: T,
|
||||
}
|
||||
|
||||
pub struct ServiceFactoryMapper<T> {
|
||||
factory: T,
|
||||
}
|
||||
|
||||
impl<T: Service> ServiceMapper<T> {
|
||||
/// Map this service's output to a different type, returning a new service
|
||||
/// of the resulting type.
|
||||
///
|
||||
/// This function is similar to the `Option::map` or `Iterator::map` where
|
||||
/// it will change the type of the underlying service.
|
||||
///
|
||||
/// Note that this function consumes the receiving service and returns a
|
||||
/// wrapped version of it, similar to the existing `map` methods in the
|
||||
/// standard library.
|
||||
pub fn map<F, R>(
|
||||
self,
|
||||
f: F,
|
||||
) -> ServiceMapper<impl Service<Request = T::Request, Response = R, Error = T::Error>>
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(T::Response) -> R + Clone,
|
||||
{
|
||||
ServiceMapper {
|
||||
service: Map::new(self.service, f),
|
||||
}
|
||||
}
|
||||
|
||||
/// Map this service's error to a different error, returning a new service.
|
||||
///
|
||||
/// This function is similar to the `Result::map_err` where it will change
|
||||
/// the error type of the underlying service. This is useful for example to
|
||||
/// ensure that services have the same error type.
|
||||
///
|
||||
/// Note that this function consumes the receiving service and returns a
|
||||
/// wrapped version of it.
|
||||
pub fn map_err<F, E>(
|
||||
self,
|
||||
f: F,
|
||||
) -> ServiceMapper<impl Service<Request = T::Request, Response = T::Response, Error = E>>
|
||||
where
|
||||
Self: Sized,
|
||||
F: Fn(T::Error) -> E + Clone,
|
||||
{
|
||||
ServiceMapper {
|
||||
service: MapErr::new(self, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for ServiceMapper<T>
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
ServiceMapper {
|
||||
service: self.service.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Service> Service for ServiceMapper<T> {
|
||||
type Request = T::Request;
|
||||
type Response = T::Response;
|
||||
type Error = T::Error;
|
||||
type Future = T::Future;
|
||||
|
||||
#[inline]
|
||||
fn poll_ready(&mut self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.service.poll_ready(ctx)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn call(&mut self, req: T::Request) -> Self::Future {
|
||||
self.service.call(req)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ServiceFactory> ServiceFactoryMapper<T> {
|
||||
/// Map this service's output to a different type, returning a new service
|
||||
/// of the resulting type.
|
||||
pub fn map<F, R>(
|
||||
self,
|
||||
f: F,
|
||||
) -> ServiceFactoryMapper<
|
||||
impl ServiceFactory<
|
||||
Config = T::Config,
|
||||
Request = T::Request,
|
||||
Response = R,
|
||||
Error = T::Error,
|
||||
InitError = T::InitError,
|
||||
>,
|
||||
>
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(T::Response) -> R + Clone,
|
||||
{
|
||||
ServiceFactoryMapper {
|
||||
factory: MapNewService::new(self.factory, f),
|
||||
}
|
||||
}
|
||||
|
||||
/// Map this service's error to a different error, returning a new service.
|
||||
pub fn map_err<F, E>(
|
||||
self,
|
||||
f: F,
|
||||
) -> ServiceFactoryMapper<
|
||||
impl ServiceFactory<
|
||||
Config = T::Config,
|
||||
Request = T::Request,
|
||||
Response = T::Response,
|
||||
Error = E,
|
||||
InitError = T::InitError,
|
||||
>,
|
||||
>
|
||||
where
|
||||
Self: Sized,
|
||||
F: Fn(T::Error) -> E + Clone,
|
||||
{
|
||||
ServiceFactoryMapper {
|
||||
factory: MapErrNewService::new(self.factory, f),
|
||||
}
|
||||
}
|
||||
|
||||
/// Map this factory's init error to a different error, returning a new service.
|
||||
pub fn map_init_err<F, E>(
|
||||
self,
|
||||
f: F,
|
||||
) -> ServiceFactoryMapper<
|
||||
impl ServiceFactory<
|
||||
Config = T::Config,
|
||||
Request = T::Request,
|
||||
Response = T::Response,
|
||||
Error = T::Error,
|
||||
InitError = E,
|
||||
>,
|
||||
>
|
||||
where
|
||||
Self: Sized,
|
||||
F: Fn(T::InitError) -> E + Clone,
|
||||
{
|
||||
ServiceFactoryMapper {
|
||||
factory: MapInitErr::new(self.factory, f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for ServiceFactoryMapper<T>
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
ServiceFactoryMapper {
|
||||
factory: self.factory.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ServiceFactory> ServiceFactory for ServiceFactoryMapper<T> {
|
||||
type Config = T::Config;
|
||||
type Request = T::Request;
|
||||
type Response = T::Response;
|
||||
type Error = T::Error;
|
||||
type Service = T::Service;
|
||||
type InitError = T::InitError;
|
||||
type Future = T::Future;
|
||||
|
||||
#[inline]
|
||||
fn new_service(&self, cfg: &T::Config) -> Self::Future {
|
||||
self.factory.new_service(cfg)
|
||||
}
|
||||
}
|
@ -1,43 +1,32 @@
|
||||
use std::cell::RefCell;
|
||||
use std::future::Future;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use futures::{Future, IntoFuture, Poll};
|
||||
use std::task::{self, Context, Poll};
|
||||
|
||||
mod and_then;
|
||||
mod and_then_apply;
|
||||
mod and_then_apply_fn;
|
||||
mod apply;
|
||||
mod apply_cfg;
|
||||
pub mod blank;
|
||||
pub mod boxed;
|
||||
mod cell;
|
||||
mod fn_service;
|
||||
mod fn_transform;
|
||||
mod from_err;
|
||||
mod into;
|
||||
mod map;
|
||||
mod map_config;
|
||||
mod map_err;
|
||||
mod map_init_err;
|
||||
mod pipeline;
|
||||
mod then;
|
||||
mod transform;
|
||||
mod transform_err;
|
||||
|
||||
pub use self::and_then::{AndThen, AndThenNewService};
|
||||
pub use self::apply::{apply_fn, new_apply_fn, Apply, ApplyNewService};
|
||||
pub use self::apply_cfg::{apply_cfg, new_apply_cfg};
|
||||
pub use self::fn_service::{new_service_cfg, new_service_fn, service_fn, ServiceFn};
|
||||
pub use self::fn_transform::transform_fn;
|
||||
pub use self::from_err::{FromErr, FromErrNewService};
|
||||
pub use self::map::{Map, MapNewService};
|
||||
pub use self::map_config::{MapConfig, MappedConfig, UnitConfig};
|
||||
pub use self::map_err::{MapErr, MapErrNewService};
|
||||
pub use self::map_init_err::MapInitErr;
|
||||
pub use self::then::{Then, ThenNewService};
|
||||
pub use self::transform::{apply_transform, IntoTransform, Transform};
|
||||
|
||||
use self::and_then_apply::AndThenTransform;
|
||||
use self::and_then_apply_fn::{AndThenApply, AndThenApplyNewService};
|
||||
pub use self::apply::{apply_fn, apply_fn_factory};
|
||||
pub use self::apply_cfg::{apply_cfg, apply_cfg_factory};
|
||||
pub use self::fn_service::{factory_fn, factory_fn_cfg, service_fn, service_fn2};
|
||||
pub use self::into::{into_factory, into_service, ServiceFactoryMapper, ServiceMapper};
|
||||
pub use self::map_config::{map_config, unit_config, MappedConfig};
|
||||
pub use self::pipeline::{pipeline, pipeline_factory, Pipeline, PipelineFactory};
|
||||
pub use self::transform::{apply, Transform};
|
||||
|
||||
/// An asynchronous function from `Request` to a `Response`.
|
||||
pub trait Service {
|
||||
@ -51,7 +40,7 @@ pub trait Service {
|
||||
type Error;
|
||||
|
||||
/// The future response value.
|
||||
type Future: Future<Item = Self::Response, Error = Self::Error>;
|
||||
type Future: Future<Output = Result<Self::Response, Self::Error>>;
|
||||
|
||||
/// Returns `Ready` when the service is able to process requests.
|
||||
///
|
||||
@ -62,7 +51,7 @@ pub trait Service {
|
||||
/// This is a **best effort** implementation. False positives are permitted.
|
||||
/// It is permitted for the service to return `Ready` from a `poll_ready`
|
||||
/// call and the next invocation of `call` results in an error.
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error>;
|
||||
fn poll_ready(&mut self, ctx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>>;
|
||||
|
||||
/// Process the request and return the response asynchronously.
|
||||
///
|
||||
@ -76,113 +65,16 @@ pub trait Service {
|
||||
fn call(&mut self, req: Self::Request) -> Self::Future;
|
||||
}
|
||||
|
||||
/// An extension trait for `Service`s that provides a variety of convenient
|
||||
/// adapters
|
||||
pub trait ServiceExt: Service {
|
||||
/// Apply function to specified service and use it as a next service in
|
||||
/// chain.
|
||||
fn apply_fn<F, B, B1, Out>(self, service: B1, f: F) -> AndThenApply<Self, B, F, Out>
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(Self::Response, &mut B) -> Out,
|
||||
Out: IntoFuture,
|
||||
Out::Error: Into<Self::Error>,
|
||||
B: Service<Error = Self::Error>,
|
||||
B1: IntoService<B>,
|
||||
{
|
||||
AndThenApply::new(self, service, f)
|
||||
}
|
||||
|
||||
/// Call another service after call to this one has resolved successfully.
|
||||
///
|
||||
/// This function can be used to chain two services together and ensure that
|
||||
/// the second service isn't called until call to the fist service have
|
||||
/// finished. Result of the call to the first service is used as an
|
||||
/// input parameter for the second service's call.
|
||||
///
|
||||
/// Note that this function consumes the receiving service and returns a
|
||||
/// wrapped version of it.
|
||||
fn and_then<F, B>(self, service: F) -> AndThen<Self, B>
|
||||
where
|
||||
Self: Sized,
|
||||
F: IntoService<B>,
|
||||
B: Service<Request = Self::Response, Error = Self::Error>,
|
||||
{
|
||||
AndThen::new(self, service.into_service())
|
||||
}
|
||||
|
||||
/// Map this service's error to any error implementing `From` for
|
||||
/// this service`s `Error`.
|
||||
///
|
||||
/// Note that this function consumes the receiving service and returns a
|
||||
/// wrapped version of it.
|
||||
fn from_err<E>(self) -> FromErr<Self, E>
|
||||
where
|
||||
Self: Sized,
|
||||
E: From<Self::Error>,
|
||||
{
|
||||
FromErr::new(self)
|
||||
}
|
||||
|
||||
/// Chain on a computation for when a call to the service finished,
|
||||
/// passing the result of the call to the next service `B`.
|
||||
///
|
||||
/// Note that this function consumes the receiving service and returns a
|
||||
/// wrapped version of it.
|
||||
fn then<B>(self, service: B) -> Then<Self, B>
|
||||
where
|
||||
Self: Sized,
|
||||
B: Service<Request = Result<Self::Response, Self::Error>, Error = Self::Error>,
|
||||
{
|
||||
Then::new(self, service)
|
||||
}
|
||||
|
||||
/// Map this service's output to a different type, returning a new service
|
||||
/// of the resulting type.
|
||||
///
|
||||
/// This function is similar to the `Option::map` or `Iterator::map` where
|
||||
/// it will change the type of the underlying service.
|
||||
///
|
||||
/// Note that this function consumes the receiving service and returns a
|
||||
/// wrapped version of it, similar to the existing `map` methods in the
|
||||
/// standard library.
|
||||
fn map<F, R>(self, f: F) -> Map<Self, F, R>
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(Self::Response) -> R,
|
||||
{
|
||||
Map::new(self, f)
|
||||
}
|
||||
|
||||
/// Map this service's error to a different error, returning a new service.
|
||||
///
|
||||
/// This function is similar to the `Result::map_err` where it will change
|
||||
/// the error type of the underlying service. This is useful for example to
|
||||
/// ensure that services have the same error type.
|
||||
///
|
||||
/// Note that this function consumes the receiving service and returns a
|
||||
/// wrapped version of it.
|
||||
fn map_err<F, E>(self, f: F) -> MapErr<Self, F, E>
|
||||
where
|
||||
Self: Sized,
|
||||
F: Fn(Self::Error) -> E,
|
||||
{
|
||||
MapErr::new(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> ServiceExt for T where T: Service {}
|
||||
|
||||
/// Creates new `Service` values.
|
||||
///
|
||||
/// Acts as a service factory. This is useful for cases where new `Service`
|
||||
/// values must be produced. One case is a TCP server listener. The listener
|
||||
/// accepts new TCP streams, obtains a new `Service` value using the
|
||||
/// `NewService` trait, and uses that new `Service` value to process inbound
|
||||
/// `ServiceFactory` trait, and uses that new `Service` value to process inbound
|
||||
/// requests on that new TCP stream.
|
||||
///
|
||||
/// `Config` is a service factory configuration type.
|
||||
pub trait NewService {
|
||||
pub trait ServiceFactory {
|
||||
/// Requests handled by the service.
|
||||
type Request;
|
||||
|
||||
@ -206,132 +98,10 @@ pub trait NewService {
|
||||
type InitError;
|
||||
|
||||
/// The future of the `Service` instance.
|
||||
type Future: Future<Item = Self::Service, Error = Self::InitError>;
|
||||
type Future: Future<Output = Result<Self::Service, Self::InitError>>;
|
||||
|
||||
/// Create and return a new service value asynchronously.
|
||||
fn new_service(&self, cfg: &Self::Config) -> Self::Future;
|
||||
|
||||
/// Apply transform service to specified service and use it as a next service in
|
||||
/// chain.
|
||||
fn apply<T, T1, B, B1>(self, transform: T1, service: B1) -> AndThenTransform<T, Self, B>
|
||||
where
|
||||
Self: Sized,
|
||||
T: Transform<B::Service, Request = Self::Response, InitError = Self::InitError>,
|
||||
T::Error: From<Self::Error>,
|
||||
T1: IntoTransform<T, B::Service>,
|
||||
B: NewService<Config = Self::Config, InitError = Self::InitError>,
|
||||
B1: IntoNewService<B>,
|
||||
{
|
||||
AndThenTransform::new(transform.into_transform(), self, service.into_new_service())
|
||||
}
|
||||
|
||||
/// Apply function to specified service and use it as a next service in
|
||||
/// chain.
|
||||
fn apply_fn<B, I, F, Out>(self, service: I, f: F) -> AndThenApplyNewService<Self, B, F, Out>
|
||||
where
|
||||
Self: Sized,
|
||||
B: NewService<Config = Self::Config, Error = Self::Error, InitError = Self::InitError>,
|
||||
I: IntoNewService<B>,
|
||||
F: FnMut(Self::Response, &mut B::Service) -> Out,
|
||||
Out: IntoFuture,
|
||||
Out::Error: Into<Self::Error>,
|
||||
{
|
||||
AndThenApplyNewService::new(self, 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>
|
||||
where
|
||||
Self: Sized,
|
||||
F: IntoNewService<B>,
|
||||
B: NewService<
|
||||
Config = Self::Config,
|
||||
Request = Self::Response,
|
||||
Error = Self::Error,
|
||||
InitError = Self::InitError,
|
||||
>,
|
||||
{
|
||||
AndThenNewService::new(self, new_service)
|
||||
}
|
||||
|
||||
/// `NewService` that create service to map this service's error
|
||||
/// and new service's init error to any error
|
||||
/// implementing `From` for this service`s `Error`.
|
||||
///
|
||||
/// Note that this function consumes the receiving new service and returns a
|
||||
/// wrapped version of it.
|
||||
fn from_err<E>(self) -> FromErrNewService<Self, E>
|
||||
where
|
||||
Self: Sized,
|
||||
E: From<Self::Error>,
|
||||
{
|
||||
FromErrNewService::new(self)
|
||||
}
|
||||
|
||||
/// Create `NewService` to chain on a computation for when a call to the
|
||||
/// service finished, passing the result of the call to the next
|
||||
/// service `B`.
|
||||
///
|
||||
/// Note that this function consumes the receiving future and returns a
|
||||
/// wrapped version of it.
|
||||
fn then<F, B>(self, new_service: F) -> ThenNewService<Self, B>
|
||||
where
|
||||
Self: Sized,
|
||||
F: IntoNewService<B>,
|
||||
B: NewService<
|
||||
Config = Self::Config,
|
||||
Request = Result<Self::Response, Self::Error>,
|
||||
Error = Self::Error,
|
||||
InitError = Self::InitError,
|
||||
>,
|
||||
{
|
||||
ThenNewService::new(self, new_service)
|
||||
}
|
||||
|
||||
/// Map this service's output to a different type, returning a new service
|
||||
/// of the resulting type.
|
||||
fn map<F, R>(self, f: F) -> MapNewService<Self, F, R>
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(Self::Response) -> R,
|
||||
{
|
||||
MapNewService::new(self, f)
|
||||
}
|
||||
|
||||
/// Map this service's error to a different error, returning a new service.
|
||||
fn map_err<F, E>(self, f: F) -> MapErrNewService<Self, F, E>
|
||||
where
|
||||
Self: Sized,
|
||||
F: Fn(Self::Error) -> E + Clone,
|
||||
{
|
||||
MapErrNewService::new(self, f)
|
||||
}
|
||||
|
||||
/// Map this factory's init error to a different error, returning a new service.
|
||||
fn map_init_err<F, E>(self, f: F) -> MapInitErr<Self, F, E>
|
||||
where
|
||||
Self: Sized,
|
||||
F: Fn(Self::InitError) -> E,
|
||||
{
|
||||
MapInitErr::new(self, f)
|
||||
}
|
||||
|
||||
/// Map config to a different error, returning a new service.
|
||||
fn map_config<F, C>(self, f: F) -> MapConfig<Self, F, C>
|
||||
where
|
||||
Self: Sized,
|
||||
F: Fn(&C) -> MappedConfig<Self::Config>,
|
||||
{
|
||||
MapConfig::new(self, f)
|
||||
}
|
||||
|
||||
/// Replace config with unit
|
||||
fn unit_config<C>(self) -> UnitConfig<Self, C>
|
||||
where
|
||||
Self: NewService<Config = ()> + Sized,
|
||||
{
|
||||
UnitConfig::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S> Service for &'a mut S
|
||||
@ -343,8 +113,8 @@ where
|
||||
type Error = S::Error;
|
||||
type Future = S::Future;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), S::Error> {
|
||||
(**self).poll_ready()
|
||||
fn poll_ready(&mut self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
(**self).poll_ready(ctx)
|
||||
}
|
||||
|
||||
fn call(&mut self, request: Self::Request) -> S::Future {
|
||||
@ -361,8 +131,8 @@ where
|
||||
type Error = S::Error;
|
||||
type Future = S::Future;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), S::Error> {
|
||||
(**self).poll_ready()
|
||||
fn poll_ready(&mut self, ctx: &mut Context<'_>) -> Poll<Result<(), S::Error>> {
|
||||
(**self).poll_ready(ctx)
|
||||
}
|
||||
|
||||
fn call(&mut self, request: Self::Request) -> S::Future {
|
||||
@ -379,18 +149,18 @@ where
|
||||
type Error = S::Error;
|
||||
type Future = S::Future;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), S::Error> {
|
||||
self.borrow_mut().poll_ready()
|
||||
fn poll_ready(&mut self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.borrow_mut().poll_ready(ctx)
|
||||
}
|
||||
|
||||
fn call(&mut self, request: Self::Request) -> S::Future {
|
||||
self.borrow_mut().call(request)
|
||||
(&mut (**self).borrow_mut()).call(request)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> NewService for Rc<S>
|
||||
impl<S> ServiceFactory for Rc<S>
|
||||
where
|
||||
S: NewService,
|
||||
S: ServiceFactory,
|
||||
{
|
||||
type Request = S::Request;
|
||||
type Response = S::Response;
|
||||
@ -405,9 +175,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> NewService for Arc<S>
|
||||
impl<S> ServiceFactory for Arc<S>
|
||||
where
|
||||
S: NewService,
|
||||
S: ServiceFactory,
|
||||
{
|
||||
type Request = S::Request;
|
||||
type Response = S::Response;
|
||||
@ -431,13 +201,13 @@ where
|
||||
fn into_service(self) -> T;
|
||||
}
|
||||
|
||||
/// Trait for types that can be converted to a `NewService`
|
||||
pub trait IntoNewService<T>
|
||||
/// Trait for types that can be converted to a `ServiceFactory`
|
||||
pub trait IntoServiceFactory<T>
|
||||
where
|
||||
T: NewService,
|
||||
T: ServiceFactory,
|
||||
{
|
||||
/// Convert to an `NewService`
|
||||
fn into_new_service(self) -> T;
|
||||
/// Convert `Self` an `ServiceFactory`
|
||||
fn into_factory(self) -> T;
|
||||
}
|
||||
|
||||
impl<T> IntoService<T> for T
|
||||
@ -449,11 +219,11 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoNewService<T> for T
|
||||
impl<T> IntoServiceFactory<T> for T
|
||||
where
|
||||
T: NewService,
|
||||
T: ServiceFactory,
|
||||
{
|
||||
fn into_new_service(self) -> T {
|
||||
fn into_factory(self) -> T {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,16 @@
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use futures::{Async, Future, Poll};
|
||||
use pin_project::pin_project;
|
||||
|
||||
use super::{NewService, Service};
|
||||
use super::{Service, ServiceFactory};
|
||||
|
||||
/// Service for the `map` combinator, changing the type of a service's response.
|
||||
///
|
||||
/// This is created by the `ServiceExt::map` method.
|
||||
pub struct Map<A, F, Response> {
|
||||
pub(crate) struct Map<A, F, Response> {
|
||||
service: A,
|
||||
f: F,
|
||||
_t: PhantomData<Response>,
|
||||
@ -52,8 +55,8 @@ where
|
||||
type Error = A::Error;
|
||||
type Future = MapFuture<A, F, Response>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
self.service.poll_ready()
|
||||
fn poll_ready(&mut self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.service.poll_ready(ctx)
|
||||
}
|
||||
|
||||
fn call(&mut self, req: A::Request) -> Self::Future {
|
||||
@ -61,12 +64,14 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MapFuture<A, F, Response>
|
||||
#[pin_project]
|
||||
pub(crate) struct MapFuture<A, F, Response>
|
||||
where
|
||||
A: Service,
|
||||
F: FnMut(A::Response) -> Response,
|
||||
{
|
||||
f: F,
|
||||
#[pin]
|
||||
fut: A::Future,
|
||||
}
|
||||
|
||||
@ -85,19 +90,20 @@ where
|
||||
A: Service,
|
||||
F: FnMut(A::Response) -> Response,
|
||||
{
|
||||
type Item = Response;
|
||||
type Error = A::Error;
|
||||
type Output = Result<Response, A::Error>;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
match self.fut.poll()? {
|
||||
Async::Ready(resp) => Ok(Async::Ready((self.f)(resp))),
|
||||
Async::NotReady => Ok(Async::NotReady),
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
match this.fut.poll(cx) {
|
||||
Poll::Ready(Ok(resp)) => Poll::Ready(Ok((this.f)(resp))),
|
||||
Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `MapNewService` new service combinator
|
||||
pub struct MapNewService<A, F, Res> {
|
||||
pub(crate) struct MapNewService<A, F, Res> {
|
||||
a: A,
|
||||
f: F,
|
||||
r: PhantomData<Res>,
|
||||
@ -107,7 +113,7 @@ impl<A, F, Res> MapNewService<A, F, Res> {
|
||||
/// Create new `Map` new service instance
|
||||
pub fn new(a: A, f: F) -> Self
|
||||
where
|
||||
A: NewService,
|
||||
A: ServiceFactory,
|
||||
F: FnMut(A::Response) -> Res,
|
||||
{
|
||||
Self {
|
||||
@ -132,9 +138,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, F, Res> NewService for MapNewService<A, F, Res>
|
||||
impl<A, F, Res> ServiceFactory for MapNewService<A, F, Res>
|
||||
where
|
||||
A: NewService,
|
||||
A: ServiceFactory,
|
||||
F: FnMut(A::Response) -> Res + Clone,
|
||||
{
|
||||
type Request = A::Request;
|
||||
@ -151,18 +157,20 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MapNewServiceFuture<A, F, Res>
|
||||
#[pin_project]
|
||||
pub(crate) struct MapNewServiceFuture<A, F, Res>
|
||||
where
|
||||
A: NewService,
|
||||
A: ServiceFactory,
|
||||
F: FnMut(A::Response) -> Res,
|
||||
{
|
||||
#[pin]
|
||||
fut: A::Future,
|
||||
f: Option<F>,
|
||||
}
|
||||
|
||||
impl<A, F, Res> MapNewServiceFuture<A, F, Res>
|
||||
where
|
||||
A: NewService,
|
||||
A: ServiceFactory,
|
||||
F: FnMut(A::Response) -> Res,
|
||||
{
|
||||
fn new(fut: A::Future, f: F) -> Self {
|
||||
@ -172,37 +180,38 @@ where
|
||||
|
||||
impl<A, F, Res> Future for MapNewServiceFuture<A, F, Res>
|
||||
where
|
||||
A: NewService,
|
||||
A: ServiceFactory,
|
||||
F: FnMut(A::Response) -> Res,
|
||||
{
|
||||
type Item = Map<A::Service, F, Res>;
|
||||
type Error = A::InitError;
|
||||
type Output = Result<Map<A::Service, F, Res>, A::InitError>;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
if let Async::Ready(service) = self.fut.poll()? {
|
||||
Ok(Async::Ready(Map::new(service, self.f.take().unwrap())))
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
if let Poll::Ready(svc) = this.fut.poll(cx)? {
|
||||
Poll::Ready(Ok(Map::new(svc, this.f.take().unwrap())))
|
||||
} else {
|
||||
Ok(Async::NotReady)
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use futures::future::{ok, FutureResult};
|
||||
use futures::future::{lazy, ok, Ready};
|
||||
|
||||
use super::*;
|
||||
use crate::{IntoNewService, Service, ServiceExt};
|
||||
use crate::{into_factory, into_service, Service};
|
||||
|
||||
struct Srv;
|
||||
|
||||
impl Service for Srv {
|
||||
type Request = ();
|
||||
type Response = ();
|
||||
type Error = ();
|
||||
type Future = FutureResult<(), ()>;
|
||||
type Future = Ready<Result<(), ()>>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
Ok(Async::Ready(()))
|
||||
fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, _: ()) -> Self::Future {
|
||||
@ -210,32 +219,27 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_poll_ready() {
|
||||
let mut srv = Srv.map(|_| "ok");
|
||||
let res = srv.poll_ready();
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), Async::Ready(()));
|
||||
#[tokio::test]
|
||||
async fn test_poll_ready() {
|
||||
let mut srv = into_service(Srv).map(|_| "ok");
|
||||
let res = lazy(|cx| srv.poll_ready(cx)).await;
|
||||
assert_eq!(res, Poll::Ready(Ok(())));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_call() {
|
||||
let mut srv = Srv.map(|_| "ok");
|
||||
let res = srv.call(()).poll();
|
||||
#[tokio::test]
|
||||
async fn test_call() {
|
||||
let mut srv = into_service(Srv).map(|_| "ok");
|
||||
let res = srv.call(()).await;
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), Async::Ready("ok"));
|
||||
assert_eq!(res.unwrap(), "ok");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_service() {
|
||||
let blank = || Ok::<_, ()>(Srv);
|
||||
let new_srv = blank.into_new_service().map(|_| "ok");
|
||||
if let Async::Ready(mut srv) = new_srv.new_service(&()).poll().unwrap() {
|
||||
let res = srv.call(()).poll();
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), Async::Ready("ok"));
|
||||
} else {
|
||||
panic!()
|
||||
}
|
||||
#[tokio::test]
|
||||
async fn test_new_service() {
|
||||
let new_srv = into_factory(|| ok::<_, ()>(Srv)).map(|_| "ok");
|
||||
let mut srv = new_srv.new_service(&()).await.unwrap();
|
||||
let res = srv.call(()).await;
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), ("ok"));
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,48 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use super::NewService;
|
||||
use super::ServiceFactory;
|
||||
|
||||
pub enum MappedConfig<'a, T> {
|
||||
Ref(&'a T),
|
||||
Owned(T),
|
||||
}
|
||||
|
||||
/// Adapt external config to a config for provided new service
|
||||
pub fn map_config<T, F, C>(
|
||||
factory: T,
|
||||
f: F,
|
||||
) -> impl ServiceFactory<
|
||||
Config = C,
|
||||
Request = T::Request,
|
||||
Response = T::Response,
|
||||
Error = T::Error,
|
||||
InitError = T::InitError,
|
||||
>
|
||||
where
|
||||
T: ServiceFactory,
|
||||
F: Fn(&C) -> MappedConfig<T::Config>,
|
||||
{
|
||||
MapConfig::new(factory, f)
|
||||
}
|
||||
|
||||
/// Replace config with unit
|
||||
pub fn unit_config<T, C>(
|
||||
new_service: T,
|
||||
) -> impl ServiceFactory<
|
||||
Config = C,
|
||||
Request = T::Request,
|
||||
Response = T::Response,
|
||||
Error = T::Error,
|
||||
InitError = T::InitError,
|
||||
>
|
||||
where
|
||||
T: ServiceFactory<Config = ()>,
|
||||
{
|
||||
UnitConfig::new(new_service)
|
||||
}
|
||||
|
||||
/// `MapInitErr` service combinator
|
||||
pub struct MapConfig<A, F, C> {
|
||||
pub(crate) struct MapConfig<A, F, C> {
|
||||
a: A,
|
||||
f: F,
|
||||
e: PhantomData<C>,
|
||||
@ -18,7 +52,7 @@ impl<A, F, C> MapConfig<A, F, C> {
|
||||
/// Create new `MapConfig` combinator
|
||||
pub fn new(a: A, f: F) -> Self
|
||||
where
|
||||
A: NewService,
|
||||
A: ServiceFactory,
|
||||
F: Fn(&C) -> MappedConfig<A::Config>,
|
||||
{
|
||||
Self {
|
||||
@ -43,9 +77,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, F, C> NewService for MapConfig<A, F, C>
|
||||
impl<A, F, C> ServiceFactory for MapConfig<A, F, C>
|
||||
where
|
||||
A: NewService,
|
||||
A: ServiceFactory,
|
||||
F: Fn(&C) -> MappedConfig<A::Config>,
|
||||
{
|
||||
type Request = A::Request;
|
||||
@ -66,17 +100,17 @@ where
|
||||
}
|
||||
|
||||
/// `MapInitErr` service combinator
|
||||
pub struct UnitConfig<A, C> {
|
||||
pub(crate) struct UnitConfig<A, C> {
|
||||
a: A,
|
||||
e: PhantomData<C>,
|
||||
}
|
||||
|
||||
impl<A, C> UnitConfig<A, C> {
|
||||
impl<A, C> UnitConfig<A, C>
|
||||
where
|
||||
A: ServiceFactory<Config = ()>,
|
||||
{
|
||||
/// Create new `UnitConfig` combinator
|
||||
pub fn new(a: A) -> Self
|
||||
where
|
||||
A: NewService<Config = ()>,
|
||||
{
|
||||
pub(crate) fn new(a: A) -> Self {
|
||||
Self { a, e: PhantomData }
|
||||
}
|
||||
}
|
||||
@ -93,9 +127,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, C> NewService for UnitConfig<A, C>
|
||||
impl<A, C> ServiceFactory for UnitConfig<A, C>
|
||||
where
|
||||
A: NewService<Config = ()>,
|
||||
A: ServiceFactory<Config = ()>,
|
||||
{
|
||||
type Request = A::Request;
|
||||
type Response = A::Response;
|
||||
|
@ -1,14 +1,17 @@
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use futures::{Async, Future, Poll};
|
||||
use pin_project::pin_project;
|
||||
|
||||
use super::{NewService, Service};
|
||||
use super::{Service, ServiceFactory};
|
||||
|
||||
/// Service for the `map_err` combinator, changing the type of a service's
|
||||
/// error.
|
||||
///
|
||||
/// This is created by the `ServiceExt::map_err` method.
|
||||
pub struct MapErr<A, F, E> {
|
||||
pub(crate) struct MapErr<A, F, E> {
|
||||
service: A,
|
||||
f: F,
|
||||
_t: PhantomData<E>,
|
||||
@ -53,8 +56,8 @@ where
|
||||
type Error = E;
|
||||
type Future = MapErrFuture<A, F, E>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
self.service.poll_ready().map_err(&self.f)
|
||||
fn poll_ready(&mut self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.service.poll_ready(ctx).map_err(&self.f)
|
||||
}
|
||||
|
||||
fn call(&mut self, req: A::Request) -> Self::Future {
|
||||
@ -62,12 +65,14 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MapErrFuture<A, F, E>
|
||||
#[pin_project]
|
||||
pub(crate) struct MapErrFuture<A, F, E>
|
||||
where
|
||||
A: Service,
|
||||
F: Fn(A::Error) -> E,
|
||||
{
|
||||
f: F,
|
||||
#[pin]
|
||||
fut: A::Future,
|
||||
}
|
||||
|
||||
@ -86,21 +91,21 @@ where
|
||||
A: Service,
|
||||
F: Fn(A::Error) -> E,
|
||||
{
|
||||
type Item = A::Response;
|
||||
type Error = E;
|
||||
type Output = Result<A::Response, E>;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
self.fut.poll().map_err(&self.f)
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
this.fut.poll(cx).map_err(this.f)
|
||||
}
|
||||
}
|
||||
|
||||
/// NewService for the `map_err` combinator, changing the type of a new
|
||||
/// Factory for the `map_err` combinator, changing the type of a new
|
||||
/// service's error.
|
||||
///
|
||||
/// This is created by the `NewServiceExt::map_err` method.
|
||||
pub struct MapErrNewService<A, F, E>
|
||||
pub(crate) struct MapErrNewService<A, F, E>
|
||||
where
|
||||
A: NewService,
|
||||
A: ServiceFactory,
|
||||
F: Fn(A::Error) -> E + Clone,
|
||||
{
|
||||
a: A,
|
||||
@ -110,11 +115,11 @@ where
|
||||
|
||||
impl<A, F, E> MapErrNewService<A, F, E>
|
||||
where
|
||||
A: NewService,
|
||||
A: ServiceFactory,
|
||||
F: Fn(A::Error) -> E + Clone,
|
||||
{
|
||||
/// Create new `MapErr` new service instance
|
||||
pub fn new(a: A, f: F) -> Self {
|
||||
pub(crate) fn new(a: A, f: F) -> Self {
|
||||
Self {
|
||||
a,
|
||||
f,
|
||||
@ -125,7 +130,7 @@ where
|
||||
|
||||
impl<A, F, E> Clone for MapErrNewService<A, F, E>
|
||||
where
|
||||
A: NewService + Clone,
|
||||
A: ServiceFactory + Clone,
|
||||
F: Fn(A::Error) -> E + Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
@ -137,9 +142,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, F, E> NewService for MapErrNewService<A, F, E>
|
||||
impl<A, F, E> ServiceFactory for MapErrNewService<A, F, E>
|
||||
where
|
||||
A: NewService,
|
||||
A: ServiceFactory,
|
||||
F: Fn(A::Error) -> E + Clone,
|
||||
{
|
||||
type Request = A::Request;
|
||||
@ -156,18 +161,20 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MapErrNewServiceFuture<A, F, E>
|
||||
#[pin_project]
|
||||
pub(crate) struct MapErrNewServiceFuture<A, F, E>
|
||||
where
|
||||
A: NewService,
|
||||
A: ServiceFactory,
|
||||
F: Fn(A::Error) -> E,
|
||||
{
|
||||
#[pin]
|
||||
fut: A::Future,
|
||||
f: F,
|
||||
}
|
||||
|
||||
impl<A, F, E> MapErrNewServiceFuture<A, F, E>
|
||||
where
|
||||
A: NewService,
|
||||
A: ServiceFactory,
|
||||
F: Fn(A::Error) -> E,
|
||||
{
|
||||
fn new(fut: A::Future, f: F) -> Self {
|
||||
@ -177,27 +184,27 @@ where
|
||||
|
||||
impl<A, F, E> Future for MapErrNewServiceFuture<A, F, E>
|
||||
where
|
||||
A: NewService,
|
||||
A: ServiceFactory,
|
||||
F: Fn(A::Error) -> E + Clone,
|
||||
{
|
||||
type Item = MapErr<A::Service, F, E>;
|
||||
type Error = A::InitError;
|
||||
type Output = Result<MapErr<A::Service, F, E>, A::InitError>;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
if let Async::Ready(service) = self.fut.poll()? {
|
||||
Ok(Async::Ready(MapErr::new(service, self.f.clone())))
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
if let Poll::Ready(svc) = this.fut.poll(cx)? {
|
||||
Poll::Ready(Ok(MapErr::new(svc, this.f.clone())))
|
||||
} else {
|
||||
Ok(Async::NotReady)
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use futures::future::{err, FutureResult};
|
||||
use futures::future::{err, lazy, ok, Ready};
|
||||
|
||||
use super::*;
|
||||
use crate::{IntoNewService, NewService, Service, ServiceExt};
|
||||
use crate::{into_factory, into_service, Service};
|
||||
|
||||
struct Srv;
|
||||
|
||||
@ -205,10 +212,10 @@ mod tests {
|
||||
type Request = ();
|
||||
type Response = ();
|
||||
type Error = ();
|
||||
type Future = FutureResult<(), ()>;
|
||||
type Future = Ready<Result<(), ()>>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
Err(())
|
||||
fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
|
||||
Poll::Ready(Err(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, _: ()) -> Self::Future {
|
||||
@ -216,32 +223,27 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_poll_ready() {
|
||||
let mut srv = Srv.map_err(|_| "error");
|
||||
let res = srv.poll_ready();
|
||||
#[tokio::test]
|
||||
async fn test_poll_ready() {
|
||||
let mut srv = into_service(Srv).map_err(|_| "error");
|
||||
let res = lazy(|cx| srv.poll_ready(cx)).await;
|
||||
assert_eq!(res, Poll::Ready(Err("error")));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_call() {
|
||||
let mut srv = into_service(Srv).map_err(|_| "error");
|
||||
let res = srv.call(()).await;
|
||||
assert!(res.is_err());
|
||||
assert_eq!(res.err().unwrap(), "error");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_call() {
|
||||
let mut srv = Srv.map_err(|_| "error");
|
||||
let res = srv.call(()).poll();
|
||||
#[tokio::test]
|
||||
async fn test_new_service() {
|
||||
let new_srv = into_factory(|| ok::<_, ()>(Srv)).map_err(|_| "error");
|
||||
let mut srv = new_srv.new_service(&()).await.unwrap();
|
||||
let res = srv.call(()).await;
|
||||
assert!(res.is_err());
|
||||
assert_eq!(res.err().unwrap(), "error");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_service() {
|
||||
let blank = || Ok::<_, ()>(Srv);
|
||||
let new_srv = blank.into_new_service().map_err(|_| "error");
|
||||
if let Async::Ready(mut srv) = new_srv.new_service(&()).poll().unwrap() {
|
||||
let res = srv.call(()).poll();
|
||||
assert!(res.is_err());
|
||||
assert_eq!(res.err().unwrap(), "error");
|
||||
} else {
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,26 @@
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use futures::{Future, Poll};
|
||||
use pin_project::pin_project;
|
||||
|
||||
use super::NewService;
|
||||
use super::ServiceFactory;
|
||||
|
||||
/// `MapInitErr` service combinator
|
||||
pub struct MapInitErr<A, F, E> {
|
||||
pub(crate) struct MapInitErr<A, F, E> {
|
||||
a: A,
|
||||
f: F,
|
||||
e: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<A, F, E> MapInitErr<A, F, E> {
|
||||
impl<A, F, E> MapInitErr<A, F, E>
|
||||
where
|
||||
A: ServiceFactory,
|
||||
F: Fn(A::InitError) -> E,
|
||||
{
|
||||
/// Create new `MapInitErr` combinator
|
||||
pub fn new(a: A, f: F) -> Self
|
||||
where
|
||||
A: NewService,
|
||||
F: Fn(A::InitError) -> E,
|
||||
{
|
||||
pub(crate) fn new(a: A, f: F) -> Self {
|
||||
Self {
|
||||
a,
|
||||
f,
|
||||
@ -40,9 +43,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, F, E> NewService for MapInitErr<A, F, E>
|
||||
impl<A, F, E> ServiceFactory for MapInitErr<A, F, E>
|
||||
where
|
||||
A: NewService,
|
||||
A: ServiceFactory,
|
||||
F: Fn(A::InitError) -> E + Clone,
|
||||
{
|
||||
type Request = A::Request;
|
||||
@ -58,19 +61,20 @@ where
|
||||
MapInitErrFuture::new(self.a.new_service(cfg), self.f.clone())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MapInitErrFuture<A, F, E>
|
||||
#[pin_project]
|
||||
pub(crate) struct MapInitErrFuture<A, F, E>
|
||||
where
|
||||
A: NewService,
|
||||
A: ServiceFactory,
|
||||
F: Fn(A::InitError) -> E,
|
||||
{
|
||||
f: F,
|
||||
#[pin]
|
||||
fut: A::Future,
|
||||
}
|
||||
|
||||
impl<A, F, E> MapInitErrFuture<A, F, E>
|
||||
where
|
||||
A: NewService,
|
||||
A: ServiceFactory,
|
||||
F: Fn(A::InitError) -> E,
|
||||
{
|
||||
fn new(fut: A::Future, f: F) -> Self {
|
||||
@ -80,13 +84,13 @@ where
|
||||
|
||||
impl<A, F, E> Future for MapInitErrFuture<A, F, E>
|
||||
where
|
||||
A: NewService,
|
||||
A: ServiceFactory,
|
||||
F: Fn(A::InitError) -> E,
|
||||
{
|
||||
type Item = A::Service;
|
||||
type Error = E;
|
||||
type Output = Result<A::Service, E>;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
self.fut.poll().map_err(&self.f)
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
this.fut.poll(cx).map_err(this.f)
|
||||
}
|
||||
}
|
||||
|
196
actix-service/src/pipeline.rs
Normal file
196
actix-service/src/pipeline.rs
Normal file
@ -0,0 +1,196 @@
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use crate::and_then::{AndThen, AndThenNewService};
|
||||
use crate::then::{Then, ThenNewService};
|
||||
use crate::{IntoService, IntoServiceFactory, Service, ServiceFactory};
|
||||
|
||||
pub fn pipeline<F, T>(service: F) -> Pipeline<T>
|
||||
where
|
||||
F: IntoService<T>,
|
||||
T: Service,
|
||||
{
|
||||
Pipeline {
|
||||
service: service.into_service(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pipeline_factory<T, F>(factory: F) -> PipelineFactory<T>
|
||||
where
|
||||
T: ServiceFactory,
|
||||
F: IntoServiceFactory<T>,
|
||||
{
|
||||
PipelineFactory {
|
||||
factory: factory.into_factory(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Pipeline service
|
||||
pub struct Pipeline<T> {
|
||||
service: T,
|
||||
}
|
||||
|
||||
impl<T: Service> Pipeline<T> {
|
||||
/// Call another service after call to this one has resolved successfully.
|
||||
///
|
||||
/// This function can be used to chain two services together and ensure that
|
||||
/// the second service isn't called until call to the fist service have
|
||||
/// finished. Result of the call to the first service is used as an
|
||||
/// input parameter for the second service's call.
|
||||
///
|
||||
/// Note that this function consumes the receiving service and returns a
|
||||
/// wrapped version of it.
|
||||
pub fn and_then<F, U>(
|
||||
self,
|
||||
service: F,
|
||||
) -> Pipeline<impl Service<Request = T::Request, Response = U::Response, Error = T::Error>>
|
||||
where
|
||||
Self: Sized,
|
||||
F: IntoService<U>,
|
||||
U: Service<Request = T::Response, Error = T::Error>,
|
||||
{
|
||||
Pipeline {
|
||||
service: AndThen::new(self.service, service.into_service()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Chain on a computation for when a call to the service finished,
|
||||
/// passing the result of the call to the next service `U`.
|
||||
///
|
||||
/// Note that this function consumes the receiving pipeline and returns a
|
||||
/// wrapped version of it.
|
||||
pub fn then<F, U>(
|
||||
self,
|
||||
service: F,
|
||||
) -> Pipeline<impl Service<Request = T::Request, Response = U::Response, Error = T::Error>>
|
||||
where
|
||||
Self: Sized,
|
||||
F: IntoService<U>,
|
||||
U: Service<Request = Result<T::Response, T::Error>, Error = T::Error>,
|
||||
{
|
||||
Pipeline {
|
||||
service: Then::new(self.service, service.into_service()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for Pipeline<T>
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Pipeline {
|
||||
service: self.service.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Service> Service for Pipeline<T> {
|
||||
type Request = T::Request;
|
||||
type Response = T::Response;
|
||||
type Error = T::Error;
|
||||
type Future = T::Future;
|
||||
|
||||
#[inline]
|
||||
fn poll_ready(&mut self, ctx: &mut Context<'_>) -> Poll<Result<(), T::Error>> {
|
||||
self.service.poll_ready(ctx)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn call(&mut self, req: T::Request) -> Self::Future {
|
||||
self.service.call(req)
|
||||
}
|
||||
}
|
||||
|
||||
/// Pipeline constructor
|
||||
pub struct PipelineFactory<T> {
|
||||
factory: T,
|
||||
}
|
||||
|
||||
impl<T: ServiceFactory> PipelineFactory<T> {
|
||||
/// Call another service after call to this one has resolved successfully.
|
||||
pub fn and_then<F, U>(
|
||||
self,
|
||||
factory: F,
|
||||
) -> PipelineFactory<
|
||||
impl ServiceFactory<
|
||||
Config = T::Config,
|
||||
Request = T::Request,
|
||||
Response = U::Response,
|
||||
Error = T::Error,
|
||||
InitError = T::InitError,
|
||||
>,
|
||||
>
|
||||
where
|
||||
Self: Sized,
|
||||
F: IntoServiceFactory<U>,
|
||||
U: ServiceFactory<
|
||||
Config = T::Config,
|
||||
Request = T::Response,
|
||||
Error = T::Error,
|
||||
InitError = T::InitError,
|
||||
>,
|
||||
{
|
||||
PipelineFactory {
|
||||
factory: AndThenNewService::new(self.factory, factory.into_factory()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create `NewService` to chain on a computation for when a call to the
|
||||
/// service finished, passing the result of the call to the next
|
||||
/// service `U`.
|
||||
///
|
||||
/// Note that this function consumes the receiving pipeline and returns a
|
||||
/// wrapped version of it.
|
||||
pub fn then<F, U>(
|
||||
self,
|
||||
factory: F,
|
||||
) -> PipelineFactory<
|
||||
impl ServiceFactory<
|
||||
Config = T::Config,
|
||||
Request = T::Request,
|
||||
Response = U::Response,
|
||||
Error = T::Error,
|
||||
InitError = T::InitError,
|
||||
>,
|
||||
>
|
||||
where
|
||||
Self: Sized,
|
||||
F: IntoServiceFactory<U>,
|
||||
U: ServiceFactory<
|
||||
Config = T::Config,
|
||||
Request = Result<T::Response, T::Error>,
|
||||
Error = T::Error,
|
||||
InitError = T::InitError,
|
||||
>,
|
||||
{
|
||||
PipelineFactory {
|
||||
factory: ThenNewService::new(self.factory, factory.into_factory()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for PipelineFactory<T>
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
PipelineFactory {
|
||||
factory: self.factory.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ServiceFactory> ServiceFactory for PipelineFactory<T> {
|
||||
type Config = T::Config;
|
||||
type Request = T::Request;
|
||||
type Response = T::Response;
|
||||
type Error = T::Error;
|
||||
type Service = T::Service;
|
||||
type InitError = T::InitError;
|
||||
type Future = T::Future;
|
||||
|
||||
#[inline]
|
||||
fn new_service(&self, cfg: &T::Config) -> Self::Future {
|
||||
self.factory.new_service(cfg)
|
||||
}
|
||||
}
|
@ -1,13 +1,17 @@
|
||||
use futures::{Async, Future, Poll};
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use super::{IntoNewService, NewService, Service};
|
||||
use pin_project::pin_project;
|
||||
|
||||
use super::{Service, ServiceFactory};
|
||||
use crate::cell::Cell;
|
||||
|
||||
/// Service for the `then` combinator, chaining a computation onto the end of
|
||||
/// another service.
|
||||
///
|
||||
/// This is created by the `ServiceExt::then` method.
|
||||
pub struct Then<A, B> {
|
||||
pub(crate) struct Then<A, B> {
|
||||
a: A,
|
||||
b: Cell<B>,
|
||||
}
|
||||
@ -45,12 +49,12 @@ where
|
||||
type Error = B::Error;
|
||||
type Future = ThenFuture<A, B>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
let not_ready = self.a.poll_ready()?.is_not_ready();
|
||||
if self.b.get_mut().poll_ready()?.is_not_ready() || not_ready {
|
||||
Ok(Async::NotReady)
|
||||
fn poll_ready(&mut self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
let not_ready = !self.a.poll_ready(ctx)?.is_ready();
|
||||
if !self.b.get_mut().poll_ready(ctx)?.is_ready() || not_ready {
|
||||
Poll::Pending
|
||||
} else {
|
||||
Ok(Async::Ready(()))
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,13 +63,16 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ThenFuture<A, B>
|
||||
#[pin_project]
|
||||
pub(crate) struct ThenFuture<A, B>
|
||||
where
|
||||
A: Service,
|
||||
B: Service<Request = Result<A::Response, A::Error>>,
|
||||
{
|
||||
b: Cell<B>,
|
||||
#[pin]
|
||||
fut_b: Option<B::Future>,
|
||||
#[pin]
|
||||
fut_a: Option<A::Future>,
|
||||
}
|
||||
|
||||
@ -88,60 +95,63 @@ where
|
||||
A: Service,
|
||||
B: Service<Request = Result<A::Response, A::Error>>,
|
||||
{
|
||||
type Item = B::Response;
|
||||
type Error = B::Error;
|
||||
type Output = Result<B::Response, B::Error>;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
if let Some(ref mut fut) = self.fut_b {
|
||||
return fut.poll();
|
||||
}
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let mut this = self.project();
|
||||
|
||||
match self.fut_a.as_mut().expect("bug in actix-service").poll() {
|
||||
Ok(Async::Ready(resp)) => {
|
||||
let _ = self.fut_a.take();
|
||||
self.fut_b = Some(self.b.get_mut().call(Ok(resp)));
|
||||
self.poll()
|
||||
loop {
|
||||
let mut fut_a = this.fut_a.as_mut();
|
||||
let mut fut_b = this.fut_b.as_mut();
|
||||
|
||||
if let Some(fut) = fut_b.as_mut().as_pin_mut() {
|
||||
return fut.poll(cx);
|
||||
}
|
||||
Err(err) => {
|
||||
let _ = self.fut_a.take();
|
||||
self.fut_b = Some(self.b.get_mut().call(Err(err)));
|
||||
self.poll()
|
||||
|
||||
match fut_a
|
||||
.as_mut()
|
||||
.as_pin_mut()
|
||||
.expect("Bug in actix-service")
|
||||
.poll(cx)
|
||||
{
|
||||
Poll::Ready(r) => {
|
||||
fut_a.set(None);
|
||||
let new_fut = this.b.get_mut().call(r);
|
||||
fut_b.set(Some(new_fut));
|
||||
}
|
||||
|
||||
Poll::Pending => return Poll::Pending,
|
||||
}
|
||||
Ok(Async::NotReady) => Ok(Async::NotReady),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `ThenNewService` new service combinator
|
||||
pub struct ThenNewService<A, B> {
|
||||
/// `.then()` service factory combinator
|
||||
pub(crate) struct ThenNewService<A, B> {
|
||||
a: A,
|
||||
b: B,
|
||||
}
|
||||
|
||||
impl<A, B> ThenNewService<A, B> {
|
||||
impl<A, B> ThenNewService<A, B>
|
||||
where
|
||||
A: ServiceFactory,
|
||||
B: ServiceFactory<
|
||||
Config = A::Config,
|
||||
Request = Result<A::Response, A::Error>,
|
||||
Error = A::Error,
|
||||
InitError = A::InitError,
|
||||
>,
|
||||
{
|
||||
/// Create new `AndThen` combinator
|
||||
pub fn new<F>(a: A, f: F) -> Self
|
||||
where
|
||||
A: NewService,
|
||||
B: NewService<
|
||||
Config = A::Config,
|
||||
Request = Result<A::Response, A::Error>,
|
||||
Error = A::Error,
|
||||
InitError = A::InitError,
|
||||
>,
|
||||
F: IntoNewService<B>,
|
||||
{
|
||||
Self {
|
||||
a,
|
||||
b: f.into_new_service(),
|
||||
}
|
||||
pub fn new(a: A, b: B) -> Self {
|
||||
Self { a, b }
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B> NewService for ThenNewService<A, B>
|
||||
impl<A, B> ServiceFactory for ThenNewService<A, B>
|
||||
where
|
||||
A: NewService,
|
||||
B: NewService<
|
||||
A: ServiceFactory,
|
||||
B: ServiceFactory<
|
||||
Config = A::Config,
|
||||
Request = Result<A::Response, A::Error>,
|
||||
Error = A::Error,
|
||||
@ -175,17 +185,20 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ThenNewServiceFuture<A, B>
|
||||
#[pin_project]
|
||||
pub(crate) struct ThenNewServiceFuture<A, B>
|
||||
where
|
||||
A: NewService,
|
||||
B: NewService<
|
||||
A: ServiceFactory,
|
||||
B: ServiceFactory<
|
||||
Config = A::Config,
|
||||
Request = Result<A::Response, A::Error>,
|
||||
Error = A::Error,
|
||||
InitError = A::InitError,
|
||||
>,
|
||||
{
|
||||
#[pin]
|
||||
fut_b: B::Future,
|
||||
#[pin]
|
||||
fut_a: A::Future,
|
||||
a: Option<A::Service>,
|
||||
b: Option<B::Service>,
|
||||
@ -193,8 +206,8 @@ where
|
||||
|
||||
impl<A, B> ThenNewServiceFuture<A, B>
|
||||
where
|
||||
A: NewService,
|
||||
B: NewService<
|
||||
A: ServiceFactory,
|
||||
B: ServiceFactory<
|
||||
Config = A::Config,
|
||||
Request = Result<A::Response, A::Error>,
|
||||
Error = A::Error,
|
||||
@ -213,61 +226,61 @@ where
|
||||
|
||||
impl<A, B> Future for ThenNewServiceFuture<A, B>
|
||||
where
|
||||
A: NewService,
|
||||
B: NewService<
|
||||
A: ServiceFactory,
|
||||
B: ServiceFactory<
|
||||
Config = A::Config,
|
||||
Request = Result<A::Response, A::Error>,
|
||||
Error = A::Error,
|
||||
InitError = A::InitError,
|
||||
>,
|
||||
{
|
||||
type Item = Then<A::Service, B::Service>;
|
||||
type Error = A::InitError;
|
||||
type Output = Result<Then<A::Service, B::Service>, A::InitError>;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
if self.a.is_none() {
|
||||
if let Async::Ready(service) = self.fut_a.poll()? {
|
||||
self.a = Some(service);
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
if this.a.is_none() {
|
||||
if let Poll::Ready(service) = this.fut_a.poll(cx)? {
|
||||
*this.a = Some(service);
|
||||
}
|
||||
}
|
||||
|
||||
if self.b.is_none() {
|
||||
if let Async::Ready(service) = self.fut_b.poll()? {
|
||||
self.b = Some(service);
|
||||
if this.b.is_none() {
|
||||
if let Poll::Ready(service) = this.fut_b.poll(cx)? {
|
||||
*this.b = Some(service);
|
||||
}
|
||||
}
|
||||
|
||||
if self.a.is_some() && self.b.is_some() {
|
||||
Ok(Async::Ready(Then::new(
|
||||
self.a.take().unwrap(),
|
||||
self.b.take().unwrap(),
|
||||
if this.a.is_some() && this.b.is_some() {
|
||||
Poll::Ready(Ok(Then::new(
|
||||
this.a.take().unwrap(),
|
||||
this.b.take().unwrap(),
|
||||
)))
|
||||
} else {
|
||||
Ok(Async::NotReady)
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use futures::future::{err, ok, FutureResult};
|
||||
use futures::{Async, Future, Poll};
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use crate::{IntoNewService, NewService, Service, ServiceExt};
|
||||
use futures::future::{err, lazy, ok, ready, Ready};
|
||||
|
||||
use crate::{pipeline, pipeline_factory, Service, ServiceFactory};
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Srv1(Rc<Cell<usize>>);
|
||||
|
||||
impl Service for Srv1 {
|
||||
type Request = Result<&'static str, &'static str>;
|
||||
type Response = &'static str;
|
||||
type Error = ();
|
||||
type Future = FutureResult<Self::Response, Self::Error>;
|
||||
type Future = Ready<Result<Self::Response, Self::Error>>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.0.set(self.0.get() + 1);
|
||||
Ok(Async::Ready(()))
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, req: Result<&'static str, &'static str>) -> Self::Future {
|
||||
@ -284,11 +297,11 @@ mod tests {
|
||||
type Request = Result<&'static str, ()>;
|
||||
type Response = (&'static str, &'static str);
|
||||
type Error = ();
|
||||
type Future = FutureResult<Self::Response, ()>;
|
||||
type Future = Ready<Result<Self::Response, ()>>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
self.0.set(self.0.get() + 1);
|
||||
Ok(Async::Ready(()))
|
||||
Poll::Ready(Err(()))
|
||||
}
|
||||
|
||||
fn call(&mut self, req: Result<&'static str, ()>) -> Self::Future {
|
||||
@ -299,46 +312,42 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_poll_ready() {
|
||||
#[tokio::test]
|
||||
async fn test_poll_ready() {
|
||||
let cnt = Rc::new(Cell::new(0));
|
||||
let mut srv = Srv1(cnt.clone()).then(Srv2(cnt.clone()));
|
||||
let res = srv.poll_ready();
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), Async::Ready(()));
|
||||
let mut srv = pipeline(Srv1(cnt.clone())).then(Srv2(cnt.clone()));
|
||||
let res = lazy(|cx| srv.poll_ready(cx)).await;
|
||||
assert_eq!(res, Poll::Ready(Err(())));
|
||||
assert_eq!(cnt.get(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_call() {
|
||||
#[tokio::test]
|
||||
async fn test_call() {
|
||||
let cnt = Rc::new(Cell::new(0));
|
||||
let mut srv = Srv1(cnt.clone()).then(Srv2(cnt)).clone();
|
||||
let mut srv = pipeline(Srv1(cnt.clone())).then(Srv2(cnt));
|
||||
|
||||
let res = srv.call(Ok("srv1")).poll();
|
||||
let res = srv.call(Ok("srv1")).await;
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), Async::Ready(("srv1", "ok")));
|
||||
assert_eq!(res.unwrap(), (("srv1", "ok")));
|
||||
|
||||
let res = srv.call(Err("srv")).poll();
|
||||
let res = srv.call(Err("srv")).await;
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), Async::Ready(("srv2", "err")));
|
||||
assert_eq!(res.unwrap(), (("srv2", "err")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_service() {
|
||||
#[tokio::test]
|
||||
async fn test_factory() {
|
||||
let cnt = Rc::new(Cell::new(0));
|
||||
let cnt2 = cnt.clone();
|
||||
let blank = move || Ok::<_, ()>(Srv1(cnt2.clone()));
|
||||
let new_srv = blank.into_new_service().then(move || Ok(Srv2(cnt.clone())));
|
||||
if let Async::Ready(mut srv) = new_srv.clone().new_service(&()).poll().unwrap() {
|
||||
let res = srv.call(Ok("srv1")).poll();
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), Async::Ready(("srv1", "ok")));
|
||||
let blank = move || ready(Ok::<_, ()>(Srv1(cnt2.clone())));
|
||||
let factory = pipeline_factory(blank).then(move || ready(Ok(Srv2(cnt.clone()))));
|
||||
let mut srv = factory.new_service(&()).await.unwrap();
|
||||
let res = srv.call(Ok("srv1")).await;
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), (("srv1", "ok")));
|
||||
|
||||
let res = srv.call(Err("srv")).poll();
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), Async::Ready(("srv2", "err")));
|
||||
} else {
|
||||
panic!()
|
||||
}
|
||||
let res = srv.call(Err("srv")).await;
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap(), (("srv2", "err")));
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use futures::{Async, Future, IntoFuture, Poll};
|
||||
use crate::transform_err::TransformMapInitErr;
|
||||
use crate::{IntoServiceFactory, Service, ServiceFactory};
|
||||
|
||||
use crate::transform_err::{TransformFromErr, TransformMapInitErr};
|
||||
use crate::{IntoNewService, NewService, Service};
|
||||
use pin_project::pin_project;
|
||||
|
||||
/// The `Transform` trait defines the interface of a Service factory. `Transform`
|
||||
/// is often implemented for middleware, defining how to construct a
|
||||
@ -32,7 +35,7 @@ pub trait Transform<S> {
|
||||
type InitError;
|
||||
|
||||
/// The future response value.
|
||||
type Future: Future<Item = Self::Transform, Error = Self::InitError>;
|
||||
type Future: Future<Output = Result<Self::Transform, Self::InitError>>;
|
||||
|
||||
/// Creates and returns a new Service component, asynchronously
|
||||
fn new_transform(&self, service: S) -> Self::Future;
|
||||
@ -46,32 +49,6 @@ pub trait Transform<S> {
|
||||
{
|
||||
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> Transform<S> for Rc<T>
|
||||
@ -106,31 +83,13 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for types that can be converted to a *transform service*
|
||||
pub trait IntoTransform<T, S>
|
||||
where
|
||||
T: Transform<S>,
|
||||
{
|
||||
/// Convert to a `TransformService`
|
||||
fn into_transform(self) -> T;
|
||||
}
|
||||
|
||||
impl<T, S> IntoTransform<T, S> for T
|
||||
where
|
||||
T: Transform<S>,
|
||||
{
|
||||
fn into_transform(self) -> T {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply transform to service factory. Function returns
|
||||
/// Apply transform to a service. Function returns
|
||||
/// services factory that in initialization creates
|
||||
/// service and applies transform to this service.
|
||||
pub fn apply_transform<T, S, F, U>(
|
||||
t: F,
|
||||
pub fn apply<T, S, U>(
|
||||
t: T,
|
||||
service: U,
|
||||
) -> impl NewService<
|
||||
) -> impl ServiceFactory<
|
||||
Config = S::Config,
|
||||
Request = T::Request,
|
||||
Response = T::Response,
|
||||
@ -139,30 +98,29 @@ pub fn apply_transform<T, S, F, U>(
|
||||
InitError = S::InitError,
|
||||
> + Clone
|
||||
where
|
||||
S: NewService,
|
||||
S: ServiceFactory,
|
||||
T: Transform<S::Service, InitError = S::InitError>,
|
||||
F: IntoTransform<T, S::Service>,
|
||||
U: IntoNewService<S>,
|
||||
U: IntoServiceFactory<S>,
|
||||
{
|
||||
ApplyTransform::new(t.into_transform(), service.into_new_service())
|
||||
ApplyTransform::new(t, service.into_factory())
|
||||
}
|
||||
|
||||
/// `Apply` transform to new service
|
||||
pub struct ApplyTransform<T, S> {
|
||||
struct ApplyTransform<T, S> {
|
||||
s: Rc<S>,
|
||||
t: Rc<T>,
|
||||
}
|
||||
|
||||
impl<T, S> ApplyTransform<T, S>
|
||||
where
|
||||
S: NewService,
|
||||
S: ServiceFactory,
|
||||
T: Transform<S::Service, InitError = S::InitError>,
|
||||
{
|
||||
/// Create new `ApplyTransform` new service instance
|
||||
pub fn new<F: IntoTransform<T, S::Service>>(t: F, service: S) -> Self {
|
||||
fn new(t: T, service: S) -> Self {
|
||||
Self {
|
||||
s: Rc::new(service),
|
||||
t: Rc::new(t.into_transform()),
|
||||
t: Rc::new(t),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -176,9 +134,9 @@ impl<T, S> Clone for ApplyTransform<T, S> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S> NewService for ApplyTransform<T, S>
|
||||
impl<T, S> ServiceFactory for ApplyTransform<T, S>
|
||||
where
|
||||
S: NewService,
|
||||
S: ServiceFactory,
|
||||
T: Transform<S::Service, InitError = S::InitError>,
|
||||
{
|
||||
type Request = T::Request;
|
||||
@ -193,40 +151,45 @@ where
|
||||
fn new_service(&self, cfg: &S::Config) -> Self::Future {
|
||||
ApplyTransformFuture {
|
||||
t_cell: self.t.clone(),
|
||||
fut_a: self.s.new_service(cfg).into_future(),
|
||||
fut_a: self.s.new_service(cfg),
|
||||
fut_t: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ApplyTransformFuture<T, S>
|
||||
#[pin_project]
|
||||
struct ApplyTransformFuture<T, S>
|
||||
where
|
||||
S: NewService,
|
||||
S: ServiceFactory,
|
||||
T: Transform<S::Service, InitError = S::InitError>,
|
||||
{
|
||||
#[pin]
|
||||
fut_a: S::Future,
|
||||
fut_t: Option<<T::Future as IntoFuture>::Future>,
|
||||
#[pin]
|
||||
fut_t: Option<T::Future>,
|
||||
t_cell: Rc<T>,
|
||||
}
|
||||
|
||||
impl<T, S> Future for ApplyTransformFuture<T, S>
|
||||
where
|
||||
S: NewService,
|
||||
S: ServiceFactory,
|
||||
T: Transform<S::Service, InitError = S::InitError>,
|
||||
{
|
||||
type Item = T::Transform;
|
||||
type Error = T::InitError;
|
||||
type Output = Result<T::Transform, T::InitError>;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
if self.fut_t.is_none() {
|
||||
if let Async::Ready(service) = self.fut_a.poll()? {
|
||||
self.fut_t = Some(self.t_cell.new_transform(service).into_future());
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let mut this = self.project();
|
||||
|
||||
if this.fut_t.as_mut().as_pin_mut().is_none() {
|
||||
if let Poll::Ready(service) = this.fut_a.poll(cx)? {
|
||||
this.fut_t.set(Some(this.t_cell.new_transform(service)));
|
||||
}
|
||||
}
|
||||
if let Some(ref mut fut) = self.fut_t {
|
||||
fut.poll()
|
||||
|
||||
if let Some(fut) = this.fut_t.as_mut().as_pin_mut() {
|
||||
fut.poll(cx)
|
||||
} else {
|
||||
Ok(Async::NotReady)
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use futures::{Future, Poll};
|
||||
use pin_project::pin_project;
|
||||
|
||||
use super::Transform;
|
||||
|
||||
@ -63,12 +66,13 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pin_project]
|
||||
pub struct TransformMapInitErrFuture<T, S, F, E>
|
||||
where
|
||||
T: Transform<S>,
|
||||
F: Fn(T::InitError) -> E,
|
||||
{
|
||||
#[pin]
|
||||
fut: T::Future,
|
||||
f: F,
|
||||
}
|
||||
@ -78,85 +82,10 @@ where
|
||||
T: Transform<S>,
|
||||
F: Fn(T::InitError) -> E + Clone,
|
||||
{
|
||||
type Item = T::Transform;
|
||||
type Error = E;
|
||||
type Output = Result<T::Transform, 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)
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
this.fut.poll(cx).map_err(this.f)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user