| Crates.io | uninit-read |
| lib.rs | uninit-read |
| version | 0.1.1 |
| created_at | 2025-11-10 16:20:05.095412+00 |
| updated_at | 2025-11-11 11:57:56.717263+00 |
| description | A marker trait and utilities for safe, high-performance reads into uninitialized buffers. |
| homepage | |
| repository | https://github.com/rrauch/uninit-read |
| max_upload_size | |
| id | 1925782 |
| size | 48,341 |
uninit-readA marker trait and utilities for safe, high-performance reads into uninitialized buffers.
The standard I/O traits, std::io::Read and futures::io::AsyncRead, require a &mut [u8] buffer. By Rust's safety
rules, this slice must be fully initialized. In performance-critical applications, the cost of zeroing a large buffer
before a read can be significant.
The common workaround is to create an uninitialized buffer and unsafely cast it to &mut [u8]:
use std::mem::MaybeUninit;
let mut uninit_buf = MaybeUninit::<[u8; 8192] >::uninit();
// This is potentially UNDEFINED BEHAVIOR!
let buf_slice = unsafe { uninit_buf.assume_init_mut() };
// reader.read(buf_slice)?;
This is dangerous because the Read contract does not forbid the implementation from reading from the buffer before
writing to it. While most readers don't, the caller is relying on an unverified implementation detail.
UninitReadThis crate provides a single, unsafe marker trait that formalizes this contract:
pub unsafe trait UninitRead {}
By implementing UninitRead for a reader type, an author makes a guarantee:
The reader implementation will not read from any part of the provided buffer that has not been written to by the implementation itself within the same call. It must treat the buffer as if it were completely uninitialized on entry.
This contract makes it sound for callers to use an uninitialized buffer with any reader that implements UninitRead.
UninitRead)If your reader upholds the safety contract, you can implement the trait for it. This is an unsafe impl because you are
making a promise the compiler cannot check.
use std::io::{Read, Result};
use uninit_read::UninitRead;
pub struct MySafeReader<R>(R);
impl<R: Read> Read for MySafeReader<R> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
// This implementation only writes to `buf` and never reads from it.
self.0.read(buf)
}
}
// SAFETY: The `read` implementation for `MySafeReader` is well-behaved and
// only writes to the buffer, never reading from uninitialized portions.
unsafe impl<R: Read> UninitRead for MySafeReader<R> {}
UninitRead)You can use the UninitReadExt traits (enabled by the exts feature) for ergonomic and safe reads into uninitialized
buffers.
use std::io::{Cursor, Result};
use std::mem::MaybeUninit;
use uninit_read::{UninitRead, UninitSyncReadExt};
// `Cursor<&[u8]>` has `UninitRead` implemented for it (with the `impls` feature).
let mut reader = Cursor::new([1, 2, 3, 4, 5]);
let mut buffer = [MaybeUninit::<u8>::uninit(); 10];
// read_uninit abstracts away the unsafe code and returns a slice to the
// initialized part of the buffer.
let initialized_part: & [u8] = reader.read_uninit( & mut buffer) ?;
assert_eq!(initialized_part, &[1, 2, 3, 4, 5]);
This crate uses feature flags to remain lightweight and dependency-free where possible.
default: ["async", "futures-lite", "impls", "reflection", "exts", "assume-uninit-read"]
exts: (Enabled by default) Provides the [UninitSyncReadExt] and [UninitAsyncReadExt] extension traits for
ergonomic reads.
impls: (Enabled by default) Provides UninitRead implementations for common standard library types like
std::fs::File, std::net::TcpStream, and &[u8].
async: Enables futures-io support. Required for all other async features.
tokio: Provides UninitRead implementation for Tokio Compat.
reflection: (Enabled by default) Enables the is_uninit_read function to check for the trait implementation at
runtime.
assume-uninit-read: Enables the AssumeUninitRead wrapper type, which allows the caller to mark third-party
readers as
UninitRead-compliant when they are known to uphold the safety contract.
If you only need to implement the UninitRead trait and do not need any implementations or utilities, you can disable
all default features for a dependency-free build:
[dependencies]
uninit-read = { version = "0.1", default-features = false }
This project is licensed under either of
at your option.