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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Add MaybeUninit::as_bytes
  • Loading branch information
Amanieu committed Jan 19, 2022

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit 5c96dcf96100d67370e794d3ffd59762dbc102ed
125 changes: 124 additions & 1 deletion library/core/src/mem/maybe_uninit.rs
Original file line number Diff line number Diff line change
@@ -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`.
///
@@ -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>(),
)
}
}
}