From 88ed708e8d23ea31a82f577046f2cb9995a211b7 Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 3 Aug 2026 13:46:42 +0200 Subject: [PATCH 1/2] core: generalize `BorrowedCursor::ensure_init` --- library/core/src/io/borrowed_buf.rs | 54 +++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/library/core/src/io/borrowed_buf.rs b/library/core/src/io/borrowed_buf.rs index 7ca6f6d8a02e8..7dac09f14e64e 100644 --- a/library/core/src/io/borrowed_buf.rs +++ b/library/core/src/io/borrowed_buf.rs @@ -2,7 +2,6 @@ use crate::fmt::{self, Debug, Formatter}; use crate::mem::{self, MaybeUninit}; -use crate::ptr; /// A borrowed buffer of initially uninitialized elements, which is incrementally filled. /// @@ -357,24 +356,57 @@ impl<'a, T: Copy> BorrowedCursor<'a, T> { } } -impl<'a> BorrowedCursor<'a, u8> { - /// Initializes all bytes in the cursor and returns them. +impl<'a, T: Default + Copy> BorrowedCursor<'a, T> { + /// Initializes all elements in the cursor with their default value and + /// returns them. #[unstable(feature = "borrowed_buf_init", issue = "160476")] #[inline] - pub fn ensure_init(&mut self) -> &mut [u8] { - // SAFETY: always in bounds and we never uninitialize these bytes. + pub fn ensure_init(&mut self) -> &mut [T] { + trait InitSpec: Default + Copy { + fn initialize(buf: &mut [MaybeUninit]); + } + + impl InitSpec for T { + default fn initialize(buf: &mut [MaybeUninit]) { + buf.write_with(|_| Self::default()); + } + } + + macro_rules! spec_zero_init { + ($ty:ty) => { + impl InitSpec for $ty { + fn initialize(buf: &mut [MaybeUninit]) { + // SAFETY: all these types can be zero-initialized. + unsafe { + buf.as_mut_ptr().write_bytes(0, buf.len()); + } + } + } + }; + } + + spec_zero_init!(i8); + spec_zero_init!(u8); + spec_zero_init!(i16); + spec_zero_init!(u16); + spec_zero_init!(i32); + spec_zero_init!(u32); + spec_zero_init!(i64); + spec_zero_init!(u64); + spec_zero_init!(i128); + spec_zero_init!(u128); + spec_zero_init!(isize); + spec_zero_init!(usize); + + // SAFETY: always in bounds and we never uninitialize these elements. let unfilled = unsafe { self.buf.buf.get_unchecked_mut(self.buf.filled..) }; if !self.buf.init { - // SAFETY: 0 is a valid value for MaybeUninit and the length matches the allocation - // since it is comes from a slice reference. - unsafe { - ptr::write_bytes(unfilled.as_mut_ptr(), 0, unfilled.len()); - } + InitSpec::initialize(unfilled); self.buf.init = true; } - // SAFETY: these bytes have just been initialized if they weren't before + // SAFETY: these elements have just been initialized if they weren't before unsafe { unfilled.assume_init_mut() } } } From 0100285a6e9d69bbc16c81af8d9037f9712c0186 Mon Sep 17 00:00:00 2001 From: joboet Date: Tue, 4 Aug 2026 16:35:31 +0200 Subject: [PATCH 2/2] core: add `slice::write_default` --- library/core/src/io/borrowed_buf.rs | 38 +-------------- library/core/src/mem/maybe_uninit.rs | 71 +++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 39 deletions(-) diff --git a/library/core/src/io/borrowed_buf.rs b/library/core/src/io/borrowed_buf.rs index 7dac09f14e64e..f2926f1ce7cf9 100644 --- a/library/core/src/io/borrowed_buf.rs +++ b/library/core/src/io/borrowed_buf.rs @@ -362,47 +362,11 @@ impl<'a, T: Default + Copy> BorrowedCursor<'a, T> { #[unstable(feature = "borrowed_buf_init", issue = "160476")] #[inline] pub fn ensure_init(&mut self) -> &mut [T] { - trait InitSpec: Default + Copy { - fn initialize(buf: &mut [MaybeUninit]); - } - - impl InitSpec for T { - default fn initialize(buf: &mut [MaybeUninit]) { - buf.write_with(|_| Self::default()); - } - } - - macro_rules! spec_zero_init { - ($ty:ty) => { - impl InitSpec for $ty { - fn initialize(buf: &mut [MaybeUninit]) { - // SAFETY: all these types can be zero-initialized. - unsafe { - buf.as_mut_ptr().write_bytes(0, buf.len()); - } - } - } - }; - } - - spec_zero_init!(i8); - spec_zero_init!(u8); - spec_zero_init!(i16); - spec_zero_init!(u16); - spec_zero_init!(i32); - spec_zero_init!(u32); - spec_zero_init!(i64); - spec_zero_init!(u64); - spec_zero_init!(i128); - spec_zero_init!(u128); - spec_zero_init!(isize); - spec_zero_init!(usize); - // SAFETY: always in bounds and we never uninitialize these elements. let unfilled = unsafe { self.buf.buf.get_unchecked_mut(self.buf.filled..) }; if !self.buf.init { - InitSpec::initialize(unfilled); + unfilled.write_default(); self.buf.init = true; } diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 9bc8b0d128d2b..6275d7cd59a2c 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -1286,8 +1286,8 @@ impl [MaybeUninit] { /// 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 - /// [slice::write_filled]. If you want to use the `Default` trait to generate values, you can - /// pass [`|_| Default::default()`][Default::default] as the argument. + /// [`slice::write_filled`]. If you want to use the `Default` trait to generate values, use + /// [`slice::write_default`]. /// /// # Panics /// @@ -1324,6 +1324,73 @@ impl [MaybeUninit] { unsafe { self.assume_init_mut() } } + /// Fills a slice with elements returned by calling [`Default::default`] for each index. + /// + /// # Panics + /// + /// This function will panic if any call to [`Default::default`] 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() }; 5]; + /// let initialized = buf.write_default(); + /// assert_eq!(initialized, &mut [0, 0, 0, 0, 0]); + /// ``` + #[unstable(feature = "maybe_uninit_fill", issue = "117428")] + pub fn write_default(&mut self) -> &mut [T] + where + T: Default, + { + trait DefaultSpec: Default { + fn write_default(buf: &mut [MaybeUninit]) -> &mut [Self]; + } + + impl DefaultSpec for T { + default fn write_default(buf: &mut [MaybeUninit]) -> &mut [Self] { + buf.write_with(|_| T::default()) + } + } + + macro_rules! spec_default_zero { + ($ty:ty) => { + impl DefaultSpec for $ty { + fn write_default(buf: &mut [MaybeUninit]) -> &mut [Self] { + // SAFETY: + // `Default::default` is equivalent to zero-initialization + // for all these types, and this initializes the entire + // slice. + unsafe { + buf.as_mut_ptr().write_bytes(0, buf.len()); + buf.assume_init_mut() + } + } + } + }; + } + + spec_default_zero!(i8); + spec_default_zero!(u8); + spec_default_zero!(i16); + spec_default_zero!(u16); + spec_default_zero!(i32); + spec_default_zero!(u32); + spec_default_zero!(i64); + spec_default_zero!(u64); + spec_default_zero!(i128); + spec_default_zero!(u128); + spec_default_zero!(isize); + spec_default_zero!(usize); + + T::write_default(self) + } + /// Fills a slice with elements yielded by an iterator until either all elements have been /// initialized or the iterator is empty. ///