Crate uninit_tools[][src]

Examples

A Read-like trait implemented to better support uninitialized memory.


use std::mem::MaybeUninit;

use uninit_tools::buffer::{Buffer, BufferRef};
use uninit_tools::traits::Initialize;

pub trait MyRead {
    // NOTE: The function does not return any count, since the buffer keeps track of that.
    //
    // Rather than using `&mut Buffer<T>` directly, we use `BufferRef<'_, T>` to prevent the
    // caller from replacing the buffer that is being filled with something different. It also
    // gives the `Read` implementor a reduced subset of the functionality, to that it cannot
    // for example read the bytes that are already written into the buffer.
    fn read<'buffer, T>(&mut self, buffer: BufferRef<'buffer, T>) -> io::Result<()>
    where
        T: Initialize<Item = u8>,
    ;
}

impl MyRead for &[u8] {
    fn read<'buffer, T>(&mut self, mut buffer: BufferRef<'buffer, T>) -> io::Result<()>
    where
        T: Initialize<Item = u8>,
    {
        // Get the minimum number of bytes to copy. Note that it will panic if the source slice
        // were to overflow, as with the regular `copy_from_slice` function for regular slices.
        let min = std::cmp::min(self.len(), buffer.remaining());

        // Advance the buffer by simply copying the source slice.
        buffer.append(&self[..min]);

        Ok(())
    }
}


// NOTE: The `Initialize` trait is implemented for arrays of all sizes, thanks to const
// generics.
let array = [MaybeUninit::uninit(); 32];
let len = array.len();
let mut buf = Buffer::uninit(array);

let original_stupid_text: &[u8] = b"copying is expensive!";
let mut stupid_text = original_stupid_text;

// Read as many bytes as possible.
stupid_text.read(buf.by_ref())?;

// Note that while we cannot do anything useful with the rest of the buffer, we can still use
// it as the destination of even more I/O, or simply check its length like we do here.
assert_eq!(buf.remaining(), len - original_stupid_text.len());


Note that this may not be the best implementation of the Read trait, but it does show that uninitialized memory handling can be done entirely in safe code, being moderately ergonomic.

(If this would be incorporated into std::io::Read, there would probably be a simpler unsafe function, that defaults to the safer wrapper.)

Modules

buffer

Buffers for single-buffer and vectored I/O which tracking initializedness and how much has been filled. Container types pointing to possibly-uninitialized memory such as Vec<MaybeUninit<Item>>, IoBox<Uninitialized>, or Box<[MaybeUninit<Item>]> can be transformed into their initialized variants via the Initialize trait, within requiring unsafe code.

buffers
initializer
traits
wrappers

Functions

cast_init_to_uninit_slice

Cast a slice of bytes into a slice of uninitialized bytes, pretending that it is uninitialized. This is completely safe, since MaybeUninit must have the exact same (direct) layout, like u8 has. The downside with this is that the information about initializedness is lost; unless relying on unsafe code, the resulting slice can only be used to prove validity of the memory range.

cast_init_to_uninit_slice_mut

Cast a mutable slice of bytes into a slice of uninitialized bytes, pretending that it is uninitialized. This is completely safe since they always have the same memory layout; however, the layout of the slices themselves must not be relied upon. The initializedness information is lost as part of this cast, but can be recovered when initializing again or by using unsafe code.

cast_uninit_to_init_slice

Cast a possibly uninitialized slice of bytes, into an initializied slice, assuming that it is initialized.

cast_uninit_to_init_slice_mut

Cast a mutable slice of possibly initialized bytes into a slice of initialized bytes, assuming it is initialized.

fill_uninit_slice

Fill a possibly uninitialized mutable slice of bytes, with the same byte, returning the initialized slice.