Skip to content

Commit b3cf03f

Browse files
committed
Add inherent versions of MaybeUninit methods for slices
1 parent 6de928d commit b3cf03f

File tree

1 file changed

+205
-1
lines changed

1 file changed

+205
-1
lines changed

library/core/src/mem/maybe_uninit.rs

+205-1
Original file line numberDiff line numberDiff line change
@@ -1409,6 +1409,210 @@ impl<T> MaybeUninit<T> {
14091409
unsafe { slice::from_raw_parts_mut(this.as_mut_ptr() as *mut MaybeUninit<u8>, bytes) }
14101410
}
14111411
}
1412+
impl<T> [MaybeUninit<T>] {
1413+
/// Copies the elements from `src` to `self`,
1414+
/// returning a mutable reference to the now initialized contents of `self`.
1415+
///
1416+
/// If `T` does not implement `Copy`, use [`write_clone_of_slice`] instead.
1417+
///
1418+
/// This is similar to [`slice::copy_from_slice`].
1419+
///
1420+
/// # Panics
1421+
///
1422+
/// This function will panic if the two slices have different lengths.
1423+
///
1424+
/// # Examples
1425+
///
1426+
/// ```
1427+
/// #![feature(maybe_uninit_write_slice)]
1428+
/// use std::mem::MaybeUninit;
1429+
///
1430+
/// let mut dst = [MaybeUninit::uninit(); 32];
1431+
/// let src = [0; 32];
1432+
///
1433+
/// let init = dst.write_copy_of_slice(&src);
1434+
///
1435+
/// assert_eq!(init, src);
1436+
/// ```
1437+
///
1438+
/// ```
1439+
/// #![feature(maybe_uninit_write_slice)]
1440+
/// use std::mem::MaybeUninit;
1441+
///
1442+
/// let mut vec = Vec::with_capacity(32);
1443+
/// let src = [0; 16];
1444+
///
1445+
/// vec.spare_capacity_mut()[..src.len()].write_copy_of_slice(&src);
1446+
///
1447+
/// // SAFETY: we have just copied all the elements of len into the spare capacity
1448+
/// // the first src.len() elements of the vec are valid now.
1449+
/// unsafe {
1450+
/// vec.set_len(src.len());
1451+
/// }
1452+
///
1453+
/// assert_eq!(vec, src);
1454+
/// ```
1455+
///
1456+
/// [`write_clone_of_slice`]: MaybeUninit::write_clone_of_slice
1457+
#[unstable(feature = "maybe_uninit_write_slice", issue = "79995")]
1458+
pub fn write_copy_of_slice(&mut self, src: &[T]) -> &mut [T]
1459+
where
1460+
T: Copy,
1461+
{
1462+
// SAFETY: &[T] and &[MaybeUninit<T>] have the same layout
1463+
let uninit_src: &[MaybeUninit<T>] = unsafe { super::transmute(src) };
1464+
1465+
self.copy_from_slice(uninit_src);
1466+
1467+
// SAFETY: Valid elements have just been copied into `self` so it is initialized
1468+
unsafe { self.assume_init_mut() }
1469+
}
1470+
1471+
/// Clones the elements from `src` to `self`,
1472+
/// returning a mutable reference to the now initialized contents of `self`.
1473+
/// Any already initialized elements will not be dropped.
1474+
///
1475+
/// If `T` implements `Copy`, use [`write_copy_of_slice`] instead.
1476+
///
1477+
/// This is similar to [`slice::clone_from_slice`] but does not drop existing elements.
1478+
///
1479+
/// # Panics
1480+
///
1481+
/// This function will panic if the two slices have different lengths, or if the implementation of `Clone` panics.
1482+
///
1483+
/// If there is a panic, the already cloned elements will be dropped.
1484+
///
1485+
/// # Examples
1486+
///
1487+
/// ```
1488+
/// #![feature(maybe_uninit_write_slice)]
1489+
/// use std::mem::MaybeUninit;
1490+
///
1491+
/// let mut dst = [MaybeUninit::uninit(); 5];
1492+
/// let src = ["wibbly", "wobbly", "timey", "wimey", "stuff"].map(|s| s.to_string());
1493+
///
1494+
/// let init = dst.write_clone_of_slice(&src);
1495+
///
1496+
/// assert_eq!(init, src);
1497+
///
1498+
/// # // Prevent leaks for Miri
1499+
/// # unsafe { std::ptr::drop_in_place(init); }
1500+
/// ```
1501+
///
1502+
/// ```
1503+
/// #![feature(maybe_uninit_write_slice)]
1504+
/// use std::mem::MaybeUninit;
1505+
///
1506+
/// let mut vec = Vec::with_capacity(32);
1507+
/// let src = ["rust", "is", "a", "pretty", "cool", "language"].map(|s| s.to_string());
1508+
///
1509+
/// vec.spare_capacity_mut()[..src.len()].write_clone_of_slice(&src);
1510+
///
1511+
/// // SAFETY: we have just cloned all the elements of len into the spare capacity
1512+
/// // the first src.len() elements of the vec are valid now.
1513+
/// unsafe {
1514+
/// vec.set_len(src.len());
1515+
/// }
1516+
///
1517+
/// assert_eq!(vec, src);
1518+
/// ```
1519+
///
1520+
/// [`write_copy_of_slice`]: MaybeUninit::write_copy_of_slice
1521+
#[unstable(feature = "maybe_uninit_write_slice", issue = "79995")]
1522+
pub fn write_clone_of_slice(&mut self, src: &[T]) -> &mut [T]
1523+
where
1524+
T: Clone,
1525+
{
1526+
// unlike copy_from_slice this does not call clone_from_slice on the slice
1527+
// this is because `MaybeUninit<T: Clone>` does not implement Clone.
1528+
1529+
assert_eq!(self.len(), src.len(), "destination and source slices have different lengths");
1530+
1531+
// NOTE: We need to explicitly slice them to the same length
1532+
// for bounds checking to be elided, and the optimizer will
1533+
// generate memcpy for simple cases (for example T = u8).
1534+
let len = self.len();
1535+
let src = &src[..len];
1536+
1537+
// guard is needed b/c panic might happen during a clone
1538+
let mut guard = Guard { slice: self, initialized: 0 };
1539+
1540+
for i in 0..len {
1541+
guard.slice[i].write(src[i].clone());
1542+
guard.initialized += 1;
1543+
}
1544+
1545+
super::forget(guard);
1546+
1547+
// SAFETY: Valid elements have just been written into `self` so it is initialized
1548+
unsafe { self.assume_init_mut() }
1549+
}
1550+
1551+
/// Drops the contained values in place.
1552+
///
1553+
/// # Safety
1554+
///
1555+
/// It is up to the caller to guarantee that every `MaybeUninit<T>` in the slice
1556+
/// really is in an initialized state. Calling this when the content is not yet
1557+
/// fully initialized causes undefined behavior.
1558+
///
1559+
/// On top of that, all additional invariants of the type `T` must be
1560+
/// satisfied, as the `Drop` implementation of `T` (or its members) may
1561+
/// rely on this. For example, setting a [`Vec<T>`] to an invalid but
1562+
/// non-null address makes it initialized (under the current implementation;
1563+
/// this does not constitute a stable guarantee), because the only
1564+
/// requirement the compiler knows about it is that the data pointer must be
1565+
/// non-null. Dropping such a `Vec<T>` however will cause undefined
1566+
/// behaviour.
1567+
///
1568+
/// [`Vec<T>`]: ../../std/vec/struct.Vec.html
1569+
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
1570+
pub unsafe fn assume_init_drop(&mut self) {
1571+
// SAFETY: the caller must guarantee that every element of `self`
1572+
// is initialized and satisfies all invariants of `T`.
1573+
// Dropping the value in place is safe if that is the case.
1574+
unsafe { ptr::drop_in_place(self as *mut [MaybeUninit<T>] as *mut [T]) }
1575+
}
1576+
1577+
/// Gets a shared reference to the contained value.
1578+
///
1579+
/// # Safety
1580+
///
1581+
/// Calling this when the content is not yet fully initialized causes undefined
1582+
/// behavior: it is up to the caller to guarantee that every `MaybeUninit<T>` in
1583+
/// the slice really is in an initialized state.
1584+
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
1585+
#[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")]
1586+
#[inline(always)]
1587+
pub const unsafe fn assume_init_ref(&self) -> &[T] {
1588+
// SAFETY: the caller must guarantee that `self` is initialized.
1589+
// This also means that `self` must be a `value` variant.
1590+
unsafe {
1591+
intrinsics::assert_inhabited::<T>();
1592+
slice::from_raw_parts(self.as_ptr().cast::<T>(), self.len())
1593+
}
1594+
}
1595+
1596+
/// Gets a mutable (unique) reference to the contained value.
1597+
///
1598+
/// # Safety
1599+
///
1600+
/// Calling this when the content is not yet fully initialized causes undefined
1601+
/// behavior: it is up to the caller to guarantee that every `MaybeUninit<T>` in the
1602+
/// slice really is in an initialized state. For instance, `.assume_init_mut()` cannot
1603+
/// be used to initialize a `MaybeUninit` slice.
1604+
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
1605+
#[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")]
1606+
#[inline(always)]
1607+
pub const unsafe fn assume_init_mut(&mut self) -> &mut [T] {
1608+
// SAFETY: the caller must guarantee that `self` is initialized.
1609+
// This also means that `self` must be a `value` variant.
1610+
unsafe {
1611+
intrinsics::assert_inhabited::<T>();
1612+
slice::from_raw_parts_mut(self.as_mut_ptr().cast::<T>(), self.len())
1613+
}
1614+
}
1615+
}
14121616

14131617
impl<T, const N: usize> MaybeUninit<[T; N]> {
14141618
/// Transposes a `MaybeUninit<[T; N]>` into a `[MaybeUninit<T>; N]`.
@@ -1459,7 +1663,7 @@ impl<'a, T> Drop for Guard<'a, T> {
14591663
let initialized_part = &mut self.slice[..self.initialized];
14601664
// SAFETY: this raw sub-slice will contain only initialized objects.
14611665
unsafe {
1462-
crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(initialized_part));
1666+
initialized_part.assume_init_drop();
14631667
}
14641668
}
14651669
}

0 commit comments

Comments
 (0)