Skip to content

Commit 313eb8f

Browse files
committed
Implement MaybeUninit::fill{,_with,_from}
ACP: rust-lang/libs-team#156 Signed-off-by: Andrew Wock <[email protected]>
1 parent 2bf78d1 commit 313eb8f

File tree

3 files changed

+376
-22
lines changed

3 files changed

+376
-22
lines changed

library/core/src/mem/maybe_uninit.rs

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

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)