Skip to content

Commit 45caae8

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

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

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

0 commit comments

Comments
 (0)