From 3008e7b341c0b686606f7e8d1164cc05f764b83b Mon Sep 17 00:00:00 2001 From: Nathy-bajo Date: Tue, 3 Sep 2024 11:45:55 +0100 Subject: [PATCH] Add documentation for SyncIoBridge with examples and alternatives --- tokio-util/src/io/sync_bridge.rs | 75 ++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/tokio-util/src/io/sync_bridge.rs b/tokio-util/src/io/sync_bridge.rs index 2402207584c..936e95769f7 100644 --- a/tokio-util/src/io/sync_bridge.rs +++ b/tokio-util/src/io/sync_bridge.rs @@ -6,6 +6,81 @@ use tokio::io::{ /// Use a [`tokio::io::AsyncRead`] synchronously as a [`std::io::Read`] or /// a [`tokio::io::AsyncWrite`] as a [`std::io::Write`]. +/// +/// # Alternatives +/// +/// In many cases, there are better alternatives to using `SyncIoBridge`, especially if you +/// want to avoid blocking the async runtime. Consider the following scenarios: +/// +/// ## Example 1: Hashing Data +/// +/// When hashing data, using `SyncIoBridge` can lead to suboptimal performance and might not fully leverage the async capabilities of the system. +/// Instead, consider reading the data into memory and then hashing it, or processing the data in chunks. +/// +/// ```rust +/// let mut data = Vec::new(); +/// reader.read_to_end(&mut data).await?; +/// let hash = blake3::hash(&data); +/// ``` +/// +/// Or, for more complex cases: +/// +/// ```rust +/// let mut data = vec![0; 64 * 1024]; +/// loop { +/// let len = reader.read(&mut data).await?; +/// if len == 0 { break; } +/// hasher.update(&data[..len]); +/// } +/// let hash = hasher.finalize(); +/// ``` +/// +/// ## Example 2: Compressing Data +/// +/// When compressing data, avoid using `SyncIoBridge`` with non-async compression libraries, as it may lead to inefficient and blocking code. +/// Instead, use `async-compression`, which is designed to work with asynchronous data streams. +/// +/// ```rust +/// use async_compression::tokio::write::GzipEncoder; +/// +/// let mut encoder = GzipEncoder::new(writer); +/// tokio::io::copy(&mut reader, &mut encoder).await?; +/// ``` +/// +/// ## Example 3: Parsing JSON +/// +/// When parsing `JSON` data, avoid using `SyncIoBridge` with `serde_json::from_reader` as it may cause blocking operations. +/// Instead, read the data into a `Vec` and parse it using `serde_json::from_slice`. +/// +/// ```rust +/// let mut data = Vec::new(); +/// reader.read_to_end(&mut data).await?; +/// let value: MyStruct = serde_json::from_slice(&data)?; +/// ``` +/// +/// ## Correct Usage of `SyncIoBridge` inside `spawn_blocking` +/// +/// `SyncIoBridge` is mainly useful when you need to interface with synchronous libraries from an asynchronous context. +/// Here is how you can do it correctly: +/// +/// ```rust +/// use tokio::task::spawn_blocking; +/// use tokio::io::AsyncReadExt; +/// use tokio_util::io::SyncIoBridge; +/// use std::fs::File; +/// use std::io::Read; +/// +/// let reader = tokio::fs::File::open("data.txt").await?; +/// let sync_reader = SyncIoBridge::new(reader); +/// +/// let result = spawn_blocking(move || { +/// let mut file = File::open("output.txt")?; +/// std::io::copy(&mut sync_reader, &mut file)?; +/// Ok::<_, std::io::Error>(()) +/// }) +/// .await??; +/// ``` +/// #[derive(Debug)] pub struct SyncIoBridge { src: T,