Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 0a00749

Browse files
committedMar 5, 2024
Implement MaybeUninit::fill{,_with,_from}
ACP: rust-lang/libs-team#156 Signed-off-by: Andrew Wock <[email protected]>
1 parent c7beecf commit 0a00749

File tree

3 files changed

+398
-22
lines changed

3 files changed

+398
-22
lines changed
 

‎library/core/src/mem/maybe_uninit.rs

Lines changed: 186 additions & 16 deletions
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

Lines changed: 1 addition & 0 deletions
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)]

‎library/core/tests/mem.rs

Lines changed: 211 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -308,21 +308,226 @@ fn uninit_write_slice_cloned_mid_panic() {
308308
}
309309
}
310310

311+
#[derive(Clone)]
312+
struct Bomb;
313+
314+
impl Drop for Bomb {
315+
fn drop(&mut self) {
316+
panic!("dropped a bomb! kaboom!")
317+
}
318+
}
319+
311320
#[test]
312321
fn uninit_write_slice_cloned_no_drop() {
313-
#[derive(Clone)]
314-
struct Bomb;
322+
let mut dst = [MaybeUninit::uninit()];
323+
let src = [Bomb];
324+
325+
MaybeUninit::clone_from_slice(&mut dst, &src);
326+
327+
forget(src);
328+
}
329+
330+
#[test]
331+
fn uninit_fill() {
332+
let mut dst = [MaybeUninit::new(255); 64];
333+
let expect = [0; 64];
334+
335+
assert_eq!(MaybeUninit::fill(&mut dst, 0), &expect);
336+
}
337+
338+
#[cfg(panic = "unwind")]
339+
struct CloneUntilPanic {
340+
limit: usize,
341+
rc: Rc<()>,
342+
}
315343

