Async-std: Documentation idea: advertise what libraries are compatible with async-std's runtime

Created on 16 Jan 2020  路  2Comments  路  Source: async-rs/async-std

Could we keep a list of what libraries work with async-std's pluggable runtimes?

In particular, the tokio ecosystem seems somewhat "closed", in that those libraries often require tokio to operate. As a user, it's confusing, because many of these libraries are not clear about whether they require tokio. For example, I asked about using hyper with async-std's runtime; maybe it's just me, but I found the response hard to understand: https://github.com/hyperium/hyper/issues/2111

My use case is that 1) I use a custom runtime for running tests, and 2) I want my release binaries to use async-std's new runtime (that automatically handles blocking threads).

Thanks!

Most helpful comment

Happens to be that I was thinking about this morning. I might come up with something over the weekend.

All 2 comments

Happens to be that I was thinking about this morning. I might come up with something over the weekend.

How to run Hyper on async-std

Instructions copied from https://github.com/async-rs/async-std-hyper

Full Cargo.toml: https://github.com/async-rs/async-std-hyper/blob/master/Cargo.toml
Full code: https://github.com/async-rs/async-std-hyper/blob/master/src/main.rs

Step 1: Dependencies

Add async-std, hyper, and tokio as dependencies to your crate:

[dependencies]
async-std = "1"
hyper = { version = "0.13", default-features = false }
tokio = { version = "0.2", default-features = false }

Step 2: Compatibility layer

Copy this compat module into your crate:

pub mod compat {
    use std::pin::Pin;
    use std::task::{Context, Poll};

    use async_std::io;
    use async_std::net::{TcpListener, TcpStream};
    use async_std::prelude::*;
    use async_std::task;

    #[derive(Clone)]
    pub struct HyperExecutor;

    impl<F> hyper::rt::Executor<F> for HyperExecutor
    where
        F: Future + Send + 'static,
        F::Output: Send + 'static,
    {
        fn execute(&self, fut: F) {
            task::spawn(fut);
        }
    }

    pub struct HyperListener(pub TcpListener);

    impl hyper::server::accept::Accept for HyperListener {
        type Conn = HyperStream;
        type Error = io::Error;

        fn poll_accept(
            mut self: Pin<&mut Self>,
            cx: &mut Context,
        ) -> Poll<Option<Result<Self::Conn, Self::Error>>> {
            let stream = task::ready!(Pin::new(&mut self.0.incoming()).poll_next(cx)).unwrap()?;
            Poll::Ready(Some(Ok(HyperStream(stream))))
        }
    }

    pub struct HyperStream(pub TcpStream);

    impl tokio::io::AsyncRead for HyperStream {
        fn poll_read(
            mut self: Pin<&mut Self>,
            cx: &mut Context,
            buf: &mut [u8],
        ) -> Poll<io::Result<usize>> {
            Pin::new(&mut self.0).poll_read(cx, buf)
        }
    }

    impl tokio::io::AsyncWrite for HyperStream {
        fn poll_write(
            mut self: Pin<&mut Self>,
            cx: &mut Context,
            buf: &[u8],
        ) -> Poll<io::Result<usize>> {
            Pin::new(&mut self.0).poll_write(cx, buf)
        }

        fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
            Pin::new(&mut self.0).poll_flush(cx)
        }

        fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
            Pin::new(&mut self.0).poll_close(cx)
        }
    }
}

Step 3: Configure Hyper

Configure the hyper builder with:

let server = Server::builder(compat::HyperListener(listener))
    .executor(compat::Executor);

Full example:

use std::convert::Infallible;

use async_std::net::TcpListener;
use async_std::task;
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server};

use compat; // This is the module from Step 2.

async fn hello(_: Request<Body>) -> Result<Response<Body>, Infallible> {
    Ok(Response::new(Body::from("Hello World!")))
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    task::block_on(async {
        let addr = "127.0.0.1:3000";
        let listener = TcpListener::bind(addr).await?;

        let make_svc = make_service_fn(|_conn| async { Ok::<_, Infallible>(service_fn(hello)) });
        let server = Server::builder(compat::HyperListener(listener))
            .executor(compat::HyperExecutor)
            .serve(make_svc);

        println!("Listening on http://{}", addr);
        server.await?;
        Ok(())
    })
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

95th picture 95th  路  7Comments

yoshuawuyts picture yoshuawuyts  路  8Comments

Nokel81 picture Nokel81  路  3Comments

ghost picture ghost  路  4Comments

joshtriplett picture joshtriplett  路  5Comments