Skip to content

Commit 6641ecd

Browse files
committed
Add inherent versions of MaybeUninit methods for slices
1 parent a48861a commit 6641ecd

File tree

1 file changed

+203
-1
lines changed

1 file changed

+203
-1
lines changed

library/core/src/mem/maybe_uninit.rs

+203-1
Original file line numberDiff line numberDiff line change
@@ -1410,6 +1410,208 @@ impl<T> MaybeUninit<T> {
14101410
unsafe { slice::from_raw_parts_mut(this.as_mut_ptr() as *mut MaybeUninit<u8>, bytes) }
14111411
}
14121412
}
1413+
impl<T> [MaybeUninit<T>] {
1414+
/// Copies the elements from `src` to `self`,
1415+
/// returning a mutable reference to the now initialized contents of `self`.
1416+
///
1417+
/// If `T` does not implement `Copy`, use [`write_clone_of_slice`] instead.
1418+
///
1419+
/// This is similar to [`slice::copy_from_slice`].
1420+
///
1421+
/// # Panics
1422+
///
1423+
/// This function will panic if the two slices have different lengths.
1424+
///
1425+
/// # Examples
1426+
///
1427+
/// ```
1428+
/// #![feature(maybe_uninit_write_slice)]
1429+
/// use std::mem::MaybeUninit;
1430+
///
1431+
/// let mut dst = [MaybeUninit::uninit(); 32];
1432+
/// let src = [0; 32];
1433+
///
1434+
/// let init = dst.write_copy_of_slice(&src);
1435+
///
1436+
/// assert_eq!(init, src);
1437+
/// ```
1438+
///
1439+
/// ```
1440+
/// #![feature(maybe_uninit_write_slice)]
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`]: slice::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 = [const { 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+
///
1505+
/// let mut vec = Vec::with_capacity(32);
1506+
/// let src = ["rust", "is", "a", "pretty", "cool", "language"].map(|s| s.to_string());
1507+
///
1508+
/// vec.spare_capacity_mut()[..src.len()].write_clone_of_slice(&src);
1509+
///
1510+
/// // SAFETY: we have just cloned all the elements of len into the spare capacity
1511+
/// // the first src.len() elements of the vec are valid now.
1512+
/// unsafe {
1513+
/// vec.set_len(src.len());
1514+
/// }
1515+
///
1516+
/// assert_eq!(vec, src);
1517+
/// ```
1518+
///
1519+
/// [`write_copy_of_slice`]: slice::write_copy_of_slice
1520+
#[unstable(feature = "maybe_uninit_write_slice", issue = "79995")]
1521+
pub fn write_clone_of_slice(&mut self, src: &[T]) -> &mut [T]
1522+
where
1523+
T: Clone,
1524+
{
1525+
// unlike copy_from_slice this does not call clone_from_slice on the slice
1526+
// this is because `MaybeUninit<T: Clone>` does not implement Clone.
1527+
1528+
assert_eq!(self.len(), src.len(), "destination and source slices have different lengths");
1529+
1530+
// NOTE: We need to explicitly slice them to the same length
1531+
// for bounds checking to be elided, and the optimizer will
1532+
// generate memcpy for simple cases (for example T = u8).
1533+
let len = self.len();
1534+
let src = &src[..len];
1535+
1536+
// guard is needed b/c panic might happen during a clone
1537+
let mut guard = Guard { slice: self, initialized: 0 };
1538+
1539+
for i in 0..len {
1540+
guard.slice[i].write(src[i].clone());
1541+
guard.initialized += 1;
1542+
}
1543+
1544+
super::forget(guard);
1545+
1546+
// SAFETY: Valid elements have just been written into `self` so it is initialized
1547+
unsafe { self.assume_init_mut() }
1548+
}
1549+
1550+
/// Drops the contained values in place.
1551+
///
1552+
/// # Safety
1553+
///
1554+
/// It is up to the caller to guarantee that every `MaybeUninit<T>` in the slice
1555+
/// really is in an initialized state. Calling this when the content is not yet
1556+
/// fully initialized causes undefined behavior.
1557+
///
1558+
/// On top of that, all additional invariants of the type `T` must be
1559+
/// satisfied, as the `Drop` implementation of `T` (or its members) may
1560+
/// rely on this. For example, setting a [`Vec<T>`] to an invalid but
1561+
/// non-null address makes it initialized (under the current implementation;
1562+
/// this does not constitute a stable guarantee), because the only
1563+
/// requirement the compiler knows about it is that the data pointer must be
1564+
/// non-null. Dropping such a `Vec<T>` however will cause undefined
1565+
/// behaviour.
1566+
///
1567+
/// [`Vec<T>`]: ../../std/vec/struct.Vec.html
1568+
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
1569+
pub unsafe fn assume_init_drop(&mut self) {
1570+
// SAFETY: the caller must guarantee that every element of `self`
1571+
// is initialized and satisfies all invariants of `T`.
1572+
// Dropping the value in place is safe if that is the case.
1573+
unsafe { ptr::drop_in_place(self as *mut [MaybeUninit<T>] as *mut [T]) }
1574+
}
1575+
1576+
/// Gets a shared reference to the contained value.
1577+
///
1578+
/// # Safety
1579+
///
1580+
/// Calling this when the content is not yet fully initialized causes undefined
1581+
/// behavior: it is up to the caller to guarantee that every `MaybeUninit<T>` in
1582+
/// the slice really is in an initialized state.
1583+
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
1584+
#[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")]
1585+
#[inline(always)]
1586+
pub const unsafe fn assume_init_ref(&self) -> &[T] {
1587+
// SAFETY: the caller must guarantee that `self` is initialized.
1588+
// This also means that `self` must be a `value` variant.
1589+
unsafe {
1590+
intrinsics::assert_inhabited::<T>();
1591+
slice::from_raw_parts(self.as_ptr().cast::<T>(), self.len())
1592+
}
1593+
}
1594+
1595+
/// Gets a mutable (unique) reference to the contained value.
1596+
///
1597+
/// # Safety
1598+
///
1599+
/// Calling this when the content is not yet fully initialized causes undefined
1600+
/// behavior: it is up to the caller to guarantee that every `MaybeUninit<T>` in the
1601+
/// slice really is in an initialized state. For instance, `.assume_init_mut()` cannot
1602+
/// be used to initialize a `MaybeUninit` slice.
1603+
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
1604+
#[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")]
1605+
#[inline(always)]
1606+
pub const unsafe fn assume_init_mut(&mut self) -> &mut [T] {
1607+
// SAFETY: the caller must guarantee that `self` is initialized.
1608+
// This also means that `self` must be a `value` variant.
1609+
unsafe {
1610+
intrinsics::assert_inhabited::<T>();
1611+
slice::from_raw_parts_mut(self.as_mut_ptr().cast::<T>(), self.len())
1612+
}
1613+
}
1614+
}
14131615

14141616
impl<T, const N: usize> MaybeUninit<[T; N]> {
14151617
/// Transposes a `MaybeUninit<[T; N]>` into a `[MaybeUninit<T>; N]`.
@@ -1460,7 +1662,7 @@ impl<'a, T> Drop for Guard<'a, T> {
14601662
let initialized_part = &mut self.slice[..self.initialized];
14611663
// SAFETY: this raw sub-slice will contain only initialized objects.
14621664
unsafe {
1463-
crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(initialized_part));
1665+
initialized_part.assume_init_drop();
14641666
}
14651667
}
14661668
}

0 commit comments

Comments
 (0)