about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <476013+matthiaskrgr@users.noreply.github.com>2025-03-19 16:52:52 +0100
committerGitHub <noreply@github.com>2025-03-19 16:52:52 +0100
commitd46cc71f5488681386a3ca32fc8da5bca03264ef (patch)
tree0e6c2935691f35a7df171ce39f02691ff6bf5a4a
parenta7fc463dd8fbeca800d4b3efc501069502cffe64 (diff)
parent8269132210360e201ff9969b956c660602104cf8 (diff)
downloadrust-d46cc71f5488681386a3ca32fc8da5bca03264ef.tar.gz
rust-d46cc71f5488681386a3ca32fc8da5bca03264ef.zip
Rollup merge of #135394 - clarfonthey:uninit-slices-part-2, r=tgross35
`MaybeUninit` inherent slice methods part 2

These were moved out of #129259 since they require additional libs-api approval. Tracking issue: #117428.

New API surface:

```rust
impl<T> [MaybeUninit<T>] {
    // replacing fill; renamed to avoid conflict
    pub fn write_filled(&mut self, value: T) -> &mut [T] where T: Clone;

    // replacing fill_with; renamed to avoid conflict
    pub fn write_with<F>(&mut self, value: F) -> &mut [T] where F: FnMut() -> T;

    // renamed to remove "fill" terminology, since this is closer to the write_*_of_slice methods
    pub fn write_iter<I>(&mut self, iter: I) -> (&mut [T], &mut Self) where I: Iterator<Item = T>;
}
```

Relevant motivation for these methods; see #129259 for earlier methods' motiviations.

* I chose `write_filled` since `filled` is being used as an object here, whereas it's being used as an action in `fill`.
* I chose `write_with` instead of `write_filled_with` since it's shorter and still matches well.
* I chose `write_iter` because it feels completely different from the fill methods, and still has the intent clear.

In all of the methods, it felt appropriate to ensure that they contained `write` to clarify that they are effectively just special ways of doing `MaybeUninit::write` for each element of a slice.

Tracking issue: https://github.com/rust-lang/rust/issues/117428

r? libs-api
-rw-r--r--library/core/src/mem/maybe_uninit.rs320
-rw-r--r--library/coretests/tests/mem.rs54
-rw-r--r--library/std/src/io/util.rs3
3 files changed, 209 insertions, 168 deletions
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index ce84f105e5c..d0be82adb6b 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -1065,161 +1065,46 @@ impl<T> MaybeUninit<T> {
         this.write_clone_of_slice(src)
     }
 
-    /// Fills a slice with elements by cloning `value`, returning a mutable reference to the now
-    /// initialized contents of the slice.
-    /// Any previously initialized elements will not be dropped.
-    ///
-    /// This is similar to [`slice::fill`].
-    ///
-    /// # Panics
-    ///
-    /// This function will panic if any call to `Clone` panics.
-    ///
-    /// If such a panic occurs, any elements previously initialized during this operation will be
-    /// dropped.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(maybe_uninit_fill)]
-    /// use std::mem::MaybeUninit;
-    ///
-    /// let mut buf = [const { MaybeUninit::uninit() }; 10];
-    /// let initialized = MaybeUninit::fill(&mut buf, 1);
-    /// assert_eq!(initialized, &mut [1; 10]);
-    /// ```
-    #[doc(alias = "memset")]
+    /// Deprecated version of [`slice::write_filled`].
     #[unstable(feature = "maybe_uninit_fill", issue = "117428")]
-    pub fn fill(this: &mut [MaybeUninit<T>], value: T) -> &mut [T]
+    #[deprecated(
+        note = "replaced by inherent write_filled method; will eventually be removed",
+        since = "1.83.0"
+    )]
+    pub fn fill<'a>(this: &'a mut [MaybeUninit<T>], value: T) -> &'a mut [T]
     where
         T: Clone,
     {
-        SpecFill::spec_fill(this, value);
-        // SAFETY: Valid elements have just been filled into `this` so it is initialized
-        unsafe { this.assume_init_mut() }
+        this.write_filled(value)
     }
 
