Skip to content

Commit e8c7d0b

Browse files
committed
Implement MaybeUninit::fill{,_with,_from}
ACP: rust-lang/libs-team#156 Signed-off-by: Andrew Wock <ajwock@gmail.com>
1 parent 8a49772 commit e8c7d0b

File tree

3 files changed

+377
-22
lines changed

3 files changed

+377
-22
lines changed

Diff for: library/core/src/mem/maybe_uninit.rs

+187-16
Original file line numberDiff line numberDiff line change
@@ -1125,22 +1125,6 @@ impl<T> MaybeUninit<T> {
11251125
// unlike copy_from_slice this does not call clone_from_slice on the slice
11261126
// this is because `MaybeUninit<T: Clone>` does not implement Clone.
11271127

1128-
struct Guard<'a, T> {
1129-
slice: &'a mut [MaybeUninit<T>],
1130-
initialized: usize,
1131-
}
1132-
1133-
impl<'a, T> Drop for Guard<'a, T> {
1134-
fn drop(&mut self) {
1135-
let initialized_part = &mut self.slice[..self.initialized];
1136-
// SAFETY: this raw slice will contain only initialized objects
1137-
// that's why, it is allowed to drop it.
1138-
unsafe {
1139-
crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(initialized_part));
1140-
}
1141-
}
1142-
}
1143-
11441128
assert_eq!(this.len(), src.len(), "destination and source slices have different lengths");
11451129
// NOTE: We need to explicitly slice them to the same length
11461130
// for bounds checking to be elided, and the optimizer will
@@ -1162,6 +1146,152 @@ impl<T> MaybeUninit<T> {
11621146
unsafe { MaybeUninit::slice_assume_init_mut(this) }
11631147
}
11641148

