1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
//!
//! # Examples
//!
//! ## A `Read`-like trait implemented to better support uninitialized memory.
//! ```
//! # use std::io;
//!
//! use std::mem::MaybeUninit;
//!
//! use uninit_tools::buffer::{Buffer, BufferRef};
//! use uninit_tools::traits::Initialize;
//! # // TODO: Add more safe abstractions for slices of I/O slices.
//!
//! 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(())
//!     }
//! }
//!
//! # fn main() -> io::Result<()> {
//!
//! // 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());
//!
//! # Ok(())
//!
//! # }
//!
//! ```
//!
//! 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.)

#![cfg_attr(
    feature = "nightly",
    feature(maybe_uninit_array_assume_init, new_uninit)
)]
use core::mem::MaybeUninit;

pub mod buffer;
pub mod buffers;
pub mod initializer;
pub mod traits;
pub mod wrappers;

#[cfg(feature = "ioslice")]
extern crate ioslice_ as ioslice;

#[cfg(feature = "ioslice")]
mod ioslice_impls;

#[cfg(feature = "alloc")]
extern crate alloc;

#[inline]
pub(crate) unsafe fn cast_slice_same_layout<A, B>(a: &[A]) -> &[B] {
    core::slice::from_raw_parts(a.as_ptr() as *const B, a.len())
}
#[inline]
pub(crate) unsafe fn cast_slice_same_layout_mut<A, B>(a: &mut [A]) -> &mut [B] {
    core::slice::from_raw_parts_mut(a.as_mut_ptr() as *mut B, a.len())
}

/// 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.
#[inline]
pub fn cast_init_to_uninit_slice<U>(init: &[U]) -> &[MaybeUninit<U>] {
    unsafe { cast_slice_same_layout(init) }
}
/// Cast a possibly uninitialized slice of bytes, into an initializied slice, assuming that it is
/// initialized.
///
/// # Safety
///
/// The initialization variant must be upheld; that is, the caller must ensure that the buffer
/// cannot contain any uninitialized data.
#[inline]
pub unsafe fn cast_uninit_to_init_slice<U>(uninit: &[MaybeUninit<U>]) -> &[U] {
    cast_slice_same_layout(uninit)
}

/// 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.
///
/// # Safety
///
/// This is unsafe, since it allows a slice which is borrowed for a lifetime possibly shorter than
/// `'static`, to be reused after the `MaybeUninit` slice has had `MaybeUninit::uninit()` values
/// written to it. For this to be safe, the caller must only write initialized bytes to the
/// returned slice.
///
/// This function is only meant to be used in generic contexts, unlike
/// [`cast_init_to_uninit_slice`], which is used more often when copying initialized bytes to
/// uninitialized bytes.
#[inline]
pub unsafe fn cast_init_to_uninit_slice_mut<U>(init: &mut [U]) -> &mut [MaybeUninit<U>] {
    cast_slice_same_layout_mut(init)
}
/// Cast a mutable slice of possibly initialized bytes into a slice of initialized bytes, assuming
/// it is initialized.
///
/// # Safety
///
/// For this to be safe, the initialization invariant must be upheld, exactly like when reading.
///
/// __NOTE: This must not be used for initializing the buffer__. If unsafe code is still somehow,
/// always initialize this by copying from _another_ MaybeUninit slice, or using [`std::ptr::copy`]
/// or [`std::ptr::copy_nonoverlapping`].
#[inline]
pub unsafe fn cast_uninit_to_init_slice_mut<U>(uninit: &mut [MaybeUninit<U>]) -> &mut [U] {
    cast_slice_same_layout_mut(uninit)
}

/// Fill a possibly uninitialized mutable slice of bytes, with the same `byte`, returning the
/// initialized slice.
#[inline]
pub fn fill_uninit_slice<U: Copy>(slice: &mut [MaybeUninit<U>], item: U) -> &mut [U] {
    unsafe {
        slice.fill(MaybeUninit::new(item));
        cast_uninit_to_init_slice_mut(slice)
    }
}