mirror of
https://github.com/fafhrd91/actix-net
synced 2025-08-31 01:40:20 +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"));
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user