Skip to content

Commit 0d8b555

Browse files
committed
Implement MaybeUninit::fill{,_cloned,_mut,_with,_from}
ACP: rust-lang/libs-team#156
1 parent a395214 commit 0d8b555

File tree

3 files changed

+426
-24
lines changed

3 files changed

+426
-24
lines changed

library/core/src/mem/maybe_uninit.rs

+213-17
Original file line numberDiff line numberDiff line change
@@ -1123,22 +1123,6 @@ impl<T> MaybeUninit<T> {
11231123
// unlike copy_from_slice this does not call clone_from_slice on the slice
11241124
// this is because `MaybeUninit<T: Clone>` does not implement Clone.
11251125

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

11491133
// guard is needed b/c panic might happen during a clone
1150-
let mut guard = Guard { slice: this, initialized: 0 };
1134+
let mut guard = CloneGuard { slice: this, initialized: 0 };
11511135

11521136
for i in 0..len {
11531137
guard.slice[i].write(src[i].clone());
@@ -1160,6 +1144,202 @@ impl<T> MaybeUninit<T> {
11601144
unsafe { MaybeUninit::slice_assume_init_mut(this) }
11611145
}
11621146

1147+
/// Fills `this` with elements by copying `value`, returning a reference to
1148+
/// the now initialized contents of `this`.
1149+
///
1150+
/// This is similar to [`slice::fill`] but is restricted to `Copy` values.
1151+
/// Use [`MaybeUninit::fill_cloned`] to initialize from a `Clone` value.
1152+
///
1153+
/// # Examples
1154+
///
1155+
/// ```
1156+
/// #![feature(maybe_uninit_fill)]
1157+
/// use std::mem::MaybeUninit;
1158+
///
1159+
/// let mut dst = [MaybeUninit::uninit(); 5];
1160+
/// let init = MaybeUninit::fill(&mut dst, 0u8);
1161+
///
1162+
/// assert_eq!(init, &[0, 0, 0, 0, 0]);
1163+
/// ```
1164+
#[doc(alias = "memset")]
1165+
#[unstable(feature = "maybe_uninit_fill", issue = "117428")]
1166+
pub fn fill<'a>(this: &'a mut [MaybeUninit<T>], value: T) -> &'a [T]
1167+
where
1168+
T: Copy,
1169+
{
1170+
this.fill(MaybeUninit::new(value));
1171+
// SAFETY: Valid elements have just been copied into `this` so it is initialized
1172+
unsafe { MaybeUninit::slice_assume_init_ref(this) }
1173+
}
1174+
1175+
/// Fills `this` with elements by copying `value`, returning a mutable
1176+
/// reference to the now initialized contents of `this`.
1177+
///
1178+
/// This is similar to [`slice::fill`] but is restricted to `Copy` values.
1179+
/// Use [`MaybeUninit::fill_cloned`] to initialize from a `Clone` value.
1180+
///
1181+
/// # Examples
1182+
///
1183+
/// ```
1184+
/// #![feature(maybe_uninit_fill)]
1185+
/// use std::mem::MaybeUninit;
1186+
///
1187+
/// let mut dst = [MaybeUninit::uninit(); 5];
1188+
/// let init = MaybeUninit::fill_mut(&mut dst, 0u8);
1189+
/// init[4] = 123;
1190+
///
1191+
/// assert_eq!(init, &[0, 0, 0, 0, 123]);
1192+
/// ```
1193+
#[unstable(feature = "maybe_uninit_fill", issue = "117428")]
1194+
pub fn fill_mut<'a>(this: &'a mut [MaybeUninit<T>], value: T) -> &'a mut [T]
1195+
where
1196+
T: Copy,
1197+
{
1198+
this.fill(MaybeUninit::new(value));
1199+
// SAFETY: Valid elements have just been copied into `this` so it is initialized
1200+
unsafe { MaybeUninit::slice_assume_init_mut(this) }
1201+
}
1202+
1203+
/// Fills `this` with elements by cloning `value`, returning a reference to
1204+
/// the now initialized contents of `this`. Any already initialized elements
1205+
/// will not be dropped.
1206+
///
1207+
/// This is similar to [`slice::fill`] but does not drop existing elements.
1208+
///
1209+
/// # Panics
1210+
///
1211+
/// This function will panic if the implementation of `Clone` panics.
1212+
///
1213+
/// If there is a panic, the already initialized elements will be dropped.
1214+
///
1215+
/// # Examples
1216+
///
1217+
/// ```
1218+
/// #![feature(maybe_uninit_fill)]
1219+
/// use std::mem::MaybeUninit;
1220+
///
1221+
/// let mut dst = [
1222+
/// MaybeUninit::uninit(),
1223+
/// MaybeUninit::uninit(),
1224+
/// MaybeUninit::uninit(),
1225+
/// ];
1226+
/// let msg = String::from("hello");
1227+
/// let init = MaybeUninit::fill_cloned(&mut dst, &msg);
1228+
///
1229+
/// assert_eq!(init, &["hello", "hello", "hello"]);
1230+
/// ```
1231+
#[unstable(feature = "maybe_uninit_fill", issue = "117428")]
1232+
pub fn fill_cloned<'a>(this: &'a mut [MaybeUninit<T>], value: &T) -> &'a [T]
1233+
where
1234+
T: Clone,
1235+
{
1236+
let len = this.len();
1237+
1238+
// guard is needed b/c panic might happen during a clone
1239+
let mut guard = CloneGuard { slice: this, initialized: 0 };
1240+
1241+
for i in 0..len {
1242+
guard.slice[i].write(value.clone());
1243+
guard.initialized += 1;
1244+
}
1245+
1246+
super::forget(guard);
1247+
1248+
// SAFETY: Valid elements have just been written into `this` so it is initialized
1249+
unsafe { MaybeUninit::slice_assume_init_ref(this) }
1250+
}
1251+
1252+
/// Fills `this` with elements returned by calling a closure repeatedly,
1253+
/// returning a reference to the now initialized contents of `this`. Any
1254+
/// already initialized elements will not be dropped.
1255+
///
1256+
/// This is similar to [`slice::fill_with`] but does not drop existing
1257+
/// elements.
1258+
///
1259+
/// # Panics
1260+
///
1261+
/// This function will panic if the closure panics.
1262+
///
1263+
/// If there is a panic, the already initialized elements will be dropped.
1264+
///
1265+
/// # Examples
1266+
///
1267+
/// ```
1268+
/// #![feature(maybe_uninit_fill)]
1269+
/// use std::mem::MaybeUninit;
1270+
///
1271+
/// let mut dst = [MaybeUninit::uninit(); 5];
1272+
/// let mut next = 0;
1273+
/// let init = MaybeUninit::fill_with(&mut dst, || { next += 1; next });
1274+
///
1275+
/// assert_eq!(init, &[1, 2, 3, 4, 5]);
1276+
/// ```
1277+
#[unstable(feature = "maybe_uninit_fill", issue = "117428")]
1278+
pub fn fill_with<'a, F>(this: &'a mut [MaybeUninit<T>], mut f: F) -> &'a [T]
1279+
where
1280+
F: FnMut() -> T,
1281+
{
1282+
let len = this.len();
1283+
let mut guard = CloneGuard { slice: this, initialized: 0 };
1284+
1285+
for i in 0..len {
1286+
guard.slice[i].write(f());
1287+
guard.initialized += 1;
1288+
}
1289+
1290+
super::forget(guard);
1291+
1292+
// SAFETY: Valid elements have just been written into `this` so it is initialized
1293+
unsafe { MaybeUninit::slice_assume_init_ref(this) }
1294+
}
1295+
1296+
/// Fills `this` with the contents of an iterator, returning a reference to
1297+
/// the now initialized contents of `this`. Any already initialized elements
1298+
/// will not be dropped.
1299+
///
1300+
/// # Panics
1301+
///
1302+
/// This function will panic if the iterator panics.
1303+
///
1304+
/// If there is a panic, the already initialized elements will be dropped.
1305+
///
1306+
/// # Examples
1307+
///
1308+
/// ```
1309+
/// #![feature(maybe_uninit_fill)]
1310+
/// use std::mem::MaybeUninit;
1311+
///
1312+
/// let mut dst = [MaybeUninit::uninit(); 5];
1313+
/// let mut iter = [1, 2, 3].into_iter().cycle();
1314+
/// let init = MaybeUninit::fill_from(&mut dst, iter);
1315+
///
1316+
/// assert_eq!(init, &[1, 2, 3, 1, 2]);
1317+
/// ```
1318+
#[unstable(feature = "maybe_uninit_fill", issue = "117428")]
1319+
pub fn fill_from<'a, I>(this: &'a mut [MaybeUninit<T>], mut iter: I) -> &'a [T]
1320+
where
1321+
I: Iterator<Item = T>,
1322+
{
1323+
let len = this.len();
1324+
let mut guard = CloneGuard { slice: this, initialized: 0 };
1325+
1326+
for i in 0..len {
1327+
match iter.next() {
1328+
Some(value) => {
1329+
guard.slice[i].write(value);
1330+
guard.initialized += 1;
1331+
}
1332+
None => break,
1333+
}
1334+
}
1335+
1336+
let init_len = guard.initialized;
1337+
super::forget(guard);
1338+
1339+
// SAFETY: Valid elements have just been written into `this` so it is initialized
1340+
unsafe { MaybeUninit::slice_assume_init_ref(&mut this[..init_len]) }
1341+
}
1342+
11631343
/// Returns the contents of this `MaybeUninit` as a slice of potentially uninitialized bytes.
11641344
///
11651345
/// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
@@ -1313,3 +1493,19 @@ impl<T, const N: usize> [MaybeUninit<T>; N] {
13131493
unsafe { intrinsics::transmute_unchecked(self) }
13141494
}
13151495
}
1496+
1497+
struct CloneGuard<'a, T> {
1498+
slice: &'a mut [MaybeUninit<T>],
1499+
initialized: usize,
1500+
}
1501+
1502+
impl<'a, T> Drop for CloneGuard<'a, T> {
1503+
fn drop(&mut self) {
1504+
let initialized_part = &mut self.slice[..self.initialized];
1505+
// SAFETY: this raw slice will contain only initialized objects
1506+
// that's why, it is allowed to drop it.
1507+
unsafe {
1508+
crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(initialized_part));
1509+
}
1510+
}
1511+
}

library/core/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#![feature(slice_from_ptr_range)]
5050
#![feature(slice_split_once)]
5151
#![feature(split_as_slice)]
52+
#![feature(maybe_uninit_fill)]
5253
#![feature(maybe_uninit_uninit_array)]
5354
#![feature(maybe_uninit_write_slice)]
5455
#![feature(maybe_uninit_uninit_array_transpose)]

0 commit comments

Comments
 (0)