1149+
/// Fills `this` with elements by cloning `value`, returning a mutable reference to the now
1150+
/// initialized contents of `this`.
1151+
/// Any previously initialized elements will not be dropped.
1152+
///
1153+
/// This is similar to [`slice::fill`].
1154+
///
1155+
/// # Panics
1156+
///
1157+
/// This function will panic if any call to `Clone` panics.
1158+
///
1159+
/// If such a panic occurs, any elements previously initialized during this operation will be
1160+
/// dropped.
1161+
///
1162+
/// # Examples
1163+
///
1164+
/// Fill an uninit vec with 1.
1165+
/// ```
1166+
/// #[feature(maybe_uninit_fill)]
1167+
/// use std::mem::MaybeUninit;
1168+
///
1169+
/// let mut buf = vec![MaybeUninit::uninit(); 10];
1170+
/// let initialized = MaybeUninit::fill(buf.as_mut_slice(), 1);
1171+
/// assert_eq!(initialized, &mut [1; 10]);
1172+
/// ```
1173+
#[doc(alias = "memset")]
1174+
#[unstable(feature = "maybe_uninit_fill", issue = "117428")]
1175+
pub fn fill<'a>(this: &'a mut [MaybeUninit<T>], value: T) -> &'a mut [T]
1176+
where
1177+
T: Clone,
1178+
{
1179+
SpecFill::spec_fill(this, value);
1180+
// SAFETY: Valid elements have just been filled into `this` so it is initialized
1181+
unsafe { MaybeUninit::slice_assume_init_mut(this) }
1182+
}
1183+
1184+
/// Fills `this` with elements returned by calling a closure repeatedly.
1185+
///
1186+
/// This method uses a closure to create new values. If you'd rather `Clone` a given value, use
1187+
/// [`MaybeUninit::fill_cloned`], or [`MaybeUninit::fill`] if the value is `Copy`. If you want
1188+
/// to use the `Default` trait to generate values, you can pass [`Default::default`] as the
1189+
/// argument.
1190+
///
1191+
/// # Panics
1192+
///
1193+
/// This function will panic if any call to the provided closure panics.
1194+
///
1195+
/// If such a panic occurs, any elements previously initialized during this operation will be
1196+
/// dropped.
1197+
///
1198+
/// # Examples
1199+
///
1200+
/// Fill an uninit vec with the default value.
1201+
/// ```
1202+
/// #[feature(maybe_uninit_fill)]
1203+
/// use std::mem::MaybeUninit;
1204+
///
1205+
/// let mut buf = vec![MaybeUninit::<i32>::uninit(); 10];
1206+
/// let initialized = MaybeUninit::fill_with(buf.as_mut_slice(), Default::default);
1207+
/// assert_eq!(initialized, &mut [1; 10]);
1208+
/// ```
1209+
#[unstable(feature = "maybe_uninit_fill", issue = "117428")]
1210+
pub fn fill_with<'a, F>(this: &'a mut [MaybeUninit<T>], mut f: F) -> &'a mut [T]
1211+
where
1212+
F: FnMut() -> T,
1213+
{
1214+
let mut guard = Guard { slice: this, initialized: 0 };
1215+
1216+
for element in guard.slice.iter_mut() {
1217+
element.write(f());
1218+
guard.initialized += 1;
1219+
}
1220+
1221+
super::forget(guard);
1222+
1223+
// SAFETY: Valid elements have just been written into `this` so it is initialized
1224+
unsafe { MaybeUninit::slice_assume_init_mut(this) }
1225+
}
1226+
1227+
/// Fills `this` with elements yielded by an iterator until either all elements have been
1228+
/// initialized or the iterator is empty.
1229+
///
1230+
/// Returns two slices. The first slice contains the initialized portion of the original slice.
1231+
/// The second slice is the still-uninitialized remainder of the original slice.
1232+
///
1233+
/// # Panics
1234+
///
1235+
/// This function panics if the iterator's `next` function panics.
1236+
///
1237+
/// If such a panic occurs, any elements previously initialized during this operation will be
1238+
/// dropped.
1239+
///
1240+
/// # Examples
1241+
///
1242+
/// Fill an uninit vec with a cycling iterator.
1243+
/// ```
1244+
/// #[feature(maybe_uninit_fill)]
1245+
/// use std::mem::MaybeUninit;
1246+
///
1247+
/// let mut buf = vec![MaybeUninit::uninit(); 5];
1248+
///
1249+
/// let iter = [1, 2, 3].into_iter().cycle();
1250+
/// let (initialized, remainder) = MaybeUninit::fill_from(&mut buf, iter);
1251+
///
1252+
/// assert_eq!(initialized, &mut [1, 2, 3, 1, 2]);
1253+
/// assert_eq!(0, remainder.len());
1254+
/// ```
1255+
///
1256+
/// Fill an uninit vec, but not completely.
1257+
/// ```
1258+
/// #[feature(maybe_uninit_fill)]
1259+
/// use std::mem::MaybeUninit;
1260+
///
1261+
/// let mut buf = vec![MaybeUninit::uninit(); 5];
1262+
/// let iter = [1, 2];
1263+
/// let (initialized, remainder) = MaybeUninit::fill_from(&mut buf, iter);
1264+
///
1265+
/// assert_eq!(initialized, &mut [1, 2]);
1266+
/// assert_eq!(remainder.len(), 3);
1267+
/// ```
1268+
#[unstable(feature = "maybe_uninit_fill", issue = "117428")]
1269+
pub fn fill_from<'a, I>(
1270+
this: &'a mut [MaybeUninit<T>],
1271+
it: I,
1272+
) -> (&'a mut [T], &'a mut [MaybeUninit<T>])
1273+
where
1274+
I: IntoIterator<Item = T>,
1275+
{
1276+
let iter = it.into_iter();
1277+
let mut guard = Guard { slice: this, initialized: 0 };
1278+
1279+
for (element, val) in guard.slice.iter_mut().zip(iter) {
1280+
element.write(val);
1281+
guard.initialized += 1;
1282+
}
1283+
1284+
let initialized_len = guard.initialized;
1285+
super::forget(guard);
1286+
1287+
// SAFETY: guard.initialized <= this.len()
1288+
let (initted, remainder) = unsafe { this.split_at_mut_unchecked(initialized_len) };
1289+
1290+
// SAFETY: Valid elements have just been written into `init`, so that portion
1291+
// of `this` is initialized.
1292+
(unsafe { MaybeUninit::slice_assume_init_mut(initted) }, remainder)
1293+
}
1294+
11651295
/// Returns the contents of this `MaybeUninit` as a slice of potentially uninitialized bytes.
11661296
///
11671297
/// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
@@ -1315,3 +1445,44 @@ impl<T, const N: usize> [MaybeUninit<T>; N] {
13151445
unsafe { intrinsics::transmute_unchecked(self) }
13161446
}
13171447
}
1448+
1449+
struct Guard<'a, T> {
1450+
slice: &'a mut [MaybeUninit<T>],
1451+
initialized: usize,
1452+
}
1453+
1454+
impl<'a, T> Drop for Guard<'a, T> {
1455+
fn drop(&mut self) {
1456+
let initialized_part = &mut self.slice[..self.initialized];
1457+
// SAFETY: this raw sub-slice will contain only initialized objects.
1458+
unsafe {
1459+
crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(initialized_part));
1460+
}
1461+
}
1462+
}
1463+
1464+
trait SpecFill<T> {
1465+
fn spec_fill(&mut self, value: T);
1466+
}
1467+
1468+
impl<T: Clone> SpecFill<T> for [MaybeUninit<T>] {
1469+
default fn spec_fill(&mut self, value: T) {
1470+
let mut guard = Guard { slice: self, initialized: 0 };
1471+
1472+
if let Some((last, elems)) = guard.slice.split_last_mut() {
1473+
for el in elems {
1474+
el.write(value.clone());
1475+
guard.initialized += 1;
1476+
}
1477+
1478+
last.write(value);
1479+
}
1480+
super::forget(guard);
1481+
}
1482+
}
1483+
1484+
impl<T: Copy> SpecFill<T> for [MaybeUninit<T>] {
1485+
fn spec_fill(&mut self, value: T) {
1486+
self.fill(MaybeUninit::new(value));
1487+
}
1488+
}

Diff for: library/core/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
#![feature(slice_from_ptr_range)]
5555
#![feature(slice_split_once)]
5656
#![feature(split_as_slice)]
57+
#![feature(maybe_uninit_fill)]
5758
#![feature(maybe_uninit_uninit_array)]
5859
#![feature(maybe_uninit_write_slice)]
5960
#![feature(maybe_uninit_uninit_array_transpose)]

0 commit comments

Comments
 (0)