Skip to content

Commit

Permalink
Rollup merge of rust-lang#65580 - SimonSapin:maybeuninit-array, r=Ama…
Browse files Browse the repository at this point in the history
…nieu

Add `MaybeUninit` methods `uninit_array`, `slice_get_ref`, `slice_get_mut`

Eventually these will hopefully become the idiomatic way to work with partially-initialized stack buffers.

All methods are unstable. Note that `uninit_array` takes a type-level `const usize` parameter, so it is blocked (at least in its current form) on const generics.

Example:

```rust
use std::mem::MaybeUninit;

let input = b"Foo";
let f = u8::to_ascii_uppercase;

let mut buffer: [MaybeUninit<u8>; 32] = MaybeUninit::uninit_array();
let vec;
let output = if let Some(buffer) = buffer.get_mut(..input.len()) {
    buffer.iter_mut().zip(input).for_each(|(a, b)| { a.write(f(b)); });
    unsafe { MaybeUninit::slice_get_ref(buffer) }
} else {
    vec = input.iter().map(f).collect::<Vec<u8>>();
    &vec
};

assert_eq!(output, b"FOO");
```
  • Loading branch information
Centril committed Nov 7, 2019
2 parents 3bb06d6 + 639c4f7 commit e11fc75
Showing 1 changed file with 63 additions and 0 deletions.
63 changes: 63 additions & 0 deletions src/libcore/mem/maybe_uninit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,43 @@ impl<T> MaybeUninit<T> {
MaybeUninit { uninit: () }
}

/// Create a new array of `MaybeUninit<T>` items, in an uninitialized state.
///
/// Note: in a future Rust version this method may become unnecessary
/// when array literal syntax allows
/// [repeating const expressions](https://github.com/rust-lang/rust/issues/49147).
/// The example below could then use `let mut buf = [MaybeUninit::<u8>::uninit(); 32];`.
///
/// # Examples
///
/// ```no_run
/// #![feature(maybe_uninit_uninit_array, maybe_uninit_extra, maybe_uninit_slice_assume_init)]
///
/// use std::mem::MaybeUninit;
///
/// extern "C" {
/// fn read_into_buffer(ptr: *mut u8, max_len: usize) -> usize;
/// }
///
/// /// Returns a (possibly smaller) slice of data that was actually read
/// fn read(buf: &mut [MaybeUninit<u8>]) -> &[u8] {
/// unsafe {
/// let len = read_into_buffer(buf.as_mut_ptr() as *mut u8, buf.len());
/// MaybeUninit::slice_get_ref(&buf[..len])
/// }
/// }
///
/// let mut buf: [MaybeUninit<u8>; 32] = MaybeUninit::uninit_array();
/// let data = read(&mut buf);
/// ```
#[unstable(feature = "maybe_uninit_uninit_array", issue = "0")]
#[inline(always)]
pub fn uninit_array<const LEN: usize>() -> [Self; LEN] {
unsafe {
MaybeUninit::<[MaybeUninit<T>; LEN]>::uninit().assume_init()
}
}

/// A promotable constant, equivalent to `uninit()`.
#[unstable(feature = "internal_uninit_const", issue = "0",
reason = "hack to work around promotability")]
Expand Down Expand Up @@ -690,6 +727,32 @@ impl<T> MaybeUninit<T> {
&mut *self.value
}

/// Assuming all the elements are initialized, get a slice to them.
///
/// # Safety
///
/// It is up to the caller to guarantee that the `MaybeUninit<T>` elements
/// really are in an initialized state.
/// Calling this when the content is not yet fully initialized causes undefined behavior.
#[unstable(feature = "maybe_uninit_slice_assume_init", issue = "0")]
#[inline(always)]
pub unsafe fn slice_get_ref(slice: &[Self]) -> &[T] {
&*(slice as *const [Self] as *const [T])
}

/// Assuming all the elements are initialized, get a mutable slice to them.
///
/// # Safety
///
/// It is up to the caller to guarantee that the `MaybeUninit<T>` elements
/// really are in an initialized state.
/// Calling this when the content is not yet fully initialized causes undefined behavior.
#[unstable(feature = "maybe_uninit_slice_assume_init", issue = "0")]
#[inline(always)]
pub unsafe fn slice_get_mut(slice: &mut [Self]) -> &mut [T] {
&mut *(slice as *mut [Self] as *mut [T])
}

/// Gets a pointer to the first element of the array.
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
#[inline(always)]
Expand Down

0 comments on commit e11fc75

Please sign in to comment.