Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add MaybeUninit::(slice_)as_bytes(_mut) #89747

Merged
merged 1 commit into from Jan 20, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
125 changes: 124 additions & 1 deletion library/core/src/mem/maybe_uninit.rs
@@ -1,8 +1,9 @@
use crate::any::type_name;
use crate::fmt;
use crate::intrinsics;
use crate::mem::ManuallyDrop;
use crate::mem::{self, ManuallyDrop};
use crate::ptr;
use crate::slice;

/// A wrapper type to construct uninitialized instances of `T`.
///
Expand Down Expand Up @@ -1160,4 +1161,126 @@ impl<T> MaybeUninit<T> {
// SAFETY: Valid elements have just been written into `this` so it is initialized
unsafe { MaybeUninit::slice_assume_init_mut(this) }
}

/// Returns the contents of this `MaybeUninit` as a slice of potentially uninitialized bytes.
///
/// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
/// contain padding bytes which are left uninitialized.
///
/// # Examples
///
/// ```
/// #![feature(maybe_uninit_as_bytes, maybe_uninit_slice)]
/// use std::mem::MaybeUninit;
///
/// let val = 0x12345678i32;
/// let uninit = MaybeUninit::new(val);
/// let uninit_bytes = uninit.as_bytes();
/// let bytes = unsafe { MaybeUninit::slice_assume_init_ref(uninit_bytes) };
/// assert_eq!(bytes, val.to_ne_bytes());
/// ```
#[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")]
pub fn as_bytes(&self) -> &[MaybeUninit<u8>] {
// SAFETY: MaybeUninit<u8> is always valid, even for padding bytes
unsafe {
slice::from_raw_parts(self.as_ptr() as *const MaybeUninit<u8>, mem::size_of::<T>())
}
}

/// Returns the contents of this `MaybeUninit` as a mutable slice of potentially uninitialized
/// bytes.
///
/// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
/// contain padding bytes which are left uninitialized.
///
/// # Examples
///
/// ```
/// #![feature(maybe_uninit_as_bytes)]
/// use std::mem::MaybeUninit;
///
/// let val = 0x12345678i32;
/// let mut uninit = MaybeUninit::new(val);
/// let uninit_bytes = uninit.as_bytes_mut();
/// if cfg!(target_endian = "little") {
/// uninit_bytes[0].write(0xcd);
/// } else {
/// uninit_bytes[3].write(0xcd);
/// }
/// let val2 = unsafe { uninit.assume_init() };
/// assert_eq!(val2, 0x123456cd);
/// ```
#[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")]
pub fn as_bytes_mut(&mut self) -> &mut [MaybeUninit<u8>] {
// SAFETY: MaybeUninit<u8> is always valid, even for padding bytes
unsafe {
slice::from_raw_parts_mut(
self.as_mut_ptr() as *mut MaybeUninit<u8>,
mem::size_of::<T>(),
)
}
}

/// Returns the contents of this slice of `MaybeUninit` as a slice of potentially uninitialized
/// bytes.
///
/// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
/// contain padding bytes which are left uninitialized.
///
/// # Examples
///
/// ```
/// #![feature(maybe_uninit_as_bytes, maybe_uninit_write_slice, maybe_uninit_slice)]
/// use std::mem::MaybeUninit;
///
/// let uninit = [MaybeUninit::new(0x1234u16), MaybeUninit::new(0x5678u16)];
/// let uninit_bytes = MaybeUninit::slice_as_bytes(&uninit);
/// let bytes = unsafe { MaybeUninit::slice_assume_init_ref(&uninit_bytes) };
/// let val1 = u16::from_ne_bytes(bytes[0..2].try_into().unwrap());
/// let val2 = u16::from_ne_bytes(bytes[2..4].try_into().unwrap());
/// assert_eq!(&[val1, val2], &[0x1234u16, 0x5678u16]);
/// ```
#[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")]
pub fn slice_as_bytes(this: &[MaybeUninit<T>]) -> &[MaybeUninit<u8>] {
// SAFETY: MaybeUninit<u8> is always valid, even for padding bytes
unsafe {
slice::from_raw_parts(
this.as_ptr() as *const MaybeUninit<u8>,
this.len() * mem::size_of::<T>(),
)
}
}

/// Returns the contents of this mutable slice of `MaybeUninit` as a mutable slice of
/// potentially uninitialized bytes.
///
/// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
/// contain padding bytes which are left uninitialized.
///
/// # Examples
///
/// ```
/// #![feature(maybe_uninit_as_bytes, maybe_uninit_write_slice, maybe_uninit_slice)]
/// use std::mem::MaybeUninit;
///
/// let mut uninit = [MaybeUninit::<u16>::uninit(), MaybeUninit::<u16>::uninit()];
/// let uninit_bytes = MaybeUninit::slice_as_bytes_mut(&mut uninit);
/// MaybeUninit::write_slice(uninit_bytes, &[0x12, 0x34, 0x56, 0x78]);
/// let vals = unsafe { MaybeUninit::slice_assume_init_ref(&uninit) };
/// if cfg!(target_endian = "little") {
/// assert_eq!(vals, &[0x3412u16, 0x7856u16]);
/// } else {
/// assert_eq!(vals, &[0x1234u16, 0x5678u16]);
/// }
/// ```
#[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")]
pub fn slice_as_bytes_mut(this: &mut [MaybeUninit<T>]) -> &mut [MaybeUninit<u8>] {
// SAFETY: MaybeUninit<u8> is always valid, even for padding bytes
unsafe {
slice::from_raw_parts_mut(
this.as_mut_ptr() as *mut MaybeUninit<u8>,
this.len() * mem::size_of::<T>(),
)
}
}
}