| Crates.io | async-read-super-ext |
| lib.rs | async-read-super-ext |
| version | 0.1.0 |
| created_at | 2025-08-07 18:19:03.421884+00 |
| updated_at | 2025-08-07 18:19:03.421884+00 |
| description | A super extension for tokio::io::AsyncRead |
| homepage | |
| repository | https://github.com/honsunrise/async-read-super-ext |
| max_upload_size | |
| id | 1785639 |
| size | 52,098 |
A Rust library that provides extended functionality for async readers, specifically focusing on UTF-8 boundary-aware reading operations.
This library extends Tokio's AsyncBufRead trait with additional methods for reading data while respecting UTF-8 character boundaries. The main feature is read_utf8_boundaries_lossy, which reads data from an async source and ensures that the output contains only valid UTF-8, replacing invalid sequences with Unicode replacement characters.
�)Add this to your Cargo.toml:
[dependencies]
async-read-super-ext = "0.1.0"
use async_read_super_ext::AsyncReadSuperExt;
use tokio::io::{AsyncBufRead, BufReader};
use std::io::Cursor;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Example with valid UTF-8 data
let data = "Hello, 🦀 World!";
let mut reader = BufReader::new(Cursor::new(data.as_bytes()));
let mut output = Vec::new();
let bytes_read = reader.read_utf8_boundaries_lossy(&mut output).await?;
let result = String::from_utf8(output)?;
println!("Read {} bytes: {}", bytes_read, result);
Ok(())
}
The library gracefully handles invalid UTF-8 sequences by replacing them with Unicode replacement characters:
use async_read_super_ext::AsyncReadSuperExt;
use tokio::io::BufReader;
use std::io::Cursor;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create data with invalid UTF-8 bytes
let mut data = Vec::new();
data.extend_from_slice("Hello ".as_bytes());
data.push(0xFF); // Invalid UTF-8 byte
data.push(0xFE); // Invalid UTF-8 byte
data.extend_from_slice(" World".as_bytes());
let mut reader = BufReader::new(Cursor::new(data));
let mut output = Vec::new();
let bytes_read = reader.read_utf8_boundaries_lossy(&mut output).await?;
let result = String::from_utf8(output)?;
println!("Read {} bytes: {}", bytes_read, result);
// Output: "Hello �� World" (with replacement characters)
Ok(())
}
The library efficiently handles large files and streams:
use async_read_super_ext::AsyncReadSuperExt;
use tokio::fs::File;
use tokio::io::BufReader;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let file = File::open("large_file.txt").await?;
let mut reader = BufReader::new(file);
let mut all_data = Vec::new();
let mut buffer = Vec::new();
loop {
buffer.clear();
let bytes_read = reader.read_utf8_boundaries_lossy(&mut buffer).await?;
if bytes_read == 0 {
break; // EOF
}
all_data.extend_from_slice(&buffer);
}
let content = String::from_utf8(all_data)?;
println!("Total content length: {} characters", content.chars().count());
Ok(())
}
The library implements a state machine that:
poll_fill_bufU+FFFD)AsyncReadSuperExt: Extension trait that adds the read_utf8_boundaries_lossy method to any AsyncBufReadUtf8BoundariesLossy: Future that implements the async reading logicThe library follows Rust's standard error handling patterns:
The library includes comprehensive tests covering:
Run tests with:
cargo test
This project is licensed under either of
at your option.
Contributions are welcome! Please feel free to submit a Pull Request.
Happy coding with Rust! 🦀✨