Skip to content

Commit 98cb338

Browse files
authored
Rollup merge of #89747 - Amanieu:maybeuninit_bytes, r=m-ou-se
Add MaybeUninit::(slice_)as_bytes(_mut) This adds methods to convert between `MaybeUninit<T>` and a slice of `MaybeUninit<u8>`. This is safe since `MaybeUninit<u8>` can correctly handle padding bytes in any `T`. These methods are added: ```rust impl<T> MaybeUninit<T> { pub fn as_bytes(&self) -> &[MaybeUninit<u8>]; pub fn as_bytes_mut(&mut self) -> &mut [MaybeUninit<u8>]; pub fn slice_as_bytes(this: &[MaybeUninit<T>]) -> &[MaybeUninit<u8>]; pub fn slice_as_bytes_mut(this: &mut [MaybeUninit<T>]) -> &mut [MaybeUninit<u8>]; } ```
2 parents 74fbbef + 5c96dcf commit 98cb338

File tree

1 file changed

+124
-1
lines changed

1 file changed

+124
-1
lines changed

library/core/src/mem/maybe_uninit.rs

+124-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use crate::any::type_name;
22
use crate::fmt;
33
use crate::intrinsics;
4-
use crate::mem::ManuallyDrop;
4+
use crate::mem::{self, ManuallyDrop};
55
use crate::ptr;
6+
use crate::slice;
67

