uninit-read 0.1.1

A marker trait and utilities for safe, high-performance reads into uninitialized buffers.
Documentation
# `uninit-read`

[![crates.io](https://img.shields.io/crates/v/uninit-read.svg)](https://crates.io/crates/uninit-read)
[![docs.rs](https://docs.rs/uninit-read/badge.svg)](https://docs.rs/uninit-read)
![license](https://img.shields.io/crates/l/uninit-read.svg)

A marker trait and utilities for safe, high-performance reads into uninitialized buffers.

## The Problem

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 `unsafe`ly cast it to `&mut [u8]`:

```rust
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.

## A Solution: `UninitRead`

This crate provides a single, `unsafe` marker trait that formalizes this contract:

```rust
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`.

## Usage

### For Library Authors (Implementing `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.

```rust
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> {}
```

### For Crate Users (Consuming `UninitRead`)

You can use the `UninitReadExt` traits (enabled by the `exts` feature) for ergonomic and safe reads into uninitialized
buffers.

```rust
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]);
```

## Features

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.

### For Library Authors

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:

```toml
[dependencies]
uninit-read = { version = "0.1", default-features = false }
```

## License

This project is licensed under either of

- Apache License, Version 2.0, ([LICENSE-APACHE]LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT]LICENSE-MIT or http://opensource.org/licenses/MIT)

at your option.