316-
impl Drop for Bomb {
317-
fn drop(&mut self) {
318-
panic!("dropped a bomb! kaboom")
344+
#[cfg(panic = "unwind")]
345+
impl Clone for CloneUntilPanic {
346+
fn clone(&self) -> Self {
347+
if Rc::strong_count(&self.rc) >= self.limit {
348+
panic!("expected panic on clone");
319349
}
350+
Self { limit: self.limit, rc: self.rc.clone() }
320351
}
352+
}
353+
354+
#[test]
355+
#[cfg(panic = "unwind")]
356+
fn uninit_fill_clone_panic_drop() {
357+
use std::panic;
358+
359+
let rc = Rc::new(());
360+
361+
let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()];
362+
363+
let src = CloneUntilPanic { limit: 3, rc: rc.clone() };
364+
let err = panic::catch_unwind(panic::AssertUnwindSafe(|| {
365+
MaybeUninit::fill(&mut dst, src);
366+
}));
367+
368+
match err {
369+
Ok(_) => unreachable!(),
370+
Err(payload) => {
371+
payload
372+
.downcast::<&'static str>()
373+
.and_then(|s| if *s == "expected panic on clone" { Ok(s) } else { Err(s) })
374+
.unwrap_or_else(|p| panic::resume_unwind(p));
375+
assert_eq!(Rc::strong_count(&rc), 1)
376+
}
377+
}
378+
}
379+
380+
#[test]
381+
#[cfg(panic = "unwind")]
382+
fn uninit_fill_clone_no_drop_clones() {
383+
let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()];
384+
385+
MaybeUninit::fill(&mut dst, Bomb);
386+
}
387+
388+
#[test]
389+
fn uninit_fill_with() {
390+
let mut dst = [MaybeUninit::new(255); 64];
391+
let expect = [0; 64];
392+
393+
assert_eq!(MaybeUninit::fill_with(&mut dst, || 0), &expect);
394+
}
395+
396+
#[test]
397+
#[cfg(panic = "unwind")]
398+
fn uninit_fill_with_mid_panic() {
399+
use std::panic;
400+
401+
let rc = Rc::new(());
402+
403+
let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()];
404+
405+
let src = CloneUntilPanic { limit: 3, rc: rc.clone() };
406+
let err = panic::catch_unwind(panic::AssertUnwindSafe(|| {
407+
MaybeUninit::fill_with(&mut dst, || src.clone());
408+
}));
409+
410+
drop(src);
411+
412+
match err {
413+
Ok(_) => unreachable!(),
414+
Err(payload) => {
415+
payload
416+
.downcast::<&'static str>()
417+
.and_then(|s| if *s == "expected panic on clone" { Ok(s) } else { Err(s) })
418+
.unwrap_or_else(|p| panic::resume_unwind(p));
321419

420+
assert_eq!(Rc::strong_count(&rc), 1)
421+
}
422+
}
423+
}
424+
425+
#[test]
426+
#[cfg(panic = "unwind")]
427+
fn uninit_fill_with_no_drop() {
428+
let mut dst = [MaybeUninit::uninit()];
429+
let src = Bomb;
430+
431+
MaybeUninit::fill_with(&mut dst, || src.clone());
432+
433+
forget(src);
434+
}
435+
436+
#[test]
437+
fn uninit_fill_from() {
438+
let mut dst = [MaybeUninit::new(255); 64];
439+
let src = [0; 64];
440+
441+
let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter());
442+
assert_eq!(initted, &src);
443+
assert_eq!(remainder.len(), 0);
444+
}
445+
446+
#[test]
447+
fn uninit_fill_from_partial() {
448+
let mut dst = [MaybeUninit::new(255); 64];
449+
let src = [0; 48];
450+
451+
let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter());
452+
assert_eq!(initted, &src);
453+
assert_eq!(remainder.len(), 16);
454+
}
455+
456+
#[test]
457+
fn uninit_over_fill() {
458+
let mut dst = [MaybeUninit::new(255); 64];
459+
let src = [0; 72];
460+
461+
let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter());
462+
assert_eq!(initted, &src[0..64]);
463+
assert_eq!(remainder.len(), 0);
464+
}
465+
466+
#[test]
467+
fn uninit_empty_fill() {
468+
let mut dst = [MaybeUninit::new(255); 64];
469+
let src = [0; 0];
470+
471+
let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter());
472+
assert_eq!(initted, &src[0..0]);
473+
assert_eq!(remainder.len(), 64);
474+
}
475+
476+
#[test]
477+
#[cfg(panic = "unwind")]
478+
fn uninit_fill_from_mid_panic() {
479+
use std::panic;
480+
481+
struct IterUntilPanic {
482+
limit: usize,
483+
rc: Rc<()>,
484+
}
485+
486+
impl Iterator for IterUntilPanic {
487+
type Item = Rc<()>;
488+
fn next(&mut self) -> Option<Self::Item> {
489+
if Rc::strong_count(&self.rc) >= self.limit {
490+
panic!("expected panic on next");
491+
}
492+
Some(self.rc.clone())
493+
}
494+
}
495+
496+
let rc = Rc::new(());
497+
498+
let mut dst = [
499+
MaybeUninit::uninit(),
500+
MaybeUninit::uninit(),
501+
MaybeUninit::uninit(),
502+
MaybeUninit::uninit(),
503+
];
504+
505+
let src = IterUntilPanic { limit: 3, rc: rc.clone() };
506+
507+
let err = panic::catch_unwind(panic::AssertUnwindSafe(|| {
508+
MaybeUninit::fill_from(&mut dst, src);
509+
}));
510+
511+
match err {
512+
Ok(_) => unreachable!(),
513+
Err(payload) => {
514+
payload
515+
.downcast::<&'static str>()
516+
.and_then(|s| if *s == "expected panic on next" { Ok(s) } else { Err(s) })
517+
.unwrap_or_else(|p| panic::resume_unwind(p));
518+
519+
assert_eq!(Rc::strong_count(&rc), 1)
520+
}
521+
}
522+
}
523+
524+
#[test]
525+
#[cfg(panic = "unwind")]
526+
fn uninit_fill_from_no_drop() {
322527
let mut dst = [MaybeUninit::uninit()];
323528
let src = [Bomb];
324529

325-
MaybeUninit::clone_from_slice(&mut dst, &src);
530+
MaybeUninit::fill_from(&mut dst, src.iter());
326531

327532
forget(src);
328533
}

0 commit comments

Comments
 (0)
Please sign in to comment.