-    /// Fills a slice with elements returned by calling a closure repeatedly.
-    ///
-    /// This method uses a closure to create new values.  If you'd rather `Clone` a given value, use
-    /// [`MaybeUninit::fill`].  If you want to use the `Default` trait to generate values, you can
-    /// pass [`Default::default`] as the argument.
-    ///
-    /// # Panics
-    ///
-    /// This function will panic if any call to the provided closure panics.
-    ///
-    /// If such a panic occurs, any elements previously initialized during this operation will be
-    /// dropped.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(maybe_uninit_fill)]
-    /// use std::mem::MaybeUninit;
-    ///
-    /// let mut buf = [const { MaybeUninit::<i32>::uninit() }; 10];
-    /// let initialized = MaybeUninit::fill_with(&mut buf, Default::default);
-    /// assert_eq!(initialized, &mut [0; 10]);
-    /// ```
+    /// Deprecated version of [`slice::write_with`].
     #[unstable(feature = "maybe_uninit_fill", issue = "117428")]
-    pub fn fill_with<F>(this: &mut [MaybeUninit<T>], mut f: F) -> &mut [T]
+    #[deprecated(
+        note = "replaced by inherent write_with method; will eventually be removed",
+        since = "1.83.0"
+    )]
+    pub fn fill_with<'a, F>(this: &'a mut [MaybeUninit<T>], mut f: F) -> &'a mut [T]
     where
         F: FnMut() -> T,
     {
-        let mut guard = Guard { slice: this, initialized: 0 };
-
-        for element in guard.slice.iter_mut() {
-            element.write(f());
-            guard.initialized += 1;
-        }
-
-        super::forget(guard);
-
-        // SAFETY: Valid elements have just been written into `this` so it is initialized
-        unsafe { this.assume_init_mut() }
+        this.write_with(|_| f())
     }
 
-    /// Fills a slice with elements yielded by an iterator until either all elements have been
-    /// initialized or the iterator is empty.
-    ///
-    /// Returns two slices. The first slice contains the initialized portion of the original slice.
-    /// The second slice is the still-uninitialized remainder of the original slice.
-    ///
-    /// # Panics
-    ///
-    /// This function panics if the iterator's `next` function panics.
-    ///
-    /// If such a panic occurs, any elements previously initialized during this operation will be
-    /// dropped.
-    ///
-    /// # Examples
-    ///
-    /// Completely filling the slice:
-    ///
-    /// ```
-    /// #![feature(maybe_uninit_fill)]
-    /// use std::mem::MaybeUninit;
-    ///
-    /// let mut buf = [const { MaybeUninit::uninit() }; 5];
-    ///
-    /// let iter = [1, 2, 3].into_iter().cycle();
-    /// let (initialized, remainder) = MaybeUninit::fill_from(&mut buf, iter);
-    ///
-    /// assert_eq!(initialized, &mut [1, 2, 3, 1, 2]);
-    /// assert_eq!(remainder.len(), 0);
-    /// ```
-    ///
-    /// Partially filling the slice:
-    ///
-    /// ```
-    /// #![feature(maybe_uninit_fill)]
-    /// use std::mem::MaybeUninit;
-    ///
-    /// let mut buf = [const { MaybeUninit::uninit() }; 5];
-    /// let iter = [1, 2];
-    /// let (initialized, remainder) = MaybeUninit::fill_from(&mut buf, iter);
-    ///
-    /// assert_eq!(initialized, &mut [1, 2]);
-    /// assert_eq!(remainder.len(), 3);
-    /// ```
-    ///
-    /// Checking an iterator after filling a slice:
-    ///
-    /// ```
-    /// #![feature(maybe_uninit_fill)]
-    /// use std::mem::MaybeUninit;
-    ///
-    /// let mut buf = [const { MaybeUninit::uninit() }; 3];
-    /// let mut iter = [1, 2, 3, 4, 5].into_iter();
-    /// let (initialized, remainder) = MaybeUninit::fill_from(&mut buf, iter.by_ref());
-    ///
-    /// assert_eq!(initialized, &mut [1, 2, 3]);
-    /// assert_eq!(remainder.len(), 0);
-    /// assert_eq!(iter.as_slice(), &[4, 5]);
-    /// ```
+    /// Deprecated version of [`slice::write_iter`].
     #[unstable(feature = "maybe_uninit_fill", issue = "117428")]
-    pub fn fill_from<I>(this: &mut [MaybeUninit<T>], it: I) -> (&mut [T], &mut [MaybeUninit<T>])
+    #[deprecated(
+        note = "replaced by inherent write_iter method; will eventually be removed",
+        since = "1.83.0"
+    )]
+    pub fn fill_from<'a, I>(
+        this: &'a mut [MaybeUninit<T>],
+        it: I,
+    ) -> (&'a mut [T], &'a mut [MaybeUninit<T>])
     where
         I: IntoIterator<Item = T>,
     {
-        let iter = it.into_iter();
-        let mut guard = Guard { slice: this, initialized: 0 };
-
-        for (element, val) in guard.slice.iter_mut().zip(iter) {
-            element.write(val);
-            guard.initialized += 1;
-        }
-
-        let initialized_len = guard.initialized;
-        super::forget(guard);
-
-        // SAFETY: guard.initialized <= this.len()
-        let (initted, remainder) = unsafe { this.split_at_mut_unchecked(initialized_len) };
-
-        // SAFETY: Valid elements have just been written into `init`, so that portion
-        // of `this` is initialized.
-        (unsafe { initted.assume_init_mut() }, remainder)
+        this.write_iter(it)
     }
 
     /// Deprecated version of [`slice::as_bytes`].