78
/// A wrapper type to construct uninitialized instances of `T`.
89
///
@@ -1160,4 +1161,126 @@ impl<T> MaybeUninit<T> {
11601161
// SAFETY: Valid elements have just been written into `this` so it is initialized
11611162
unsafe { MaybeUninit::slice_assume_init_mut(this) }
11621163
}
1164+
1165+
/// Returns the contents of this `MaybeUninit` as a slice of potentially uninitialized bytes.
1166+
///
1167+
/// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
1168+
/// contain padding bytes which are left uninitialized.
1169+
///
1170+
/// # Examples
1171+
///
1172+
/// ```
1173+
/// #![feature(maybe_uninit_as_bytes, maybe_uninit_slice)]
1174+
/// use std::mem::MaybeUninit;
1175+
///
1176+
/// let val = 0x12345678i32;
1177+
/// let uninit = MaybeUninit::new(val);
1178+
/// let uninit_bytes = uninit.as_bytes();
1179+
/// let bytes = unsafe { MaybeUninit::slice_assume_init_ref(uninit_bytes) };
1180+
/// assert_eq!(bytes, val.to_ne_bytes());
1181+
/// ```
1182+
#[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")]
1183+
pub fn as_bytes(&self) -> &[MaybeUninit<u8>] {
1184+
// SAFETY: MaybeUninit<u8> is always valid, even for padding bytes
1185+
unsafe {
1186+
slice::from_raw_parts(self.as_ptr() as *const MaybeUninit<u8>, mem::size_of::<T>())
1187+
}
1188+
}
1189+
1190+
/// Returns the contents of this `MaybeUninit` as a mutable slice of potentially uninitialized
1191+
/// bytes.
1192+
///
1193+
/// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
1194+
/// contain padding bytes which are left uninitialized.
1195+
///
1196+
/// # Examples
1197+
///
1198+
/// ```
1199+
/// #![feature(maybe_uninit_as_bytes)]
1200+
/// use std::mem::MaybeUninit;
1201+
///
1202+
/// let val = 0x12345678i32;
1203+
/// let mut uninit = MaybeUninit::new(val);
1204+
/// let uninit_bytes = uninit.as_bytes_mut();
1205+
/// if cfg!(target_endian = "little") {
1206+
/// uninit_bytes[0].write(0xcd);
1207+
/// } else {
1208+
/// uninit_bytes[3].write(0xcd);
1209+
/// }
1210+
/// let val2 = unsafe { uninit.assume_init() };
1211+
/// assert_eq!(val2, 0x123456cd);
1212+
/// ```
1213+
#[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")]
1214+
pub fn as_bytes_mut(&mut self) -> &mut [MaybeUninit<u8>] {
1215+
// SAFETY: MaybeUninit<u8> is always valid, even for padding bytes
1216+
unsafe {
1217+
slice::from_raw_parts_mut(
1218+
self.as_mut_ptr() as *mut MaybeUninit<u8>,
1219+
mem::size_of::<T>(),
1220+
)
1221+
}
1222+
}
1223+
1224+
/// Returns the contents of this slice of `MaybeUninit` as a slice of potentially uninitialized
1225+
/// bytes.
1226+
///
1227+
/// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
1228+
/// contain padding bytes which are left uninitialized.
1229+
///
1230+
/// # Examples
1231+
///
1232+
/// ```
1233+
/// #![feature(maybe_uninit_as_bytes, maybe_uninit_write_slice, maybe_uninit_slice)]
1234+
/// use std::mem::MaybeUninit;
1235+
///
1236+
/// let uninit = [MaybeUninit::new(0x1234u16), MaybeUninit::new(0x5678u16)];
1237+
/// let uninit_bytes = MaybeUninit::slice_as_bytes(&uninit);
1238+
/// let bytes = unsafe { MaybeUninit::slice_assume_init_ref(&uninit_bytes) };
1239+
/// let val1 = u16::from_ne_bytes(bytes[0..2].try_into().unwrap());
1240+
/// let val2 = u16::from_ne_bytes(bytes[2..4].try_into().unwrap());
1241+
/// assert_eq!(&[val1, val2], &[0x1234u16, 0x5678u16]);
1242+
/// ```
1243+
#[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")]
1244+
pub fn slice_as_bytes(this: &[MaybeUninit<T>]) -> &[MaybeUninit<u8>] {
1245+
// SAFETY: MaybeUninit<u8> is always valid, even for padding bytes
1246+
unsafe {
1247+
slice::from_raw_parts(
1248+
this.as_ptr() as *const MaybeUninit<u8>,
1249+
this.len() * mem::size_of::<T>(),
1250+
)
1251+
}
1252+
}
1253+
1254+
/// Returns the contents of this mutable slice of `MaybeUninit` as a mutable slice of
1255+
/// potentially uninitialized bytes.
1256+
///
1257+
/// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
1258+
/// contain padding bytes which are left uninitialized.
1259+
///
1260+
/// # Examples
1261+
///
1262+
/// ```
1263+
/// #![feature(maybe_uninit_as_bytes, maybe_uninit_write_slice, maybe_uninit_slice)]
1264+
/// use std::mem::MaybeUninit;
1265+
///
1266+
/// let mut uninit = [MaybeUninit::<u16>::uninit(), MaybeUninit::<u16>::uninit()];
1267+
/// let uninit_bytes = MaybeUninit::slice_as_bytes_mut(&mut uninit);
1268+
/// MaybeUninit::write_slice(uninit_bytes, &[0x12, 0x34, 0x56, 0x78]);
1269+
/// let vals = unsafe { MaybeUninit::slice_assume_init_ref(&uninit) };
1270+
/// if cfg!(target_endian = "little") {
1271+
/// assert_eq!(vals, &[0x3412u16, 0x7856u16]);
1272+
/// } else {
1273+
/// assert_eq!(vals, &[0x1234u16, 0x5678u16]);
1274+
/// }
1275+
/// ```
1276+
#[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")]
1277+
pub fn slice_as_bytes_mut(this: &mut [MaybeUninit<T>]) -> &mut [MaybeUninit<u8>] {
1278+
// SAFETY: MaybeUninit<u8> is always valid, even for padding bytes
1279+
unsafe {
1280+
slice::from_raw_parts_mut(
1281+
this.as_mut_ptr() as *mut MaybeUninit<u8>,
1282+
this.len() * mem::size_of::<T>(),
1283+
)
1284+
}
1285+
}
11631286
}

0 commit comments

Comments
 (0)