uninit 0.5.1-rc1

A collection of tools for a safer usage of uninitialized memory
Documentation
# `::uninit`

> A collection of tools for a safer usage of uninitialized memory.

[![Latest version](https://img.shields.io/crates/v/uninit.svg)](https://crates.io/crates/uninit)
[![Documentation](https://docs.rs/uninit/badge.svg)](https://docs.rs/uninit)
![License](https://img.shields.io/crates/l/uninit.svg)
___

Many crates out there try to replicate C "optimization" patterns such as
handling uninitialized memory without taking into account that Rust types
carry semantics much more subtle than those of C.

For instance, the following code is _Undefined Behavior_!

```rust
use ::core::mem;

let mut array: [u8; 256] = unsafe { mem::uninitialized() };
for (i, x) in array.iter_mut().enumerate() {
    *x = i as u8;
}
```

Indeed, it creates `u8`s with uninitialized memory, which currently
has **no defined behavior** in the Rust model (see [_"What The Hardware Does"
is not What Your Program Does: Uninitialized Memory_, by Ralf Jung](
https://www.ralfj.de/blog/2019/07/14/uninit.html)), and then creates Rust
references to these invalid `u8`s, which become in turn invalid too.

## Do not use [`mem::uninitialized`]!

In hindsight, offering a [`mem::uninitialized`] function in the [`core`
library](https://doc.rust-lang.org/core) of Rust (even if it was marked
`unsafe`), has been of the worst mistakes of the language. Indeed, the function
is generic and only bounded by `Sized`, and it turns out that, except for
zero-sized types or the later introduced [`MaybeUninit`]`<T>`, **all the other
calls to this function are unsound** (instant UB).

Note that there are other ways to trigger this UB without explicitely using
[`mem::uninitialized`]`::<T>()`, such as:

  - ```rust
    use ::core::mem::MaybeUninit;
    type T = u8; // for the example

    unsafe {
        MaybeUninit::<T>::uninit() // Uninitialized `MaybeUninit<T>` => Fine
            .assume_init()         // Back to an uninitialized `T` => UB
    };
    ```

      - this is exactly equivalent to calling `mem::uninitialized::<T>()`,
        which breaks the _validity_ invariant of `T` and thus causes
        "instant UB".

        There currently only two exceptions / _valid_ use cases:

          - either [`type T = [MaybeUninit<U>; N]`][`uninit_array!`],

          - or `T` is an inhabited ZST (this may, however, break safety
            invariants associated with the properties of the type, causing UB
            once such broken invariant is witnessed).

      - yes, using [`MaybeUninit`] is more subtle than just changing a function
        call.

  - ```rust
    let mut vec: Vec<u8> = Vec::with_capacity(100); // Fine
    unsafe {
        vec.set_len(100); // we have an uninitialized [u8; 100] in the heap
        // This has broken the _safety_ invariant of `Vec`, but is not yet UB
        // since no code has witnessed the broken state
    }
    let heap_bytes: &[u8] = &*vec; // Witness the broken safety invariant: UB!
    ```

## Instead, (you can) use [`MaybeUninit`]

So, the solution to manipulating uninitialized memory is to use
[`MaybeUninit`]: the special type `MaybeUninit<T>` does not assume that its
backing memory has been initialized / **the behavior of an uninitialized
`MaybeUninit<T>` is well-defined, no matter the `T`**.

### How to correctly use [`MaybeUninit`]

It is all about the _**delayed** initialization pattern_:

 1. **Creation**

    A `MaybeUninit<T>` is created, with, for instance,
    `MaybeUninit::<T>::uninit()`:

    ```rust
    use ::core::mem::MaybeUninit;

    let mut x = MaybeUninit::<i32>::uninit();
    ```

 2. **(Delayed) Initialization**

    With great care to avoid accidentally creating (even if only for an
    instant) a `&T`, `&mut T`, or even a `T` while the memory has not been
    initialized yet (which would be UB), we can write to (and thus initialize) the
    uninitialized memory through a `&mut MaybeUninit<T>`:

      - either directly, for instance:

        ```rust
        use ::core::mem::MaybeUninit;
        let mut x = MaybeUninit::<i32>::uninit();

        x = MaybeUninit::new(42);
        assert_eq!(42, unsafe { x.assume_init() });
        ```

      - or through a raw `*mut T` pointer (contrary to Rust references,
        raw pointers do not assume that the memory they point to is
        valid). For instance:

        ```rust
        use ::core::mem::MaybeUninit;
        let mut x = MaybeUninit::<i32>::uninit();

        unsafe {
            x.as_mut_ptr().write(42);
            assert_eq!(x.assume_init(), 42);
        }
        ```

      - or, if you use the tools of this crate, by upgrading the
        `&mut MaybeUninit<T>` into a "`&out T`" type called
        [`Out`]`<T>`:

        ```rust
        #![forbid(unsafe_code)] // no unsafe!
        use ::core::mem::MaybeUninit;
        use ::uninit::prelude::*;

        let mut x = MaybeUninit::uninit();
        let at_init_x: &i32 = x.as_out().write(42);
        assert_eq!(at_init_x, &42);
        ```

 3. **Type-level upgrade**

    Once we know, for sure, that the memory has been initialized, we can
    upgrade the `MaybeUninit<T>` type to the fully-fledged `T` type:

      - By value (`MaybeUninit<T> -> T`): [`.assume_init()`]
        https://doc.rust-lang.org/core/mem/union.MaybeUninit.html#method.assume_init

      - By shared reference (`&MaybeUninit<T> -> &T`):
        [`.assume_init_by_ref()`]

      - By unique reference (`&mut MaybeUninit<T> -> &mut T`):
        [`.assume_init_by_mut()`]

## The problem

As you can see, manipulating [`MaybeUninit`] to initialize its contents is
done through restrictive and unergonomic types
(`&mut MaybeUninit<T>` / `*mut T`).

> So most APIs **do not** offer a way to output / write into uninitialized memory.

This is what ends up leading many people to do the step `.3` before the
step `.2`: it is oh so much ergonomic to work with a `&mut T` than a
`*mut T`, especially when arrays, slices and vectors are involved. Thus
people end up doing UB.

### One of the worst offenders of this situation is the [`Read`] trait

```rust
use ::std::io;

pub trait Read {
    fn read (&mut self, buf: &mut [u8]) -> Result<usize, io::Error>;
    // ...
}
```

that is, there is no way to `.read()` into an uninitialized buffer (it would
require an api taking either a `(*mut u8, usize)` pair, or, equivalently and
by the way more ergonomically, a [`&out [u8]`][`crate::prelude::Out`]).

# Enter `::uninit`

So, the objective of this crate is double:

  - it offers ergonomic ways to create uninitialized buffers.

    For instance:

      - [`uninit_array!`]

      - [`Vec::reserve_uninit`]

  - it tries to offer APIs that are equivalent to pervasive APIs,
    such as `Read`'s, but that are able to work with such uninitialized buffers.

    For instance:

      - [`ReadIntoUninit`]

      - [Initialize an uninitialized buffer with `.copy_from_slice()`]

### `#![no_std]` friendly

Simply disable the default-enabled `"std"` feature in your `Cargo.toml` file:

```toml
[dependencies]
uninit = { version = "x.y.z", default-features = false }
```

[`Read`]: https://doc.rust-lang.org/1.36.0/std/io/trait.Read.html
[`mem::uninitialized`]: https://doc.rust-lang.org/core/mem/fn.uninitialized.html
[`MaybeUninit`]: https://doc.rust-lang.org/core/mem/union.MaybeUninit.html
[`.assume_init_by_ref()`]: https://docs.rs/uninit/0.3.0/uninit/extension_traits/trait.MaybeUninitExt.html#tymethod.assume_init_by_ref
[`.assume_init_by_mut()`]: https://docs.rs/uninit/0.3.0/uninit/extension_traits/trait.MaybeUninitExt.html#tymethod.assume_init_by_mut
[`uninit_array!`]: https://docs.rs/uninit/0.3.0/uninit/macro.uninit_array.html
[`Vec::reserve_uninit`]: https://docs.rs/uninit/0.3.0/uninit/extension_traits/trait.VecCapacity.html#tymethod.reserve_uninit
[`Out`]: https://docs.rs/uninit/0.3.0/uninit/out_ref/struct.Out.html
[Initialize an uninitialized buffer with `.copy_from_slice()`]: https://docs.rs/uninit/0.3.0/uninit/out_ref/struct.Out.html#method.copy_from_slice
[`ReadIntoUninit`]: https://docs.rs/uninit/0.3.0/uninit/read/trait.ReadIntoUninit.html