@@ -1380,6 +1265,163 @@ impl<T> [MaybeUninit<T>] {
         unsafe { self.assume_init_mut() }
     }
 
+    /// Fills a slice with elements by cloning `value`, returning a mutable reference to the now
+    /// initialized contents of the slice.
+    /// Any previously initialized elements will not be dropped.
+    ///
+    /// This is similar to [`slice::fill`].
+    ///
+    /// # Panics
+    ///
+    /// This function will panic if any call to `Clone` panics.
+    ///
+    /// If such a panic occurs, any elements previously initialized during this operation will be
+    /// dropped.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(maybe_uninit_fill)]
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let mut buf = [const { MaybeUninit::uninit() }; 10];
+    /// let initialized = buf.write_filled(1);
+    /// assert_eq!(initialized, &mut [1; 10]);
+    /// ```
+    #[doc(alias = "memset")]
+    #[unstable(feature = "maybe_uninit_fill", issue = "117428")]
+    pub fn write_filled(&mut self, value: T) -> &mut [T]
+    where
+        T: Clone,
+    {
+        SpecFill::spec_fill(self, value);
+        // SAFETY: Valid elements have just been filled into `self` so it is initialized
+        unsafe { self.assume_init_mut() }
+    }
+
+    /// Fills a slice with elements returned by calling a closure for each index.
+    ///
+    /// This method uses a closure to create new values. If you'd rather `Clone` a given value, use
+    /// [`MaybeUninit::fill`]. If you want to use the `Default` trait to generate values, you can
+    /// pass [`|_| Default::default()`][Default::default] as the argument.
+    ///
+    /// # Panics
+    ///
+    /// This function will panic if any call to the provided closure panics.
+    ///
+    /// If such a panic occurs, any elements previously initialized during this operation will be
+    /// dropped.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(maybe_uninit_fill)]
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let mut buf = [const { MaybeUninit::<usize>::uninit() }; 5];
+    /// let initialized = buf.write_with(|idx| idx + 1);
+    /// assert_eq!(initialized, &mut [1, 2, 3, 4, 5]);
+    /// ```
+    #[unstable(feature = "maybe_uninit_fill", issue = "117428")]
+    pub fn write_with<F>(&mut self, mut f: F) -> &mut [T]
+    where
+        F: FnMut(usize) -> T,
+    {
+        let mut guard = Guard { slice: self, initialized: 0 };
+
+        for (idx, element) in guard.slice.iter_mut().enumerate() {
+            element.write(f(idx));
+            guard.initialized += 1;
+        }
+
+        super::forget(guard);
+
+        // SAFETY: Valid elements have just been written into `this` so it is initialized
+        unsafe { self.assume_init_mut() }
+    }
+
+    /// Fills a slice with elements yielded by an iterator until either all elements have been
+    /// initialized or the iterator is empty.
+    ///
+    /// Returns two slices. The first slice contains the initialized portion of the original slice.
+    /// The second slice is the still-uninitialized remainder of the original slice.
+    ///
+    /// # Panics
+    ///
+    /// This function panics if the iterator's `next` function panics.
+    ///
+    /// If such a panic occurs, any elements previously initialized during this operation will be
+    /// dropped.
+    ///
+    /// # Examples
+    ///
+    /// Completely filling the slice:
+    ///
+    /// ```
+    /// #![feature(maybe_uninit_fill)]
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let mut buf = [const { MaybeUninit::uninit() }; 5];
+    ///
+    /// let iter = [1, 2, 3].into_iter().cycle();
+    /// let (initialized, remainder) = buf.write_iter(iter);
+    ///
+    /// assert_eq!(initialized, &mut [1, 2, 3, 1, 2]);
+    /// assert_eq!(remainder.len(), 0);
+    /// ```
+    ///
+    /// Partially filling the slice:
+    ///
+    /// ```
+    /// #![feature(maybe_uninit_fill)]
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let mut buf = [const { MaybeUninit::uninit() }; 5];
+    /// let iter = [1, 2];
+    /// let (initialized, remainder) = buf.write_iter(iter);
+    ///
+    /// assert_eq!(initialized, &mut [1, 2]);
+    /// assert_eq!(remainder.len(), 3);
+    /// ```
+    ///
+    /// Checking an iterator after filling a slice:
+    ///
+    /// ```
+    /// #![feature(maybe_uninit_fill)]
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let mut buf = [const { MaybeUninit::uninit() }; 3];
+    /// let mut iter = [1, 2, 3, 4, 5].into_iter();
+    /// let (initialized, remainder) = buf.write_iter(iter.by_ref());
+    ///
+    /// assert_eq!(initialized, &mut [1, 2, 3]);
+    /// assert_eq!(remainder.len(), 0);
+    /// assert_eq!(iter.as_slice(), &[4, 5]);
+    /// ```
+    #[unstable(feature = "maybe_uninit_fill", issue = "117428")]
+    pub fn write_iter<I>(&mut self, it: I) -> (&mut [T], &mut [MaybeUninit<T>])
+    where
+        I: IntoIterator<Item = T>,
+    {
+        let iter = it.into_iter();
+        let mut guard = Guard { slice: self, initialized: 0 };
+
+        for (element, val) in guard.slice.iter_mut().zip(iter) {
+            element.write(val);
+            guard.initialized += 1;
+        }
+
+        let initialized_len = guard.initialized;
+        super::forget(guard);
+
+        // SAFETY: guard.initialized <= self.len()
+        let (initted, remainder) = unsafe { self.split_at_mut_unchecked(initialized_len) };
+
+        // SAFETY: Valid elements have just been written into `init`, so that portion
+        // of `this` is initialized.
+        (unsafe { initted.assume_init_mut() }, remainder)
+    }
+
     /// Returns the contents of this `MaybeUninit` as a slice of potentially uninitialized bytes.
     ///
     /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
