Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
rw opened this issue Jan 16, 2020 · 2 comments
Assignees

Comments

@rw
Copy link

rw commented Jan 16, 2020

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: hyperium/hyper#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!

@skade
Copy link
Collaborator

skade commented Jan 16, 2020

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

@skade skade self-assigned this Jan 16, 2020
@ghost
Copy link

ghost commented Feb 9, 2020

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(())
    })
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants