|
1 | 1 | //! Compatibility between the `tokio::io` and `futures-io` versions of the
|
2 | 2 | //! `AsyncRead` and `AsyncWrite` traits.
|
| 3 | +//! |
| 4 | +//! ## Bridging Tokio and Futures I/O with `compat()` |
| 5 | +//! |
| 6 | +//! The [`compat()`] function provides a compatibility layer that allows types implementing |
| 7 | +//! [`tokio::io::AsyncRead`] or [`tokio::io::AsyncWrite`] to be used as their |
| 8 | +//! [`futures::io::AsyncRead`] or [`futures::io::AsyncWrite`] counterparts — and vice versa. |
| 9 | +//! |
| 10 | +//! This is especially useful when working with libraries that expect I/O types from one ecosystem |
| 11 | +//! (usually `futures`) but you are using types from the other (usually `tokio`). |
| 12 | +//! |
| 13 | +//! ## Compatibility Overview |
| 14 | +//! |
| 15 | +//! | Inner Type Implements... | `Compat<T>` Implements... | |
| 16 | +//! |-----------------------------|-----------------------------| |
| 17 | +//! | [`tokio::io::AsyncRead`] | [`futures::io::AsyncRead`] | |
| 18 | +//! | [`futures::io::AsyncRead`] | [`tokio::io::AsyncRead`] | |
| 19 | +//! | [`tokio::io::AsyncWrite`] | [`futures::io::AsyncWrite`] | |
| 20 | +//! | [`futures::io::AsyncWrite`] | [`tokio::io::AsyncWrite`] | |
| 21 | +//! |
| 22 | +//! ## Feature Flag |
| 23 | +//! |
| 24 | +//! This functionality is available through the `compat` feature flag: |
| 25 | +//! |
| 26 | +//! ```toml |
| 27 | +//! tokio-util = { version = "...", features = ["compat"] } |
| 28 | +//! ``` |
| 29 | +//! |
| 30 | +//! ## Example 1: Tokio -> Futures (`AsyncRead`) |
| 31 | +//! |
| 32 | +//! This example demonstrates sending data over a [`tokio::net::TcpStream`] and using |
| 33 | +//! [`futures::io::AsyncReadExt::read`] from the `futures` crate to read it after adapting the |
| 34 | +//! stream via [`compat()`]. |
| 35 | +//! |
| 36 | +//! ```no_run |
| 37 | +//! use tokio::net::{TcpListener, TcpStream}; |
| 38 | +//! use tokio::io::AsyncWriteExt; |
| 39 | +//! use tokio_util::compat::TokioAsyncReadCompatExt; |
| 40 | +//! use futures::io::AsyncReadExt; |
| 41 | +//! |
| 42 | +//! #[tokio::main] |
| 43 | +//! async fn main() -> std::io::Result<()> { |
| 44 | +//! let listener = TcpListener::bind("127.0.0.1:8081").await?; |
| 45 | +//! |
| 46 | +//! tokio::spawn(async { |
| 47 | +//! let mut client = TcpStream::connect("127.0.0.1:8081").await.unwrap(); |
| 48 | +//! client.write_all(b"Hello World").await.unwrap(); |
| 49 | +//! }); |
| 50 | +//! |
| 51 | +//! let (stream, _) = listener.accept().await?; |
| 52 | +//! |
| 53 | +//! // Adapt `tokio::TcpStream` to be used with `futures::io::AsyncReadExt` |
| 54 | +//! let mut compat_stream = stream.compat(); |
| 55 | +//! let mut buffer = [0; 20]; |
| 56 | +//! let n = compat_stream.read(&mut buffer).await?; |
| 57 | +//! println!("Received: {}", String::from_utf8_lossy(&buffer[..n])); |
| 58 | +//! |
| 59 | +//! Ok(()) |
| 60 | +//! } |
| 61 | +//! ``` |
| 62 | +//! |
| 63 | +//! ## Example 2: Futures -> Tokio (`AsyncRead`) |
| 64 | +//! |
| 65 | +//! The reverse is also possible: you can take a [`futures::io::AsyncRead`] (e.g. a cursor) and |
| 66 | +//! adapt it to be used with [`tokio::io::AsyncReadExt::read_to_end`] |
| 67 | +//! |
| 68 | +//! ``` |
| 69 | +//! use futures::io::Cursor; |
| 70 | +//! use tokio_util::compat::FuturesAsyncReadCompatExt; |
| 71 | +//! use tokio::io::AsyncReadExt; |
| 72 | +//! |
| 73 | +//! fn main() { |
| 74 | +//! let future = async { |
| 75 | +//! let reader = Cursor::new(b"Hello from futures"); |
| 76 | +//! let mut compat_reader = reader.compat(); |
| 77 | +//! let mut buf = Vec::new(); |
| 78 | +//! compat_reader.read_to_end(&mut buf).await.unwrap(); |
| 79 | +//! assert_eq!(&buf, b"Hello from futures"); |
| 80 | +//! }; |
| 81 | +//! |
| 82 | +//! // Run the future inside a Tokio runtime |
| 83 | +//! tokio::runtime::Runtime::new().unwrap().block_on(future); |
| 84 | +//! } |
| 85 | +//! ``` |
| 86 | +//! |
| 87 | +//! ## Common Use Cases |
| 88 | +//! |
| 89 | +//! - Using `tokio` sockets with `async-tungstenite`, `async-compression`, or `futures-rs`-based |
| 90 | +//! libraries. |
| 91 | +//! - Bridging I/O interfaces between mixed-ecosystem libraries. |
| 92 | +//! - Avoiding rewrites or duplication of I/O code in async environments. |
| 93 | +//! |
| 94 | +//! ## See Also |
| 95 | +//! |
| 96 | +//! - [`Compat`] type |
| 97 | +//! - [`TokioAsyncReadCompatExt`] |
| 98 | +//! - [`FuturesAsyncReadCompatExt`] |
| 99 | +//! - [`tokio::io`] |
| 100 | +//! - [`futures::io`] |
| 101 | +//! |
| 102 | +//! [`futures::io`]: https://docs.rs/futures/latest/futures/io/ |
| 103 | +//! [`futures::io::AsyncRead`]: https://docs.rs/futures/latest/futures/io/trait.AsyncRead.html |
| 104 | +//! [`futures::io::AsyncWrite`]: https://docs.rs/futures/latest/futures/io/trait.AsyncWrite.html |
| 105 | +//! [`futures::io::AsyncReadExt::read`]: https://docs.rs/futures/latest/futures/io/trait.AsyncReadExt.html#method.read |
| 106 | +//! [`compat()`]: TokioAsyncReadCompatExt::compat |
| 107 | +
|
3 | 108 | use pin_project_lite::pin_project;
|
4 | 109 | use std::io;
|
5 | 110 | use std::pin::Pin;
|
|
0 commit comments