diff --git a/library/coretests/tests/mem.rs b/library/coretests/tests/mem.rs
index 9cb94ca3b0f..9c15be4a8c4 100644
--- a/library/coretests/tests/mem.rs
+++ b/library/coretests/tests/mem.rs
@@ -1,5 +1,5 @@
 use core::mem::*;
-use core::ptr;
+use core::{array, ptr};
 #[cfg(panic = "unwind")]
 use std::rc::Rc;
 
@@ -327,11 +327,11 @@ fn uninit_write_clone_of_slice_no_drop() {
 }
 
 #[test]
-fn uninit_fill() {
+fn uninit_write_filled() {
     let mut dst = [MaybeUninit::new(255); 64];
     let expect = [0; 64];
 
-    assert_eq!(MaybeUninit::fill(&mut dst, 0), &expect);
+    assert_eq!(dst.write_filled(0), &expect);
 }
 
 #[cfg(panic = "unwind")]
@@ -352,7 +352,7 @@ impl Clone for CloneUntilPanic {
 
 #[test]
 #[cfg(panic = "unwind")]
-fn uninit_fill_clone_panic_drop() {
+fn uninit_write_filled_panic_drop() {
     use std::panic;
 
     let rc = Rc::new(());
@@ -361,7 +361,7 @@ fn uninit_fill_clone_panic_drop() {
 
     let src = CloneUntilPanic { limit: 3, rc: rc.clone() };
     let err = panic::catch_unwind(panic::AssertUnwindSafe(|| {
-        MaybeUninit::fill(&mut dst, src);
+        dst.write_filled(src);
     }));
 
     match err {
@@ -378,23 +378,23 @@ fn uninit_fill_clone_panic_drop() {
 
 #[test]
 #[cfg(panic = "unwind")]
-fn uninit_fill_clone_no_drop_clones() {
+fn uninit_write_filled_no_drop_clones() {
     let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()];
 
-    MaybeUninit::fill(&mut dst, Bomb);
+    dst.write_filled(Bomb);
 }
 
 #[test]
-fn uninit_fill_with() {
-    let mut dst = [MaybeUninit::new(255); 64];
-    let expect = [0; 64];
+fn uninit_write_with() {
+    let mut dst = [MaybeUninit::new(255usize); 64];
+    let expect = array::from_fn::<usize, 64, _>(|idx| idx);
 
-    assert_eq!(MaybeUninit::fill_with(&mut dst, || 0), &expect);
+    assert_eq!(dst.write_with(|idx| idx), &expect);
 }
 
 #[test]
 #[cfg(panic = "unwind")]
-fn uninit_fill_with_mid_panic() {
+fn uninit_write_with_mid_panic() {
     use std::panic;
 
     let rc = Rc::new(());
@@ -403,7 +403,7 @@ fn uninit_fill_with_mid_panic() {
 
     let src = CloneUntilPanic { limit: 3, rc: rc.clone() };
     let err = panic::catch_unwind(panic::AssertUnwindSafe(|| {
-        MaybeUninit::fill_with(&mut dst, || src.clone());
+        dst.write_with(|_| src.clone());
     }));
 
     drop(src);
@@ -423,58 +423,58 @@ fn uninit_fill_with_mid_panic() {
 
 #[test]
 #[cfg(panic = "unwind")]
-fn uninit_fill_with_no_drop() {
+fn uninit_write_with_no_drop() {
     let mut dst = [MaybeUninit::uninit()];
     let src = Bomb;
 
-    MaybeUninit::fill_with(&mut dst, || src.clone());
+    dst.write_with(|_| src.clone());
 
     forget(src);
 }
 
 #[test]
-fn uninit_fill_from() {
+fn uninit_write_iter() {
     let mut dst = [MaybeUninit::new(255); 64];
     let src = [0; 64];
 
-    let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter());
+    let (initted, remainder) = dst.write_iter(src.into_iter());
     assert_eq!(initted, &src);
     assert_eq!(remainder.len(), 0);
 }
 
 #[test]
-fn uninit_fill_from_partial() {
+fn uninit_write_iter_partial() {
     let mut dst = [MaybeUninit::new(255); 64];
     let src = [0; 48];
 
-    let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter());
+    let (initted, remainder) = dst.write_iter(src.into_iter());
     assert_eq!(initted, &src);
     assert_eq!(remainder.len(), 16);
 }
 
 #[test]
-fn uninit_over_fill() {
+fn uninit_write_iter_overfill() {
     let mut dst = [MaybeUninit::new(255); 64];
     let src = [0; 72];
 
-    let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter());
+    let (initted, remainder) = dst.write_iter(src.into_iter());
     assert_eq!(initted, &src[0..64]);
     assert_eq!(remainder.len(), 0);
 }
 
 #[test]
-fn uninit_empty_fill() {
+fn uninit_write_iter_empty() {
     let mut dst = [MaybeUninit::new(255); 64];
     let src = [0; 0];
 
-    let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter());
+    let (initted, remainder) = dst.write_iter(src.into_iter());
     assert_eq!(initted, &src[0..0]);
     assert_eq!(remainder.len(), 64);
 }
 
 #[test]
 #[cfg(panic = "unwind")]
-fn uninit_fill_from_mid_panic() {
+fn uninit_write_iter_mid_panic() {
     use std::panic;
 
     struct IterUntilPanic {
@@ -504,7 +504,7 @@ fn uninit_fill_from_mid_panic() {
     let src = IterUntilPanic { limit: 3, rc: rc.clone() };
 
     let err = panic::catch_unwind(panic::AssertUnwindSafe(|| {
-        MaybeUninit::fill_from(&mut dst, src);
+        dst.write_iter(src);
     }));
 
     match err {
@@ -522,11 +522,11 @@ fn uninit_fill_from_mid_panic() {
 
 #[test]
 #[cfg(panic = "unwind")]
-fn uninit_fill_from_no_drop() {
+fn uninit_write_iter_no_drop() {
     let mut dst = [MaybeUninit::uninit()];
     let src = [Bomb];
 
-    MaybeUninit::fill_from(&mut dst, src.iter());
+    dst.write_iter(src.iter());
 
     forget(src);
 }
diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs
index cb3f864fd4e..3b66dbf40b6 100644
--- a/library/std/src/io/util.rs
+++ b/library/std/src/io/util.rs
@@ -7,7 +7,6 @@ use crate::fmt;
 use crate::io::{
     self, BorrowedCursor, BufRead, IoSlice, IoSliceMut, Read, Seek, SeekFrom, SizeHint, Write,
 };
-use crate::mem::MaybeUninit;
 
 /// `Empty` ignores any data written via [`Write`], and will always be empty
 /// (returning zero bytes) when read via [`Read`].
@@ -196,7 +195,7 @@ impl Read for Repeat {
     #[inline]
     fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> io::Result<()> {
         // SAFETY: No uninit bytes are being written.
-        MaybeUninit::fill(unsafe { buf.as_mut() }, self.byte);
+        unsafe { buf.as_mut() }.write_filled(self.byte);
         // SAFETY: the entire unfilled portion of buf has been initialized.
         unsafe { buf.advance_unchecked(buf.capacity()) };
         Ok(())