[−][src]Crate ioslice
#![no_std]
-friendly wrappers over the std::io::IoSlice
and std::io::IoSliceMut
, which
are shared slices and exclusive slices, respectively, and ABI-compatible with system types for
I/O vectors.
Internally, the struct will store the following based on crate features:
std
- wrappingstd::io::IoSlice
directly, with accessors for it as well as conversion functions and From impls.libc
(and#[cfg(unix)]
) - wrappinglibc::iovec
directly on platforms that support it. A marker is also stored, to safely wrap the raw pointer, and forcing usage of this API to follow the borrow checker rules.- (none) - wrapping a regular slice, that may not have the same ABI guarantees as the types from std or libc have.
IoSlice
will however implement AsRef<[u8]>
, Borrow<[u8]>
, and Deref<Target = [u8]>
regardless of the features used.
Examples
A Read
-like trait implemented to better support uninitialized memory.
use std::mem::MaybeUninit; use ioslice::{Initialization, Initialized, IoSliceMut, SliceMutPartialExt}; pub trait MyRead { // NOTE: This could be a regular slice as well. fn read<'a, I: Initialization>(&mut self, slice: IoSliceMut<'a, I>) -> io::Result<(IoSliceMut<'a, Initialized>, IoSliceMut<'a, I>)>; } impl MyRead for &[u8] { fn read<'a, I: Initialization>(&mut self, slice: IoSliceMut<'a, I>) -> io::Result<(IoSliceMut<'a, Initialized>, IoSliceMut<'a, I>)> { // Begin with taking the minimum slice that can fit the copy into the buffer. let bytes_to_copy = std::cmp::min(self.len(), slice.len()); let (source, source_remainder) = self.split_at(bytes_to_copy); // Split the possibly uninitialized slice into an initialized and an uninitialized // part. This allows the `Read` implementation to only read part of the data requested. // // Normally this would be done via returning `usize`, but we need to be able to prove // that we have initialized it. let (initialized, remainder) = slice.partially_init_by_copying(source); // Advance the slice that is being read. let bytes_copied = initialized.len(); *self = source_remainder; // And finally, return the initialized part and the remainder to prove that we have // initialized it. (And to make it possible for safe code to use the buffer directly.) Ok((initialized, remainder)) } } let mut buf = [MaybeUninit::uninit(); 32]; let buf = IoSliceMut::from_uninit(&mut buf); let len = buf.len(); let original_stupid_text: &[u8] = b"copying is expensive!"; let mut stupid_text = original_stupid_text; // Read as many bytes as possible. let (initialized, remainder) = stupid_text.read(buf)?; assert_eq!(initialized, original_stupid_text); // Note that while we cannot read the rest of the buffer, we can still use it as the // destination of even more I/O, or simply check its length here. assert_eq!(remainder.len(), 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.)
Structs
AllocationError | An error that may occur if allocating an I/O box fails. |
IoBox | An owned chunk of memory, that is ABI-compatible with |
IoSlice | A |
IoSliceMut | A |
Enums
Initialized | |
Uninitialized |
Traits
Initialization | |
SliceMut | A trait for mutable slices (there is not much to do at all with an uninitialized immutable slice, is there?), that can be safely casted to an uninitialized slice, but also unsafely assumed to be initialized when they may not be. |
SliceMutExt | |
SliceMutPartial | |
SliceMutPartialExt |
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 |
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. |