From a0af02a396274b30ec1d0a27e18ac9ae6eaa2186 Mon Sep 17 00:00:00 2001 From: Suryakant Soni <40172696+Suryakant-Soni@users.noreply.github.com> Date: Mon, 28 Apr 2025 19:50:47 +0530 Subject: [PATCH] compat: add more documentation to `tokio_util::compat` (#7279) --- tokio-util/src/compat.rs | 105 +++++++++++++++++++++++++++++++++++++++ tokio-util/src/lib.rs | 2 - 2 files changed, 105 insertions(+), 2 deletions(-) diff --git a/tokio-util/src/compat.rs b/tokio-util/src/compat.rs index b71e2b1b0..9e3f26bdc 100644 --- a/tokio-util/src/compat.rs +++ b/tokio-util/src/compat.rs @@ -1,5 +1,110 @@ //! Compatibility between the `tokio::io` and `futures-io` versions of the //! `AsyncRead` and `AsyncWrite` traits. +//! +//! ## Bridging Tokio and Futures I/O with `compat()` +//! +//! The [`compat()`] function provides a compatibility layer that allows types implementing +//! [`tokio::io::AsyncRead`] or [`tokio::io::AsyncWrite`] to be used as their +//! [`futures::io::AsyncRead`] or [`futures::io::AsyncWrite`] counterparts — and vice versa. +//! +//! This is especially useful when working with libraries that expect I/O types from one ecosystem +//! (usually `futures`) but you are using types from the other (usually `tokio`). +//! +//! ## Compatibility Overview +//! +//! | Inner Type Implements... | `Compat` Implements... | +//! |-----------------------------|-----------------------------| +//! | [`tokio::io::AsyncRead`] | [`futures::io::AsyncRead`] | +//! | [`futures::io::AsyncRead`] | [`tokio::io::AsyncRead`] | +//! | [`tokio::io::AsyncWrite`] | [`futures::io::AsyncWrite`] | +//! | [`futures::io::AsyncWrite`] | [`tokio::io::AsyncWrite`] | +//! +//! ## Feature Flag +//! +//! This functionality is available through the `compat` feature flag: +//! +//! ```toml +//! tokio-util = { version = "...", features = ["compat"] } +//! ``` +//! +//! ## Example 1: Tokio -> Futures (`AsyncRead`) +//! +//! This example demonstrates sending data over a [`tokio::net::TcpStream`] and using +//! [`futures::io::AsyncReadExt::read`] from the `futures` crate to read it after adapting the +//! stream via [`compat()`]. +//! +//! ```no_run +//! use tokio::net::{TcpListener, TcpStream}; +//! use tokio::io::AsyncWriteExt; +//! use tokio_util::compat::TokioAsyncReadCompatExt; +//! use futures::io::AsyncReadExt; +//! +//! #[tokio::main] +//! async fn main() -> std::io::Result<()> { +//! let listener = TcpListener::bind("127.0.0.1:8081").await?; +//! +//! tokio::spawn(async { +//! let mut client = TcpStream::connect("127.0.0.1:8081").await.unwrap(); +//! client.write_all(b"Hello World").await.unwrap(); +//! }); +//! +//! let (stream, _) = listener.accept().await?; +//! +//! // Adapt `tokio::TcpStream` to be used with `futures::io::AsyncReadExt` +//! let mut compat_stream = stream.compat(); +//! let mut buffer = [0; 20]; +//! let n = compat_stream.read(&mut buffer).await?; +//! println!("Received: {}", String::from_utf8_lossy(&buffer[..n])); +//! +//! Ok(()) +//! } +//! ``` +//! +//! ## Example 2: Futures -> Tokio (`AsyncRead`) +//! +//! The reverse is also possible: you can take a [`futures::io::AsyncRead`] (e.g. a cursor) and +//! adapt it to be used with [`tokio::io::AsyncReadExt::read_to_end`] +//! +//! ``` +//! use futures::io::Cursor; +//! use tokio_util::compat::FuturesAsyncReadCompatExt; +//! use tokio::io::AsyncReadExt; +//! +//! fn main() { +//! let future = async { +//! let reader = Cursor::new(b"Hello from futures"); +//! let mut compat_reader = reader.compat(); +//! let mut buf = Vec::new(); +//! compat_reader.read_to_end(&mut buf).await.unwrap(); +//! assert_eq!(&buf, b"Hello from futures"); +//! }; +//! +//! // Run the future inside a Tokio runtime +//! tokio::runtime::Runtime::new().unwrap().block_on(future); +//! } +//! ``` +//! +//! ## Common Use Cases +//! +//! - Using `tokio` sockets with `async-tungstenite`, `async-compression`, or `futures-rs`-based +//! libraries. +//! - Bridging I/O interfaces between mixed-ecosystem libraries. +//! - Avoiding rewrites or duplication of I/O code in async environments. +//! +//! ## See Also +//! +//! - [`Compat`] type +//! - [`TokioAsyncReadCompatExt`] +//! - [`FuturesAsyncReadCompatExt`] +//! - [`tokio::io`] +//! - [`futures::io`] +//! +//! [`futures::io`]: https://docs.rs/futures/latest/futures/io/ +//! [`futures::io::AsyncRead`]: https://docs.rs/futures/latest/futures/io/trait.AsyncRead.html +//! [`futures::io::AsyncWrite`]: https://docs.rs/futures/latest/futures/io/trait.AsyncWrite.html +//! [`futures::io::AsyncReadExt::read`]: https://docs.rs/futures/latest/futures/io/trait.AsyncReadExt.html#method.read +//! [`compat()`]: TokioAsyncReadCompatExt::compat + use pin_project_lite::pin_project; use std::io; use std::pin::Pin; diff --git a/tokio-util/src/lib.rs b/tokio-util/src/lib.rs index 1df4de1b4..a68a6ba38 100644 --- a/tokio-util/src/lib.rs +++ b/tokio-util/src/lib.rs @@ -16,8 +16,6 @@ //! This crate is not versioned in lockstep with the core //! [`tokio`] crate. However, `tokio-util` _will_ respect Rust's //! semantic versioning policy, especially with regard to breaking changes. -//! -//! [`tokio`]: https://docs.rs/tokio #[macro_use] mod cfg;