• Stars
    star
    120
  • Rank 295,983 (Top 6 %)
  • Language
    Rust
  • License
    Apache License 2.0
  • Created about 4 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Compatibility adapter between tokio and futures

async-compat

Build License Cargo Documentation

Compatibility adapter between tokio and futures.

There are two kinds of compatibility issues between tokio and futures:

  1. Tokio's types cannot be used outside tokio context, so any attempt to use them will panic.
    • Solution: If you apply the Compat adapter to a future, the future will enter the context of a global single-threaded tokio runtime started by this crate. That does not mean the future runs on the tokio runtime - it only means the future sets a thread-local variable pointing to the global tokio runtime so that tokio's types can be used inside it.
  2. Tokio and futures have similar but different I/O traits AsyncRead, AsyncWrite, AsyncBufRead, and AsyncSeek.
    • Solution: When the Compat adapter is applied to an I/O type, it will implement traits of the opposite kind. That's how you can use tokio-based types wherever futures-based types are expected, and the other way around.

Examples

This program reads lines from stdin and echoes them into stdout, except it's not going to work:

fn main() -> std::io::Result<()> {
    futures::executor::block_on(async {
        let stdin = tokio::io::stdin();
        let mut stdout = tokio::io::stdout();

        // The following line will not work for two reasons:
        // 1. Runtime error because stdin and stdout are used outside tokio context.
        // 2. Compilation error due to mismatched `AsyncRead` and `AsyncWrite` traits.
        futures::io::copy(stdin, &mut stdout).await?;
        Ok(())
    })
}

To get around the compatibility issues, apply the Compat adapter to stdin, stdout, and futures::io::copy():

use async_compat::CompatExt;

fn main() -> std::io::Result<()> {
    futures::executor::block_on(async {
        let stdin = tokio::io::stdin();
        let mut stdout = tokio::io::stdout();

        futures::io::copy(stdin.compat(), &mut stdout.compat_mut()).compat().await?;
        Ok(())
    })
}

It is also possible to apply Compat to the outer future passed to futures::executor::block_on() rather than futures::io::copy() itself. When applied to the outer future, individual inner futures don't need the adapter because they're all now inside tokio context:

use async_compat::{Compat, CompatExt};

fn main() -> std::io::Result<()> {
    futures::executor::block_on(Compat::new(async {
        let stdin = tokio::io::stdin();
        let mut stdout = tokio::io::stdout();

        futures::io::copy(stdin.compat(), &mut stdout.compat_mut()).await?;
        Ok(())
    }))
}

The compatibility adapter converts between tokio-based and futures-based I/O types in any direction. Here's how we can write the same program by using futures-based I/O types inside tokio:

use async_compat::CompatExt;
use blocking::Unblock;

#[tokio::main]
async fn main() -> std::io::Result<()> {
    let mut stdin = Unblock::new(std::io::stdin());
    let mut stdout = Unblock::new(std::io::stdout());

    tokio::io::copy(&mut stdin.compat_mut(), &mut stdout.compat_mut()).await?;
    Ok(())
}

Finally, we can use any tokio-based crate from any other async runtime. Here are reqwest and warp as an example:

use async_compat::{Compat, CompatExt};
use warp::Filter;

fn main() {
    futures::executor::block_on(Compat::new(async {
        // Make an HTTP GET request.
        let response = reqwest::get("https://www.rust-lang.org").await.unwrap();
        println!("{}", response.text().await.unwrap());

        // Start an HTTP server.
        let routes = warp::any().map(|| "Hello from warp!");
        warp::serve(routes).run(([127, 0, 0, 1], 8080)).await;
    }))
}

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

More Repositories

1

smol

A small and fast async runtime for Rust
Rust
2,871
star
2

async-channel

Async multi-producer multi-consumer channel
Rust
524
star
3

async-io

Async I/O and timers
Rust
330
star
4

polling

Portable interface to epoll, kqueue, event ports, and wepoll
Rust
329
star
5

futures-lite

Futures, streams, and async I/O combinators.
Rust
293
star
6

fastrand

A simple and fast random number generator
Rust
287
star
7

blocking

A thread pool for isolating blocking I/O in async programs
Rust
278
star
8

event-listener

Notify async tasks or threads
Rust
274
star
9

async-task

Task abstraction for building executors
Rust
255
star
10

async-lock

Async synchronization primitives
Rust
193
star
11

concurrent-queue

Concurrent multi-producer multi-consumer queue
Rust
180
star
12

async-executor

Async executor
Rust
179
star
13

async-process

Async interface for working with processes
Rust
124
star
14

async-net

Async networking primitives for TCP/UDP/Unix communication
Rust
112
star
15

async-fs

Async filesystem primitives
Rust
110
star
16

easy-parallel

Run closures in parallel
Rust
100
star
17

async-broadcast

Async broadcast channels
Rust
96
star
18

parking

Thread parking and unparking
Rust
55
star
19

cache-padded

Prevent false sharing by padding and aligning to the length of a cache line
Rust
50
star
20

waker-fn

Convert closures into wakers
Rust
38
star
21

vec-arena

[DEPRECATED] A simple object arena
Rust
38
star
22

async-rustls

Async TLS/SSL streams using rustls
Rust
32
star
23

async-dup

Duplicate an async I/O handle
Rust
31
star
24

atomic-waker

futures::task::AtomicWaker extracted into its own crate
Rust
18
star
25

nb-connect

[DEPRECATED] Non-blocking TCP or Unix connect
Rust
15
star
26

async-signal

Asynchronous signal handling
Rust
14
star
27

piper

An asynchronous single-consumer single-producer pipe for bytes
Rust
8
star
28

fastrand-contrib

Extension functionality for the fastrand crate
Rust
5
star
29

smol-macros

Macros for using smol-rs
Rust
1
star