Unlock yourself from the tokio walled garden.
[Tokio] uses [non-standard] I/O traits (causes compilation errors) and has the concept of "tokio context" (causes runtime errors). Using [tokio]-based crates outside the [tokio] runtime can be a frustrating experience, thus locking you into the [tokio] ecosystem and preventing you from using other async crates.
This crate is a magic wand that fixes such compilation and runtime errors caused by [tokio].
Here's a classic "cat" example that reads lines from stdin and echoes them into stdout. We'll use [tokio]'s stdin/stdout types, but rely on [futures] for everything else:
```rust 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, &mut stdout).await?;
Ok(())
})
} ```
We get errors because [tokio::io::AsyncRead
] and [tokio::io::AsyncWrite
] are different from
[futures_io::AsyncRead
] and [futures_io::AsyncWrite
]:
error[E0277]: the trait bound `tokio::io::Stdin: futures::AsyncRead` is not satisfied
--> example.rs:6:9
|
6 | futures::io::copy(stdin, &mut stdout).await?;
| ^^^^^^^^^^^^^^^^^ the trait `futures::AsyncRead` is not implemented for `tokio::io::Stdin`
error[E0277]: the trait bound `tokio::io::Stdout: futures::AsyncWrite` is not satisfied
--> example.rs:6:34
|
6 | futures::io::copy(stdin, &mut stdout).await?;
| ^^^^^^^^^^^ the trait `futures::AsyncWrite` is not implemented for `tokio::io::Stdout`
Let's apply .fix()
and .fix_mut()
to convert between
[tokio]-based and [futures]-based types:
```rust use tokio_fix::Fix;
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.fix(), &mut stdout.fix_mut()).await?;
Ok(())
})
} ```
Now the program compiles, but we get an error at runtime:
thread 'main' panicked at 'not currently running on the Tokio runtime.'
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Yikes! This is because [tokio]'s stdin and stdout are used outside the [tokio] context. We can
apply .fix()
on the [futures::io::copy()
] future to let it enter the
[tokio] context:
```rust use tokio_fix::Fix;
fn main() -> std::io::Result<()> { futures::executor::blockon(async { let stdin = tokio::io::stdin(); let mut stdout = tokio::io::stdout(); futures::io::copy(stdin.fix(), &mut stdout.fixmut()).fix().await?; Ok(()) }) } ```
Problem solved. It is also possible to apply fix()
to the outer future passed to
[futures::executor::block_on()
]:
```rust use tokio_fix::{fix, Fix};
fn main() -> std::io::Result<()> { futures::executor::block_on(fix(async { let stdin = tokio::io::stdin(); let mut stdout = tokio::io::stdout();
futures::io::copy(stdin.fix(), &mut stdout.fix_mut()).await?;
Ok(())
}))
} ```
In the previous example, we were using [tokio] from [futures], but it is also possible to use [futures] from [tokio]. All the fixes are applied very similarly:
```rust use blocking::Unblock; use tokio_fix::Fix;
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.fix_mut(), &mut stdout.fix_mut()).await?;
Ok(())
} ```
Here, we're using the [blocking] crate, which is based on [futures] rather than [tokio].
Now you can use any [tokio]-based crate without being locked into the [tokio] ecosystem!
Let's use [reqwest] and [warp] from [futures]:
```rust use tokio_fix::fix; use warp::Filter;
fn main() { futures::executor::block_on(fix(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;
}))
} ```
Licensed under either of
at your option.
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.