From bb5506353c7202c003653a9e4b6ee6f73dfd8fb8 Mon Sep 17 00:00:00 2001 From: Alex Saveau Date: Sun, 16 Oct 2022 16:41:11 -0700 Subject: [PATCH] Tidy up maybe_uninit_write_slice API - Move methods to extensions Signed-off-by: Alex Saveau --- library/core/src/mem/maybe_uninit.rs | 292 ++++++++++++------------- library/core/tests/mem.rs | 18 +- library/proc_macro/src/bridge/arena.rs | 2 +- library/std/src/io/readbuf.rs | 2 +- library/std/src/net/display_buffer.rs | 2 +- 5 files changed, 155 insertions(+), 161 deletions(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 2ae9636762813..920c8b644a782 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -1014,154 +1014,6 @@ impl MaybeUninit { this.as_mut_ptr() as *mut T } - /// Copies the elements from `src` to `this`, returning a mutable reference to the now initialized contents of `this`. - /// - /// If `T` does not implement `Copy`, use [`write_slice_cloned`] - /// - /// This is similar to [`slice::copy_from_slice`]. - /// - /// # Panics - /// - /// This function will panic if the two slices have different lengths. - /// - /// # Examples - /// - /// ``` - /// #![feature(maybe_uninit_write_slice)] - /// use std::mem::MaybeUninit; - /// - /// let mut dst = [MaybeUninit::uninit(); 32]; - /// let src = [0; 32]; - /// - /// let init = MaybeUninit::write_slice(&mut dst, &src); - /// - /// assert_eq!(init, src); - /// ``` - /// - /// ``` - /// #![feature(maybe_uninit_write_slice)] - /// use std::mem::MaybeUninit; - /// - /// let mut vec = Vec::with_capacity(32); - /// let src = [0; 16]; - /// - /// MaybeUninit::write_slice(&mut vec.spare_capacity_mut()[..src.len()], &src); - /// - /// // SAFETY: we have just copied all the elements of len into the spare capacity - /// // the first src.len() elements of the vec are valid now. - /// unsafe { - /// vec.set_len(src.len()); - /// } - /// - /// assert_eq!(vec, src); - /// ``` - /// - /// [`write_slice_cloned`]: MaybeUninit::write_slice_cloned - #[unstable(feature = "maybe_uninit_write_slice", issue = "79995")] - pub fn write_slice<'a>(this: &'a mut [MaybeUninit], src: &[T]) -> &'a mut [T] - where - T: Copy, - { - // SAFETY: &[T] and &[MaybeUninit] have the same layout - let uninit_src: &[MaybeUninit] = unsafe { super::transmute(src) }; - - this.copy_from_slice(uninit_src); - - // SAFETY: Valid elements have just been copied into `this` so it is initialized - unsafe { MaybeUninit::slice_assume_init_mut(this) } - } - - /// Clones the elements from `src` to `this`, returning a mutable reference to the now initialized contents of `this`. - /// Any already initialized elements will not be dropped. - /// - /// If `T` implements `Copy`, use [`write_slice`] - /// - /// This is similar to [`slice::clone_from_slice`] but does not drop existing elements. - /// - /// # Panics - /// - /// This function will panic if the two slices have different lengths, or if the implementation of `Clone` panics. - /// - /// If there is a panic, the already cloned elements will be dropped. - /// - /// # Examples - /// - /// ``` - /// #![feature(maybe_uninit_write_slice)] - /// use std::mem::MaybeUninit; - /// - /// let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()]; - /// let src = ["wibbly".to_string(), "wobbly".to_string(), "timey".to_string(), "wimey".to_string(), "stuff".to_string()]; - /// - /// let init = MaybeUninit::write_slice_cloned(&mut dst, &src); - /// - /// assert_eq!(init, src); - /// ``` - /// - /// ``` - /// #![feature(maybe_uninit_write_slice)] - /// use std::mem::MaybeUninit; - /// - /// let mut vec = Vec::with_capacity(32); - /// let src = ["rust", "is", "a", "pretty", "cool", "language"]; - /// - /// MaybeUninit::write_slice_cloned(&mut vec.spare_capacity_mut()[..src.len()], &src); - /// - /// // SAFETY: we have just cloned all the elements of len into the spare capacity - /// // the first src.len() elements of the vec are valid now. - /// unsafe { - /// vec.set_len(src.len()); - /// } - /// - /// assert_eq!(vec, src); - /// ``` - /// - /// [`write_slice`]: MaybeUninit::write_slice - #[unstable(feature = "maybe_uninit_write_slice", issue = "79995")] - pub fn write_slice_cloned<'a>(this: &'a mut [MaybeUninit], src: &[T]) -> &'a mut [T] - where - T: Clone, - { - // unlike copy_from_slice this does not call clone_from_slice on the slice - // this is because `MaybeUninit` does not implement Clone. - - struct Guard<'a, T> { - slice: &'a mut [MaybeUninit], - initialized: usize, - } - - impl<'a, T> Drop for Guard<'a, T> { - fn drop(&mut self) { - let initialized_part = &mut self.slice[..self.initialized]; - // SAFETY: this raw slice will contain only initialized objects - // that's why, it is allowed to drop it. - unsafe { - crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(initialized_part)); - } - } - } - - assert_eq!(this.len(), src.len(), "destination and source slices have different lengths"); - // NOTE: We need to explicitly slice them to the same length - // for bounds checking to be elided, and the optimizer will - // generate memcpy for simple cases (for example T = u8). - let len = this.len(); - let src = &src[..len]; - - // guard is needed b/c panic might happen during a clone - let mut guard = Guard { slice: this, initialized: 0 }; - - for i in 0..len { - guard.slice[i].write(src[i].clone()); - guard.initialized += 1; - } - - super::forget(guard); - - // SAFETY: Valid elements have just been written into `this` so it is initialized - unsafe { MaybeUninit::slice_assume_init_mut(this) } - } - /// 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 @@ -1265,7 +1117,7 @@ impl MaybeUninit { /// /// let mut uninit = [MaybeUninit::::uninit(), MaybeUninit::::uninit()]; /// let uninit_bytes = MaybeUninit::slice_as_bytes_mut(&mut uninit); - /// MaybeUninit::write_slice(uninit_bytes, &[0x12, 0x34, 0x56, 0x78]); + /// uninit_bytes.write_slice(&[0x12, 0x34, 0x56, 0x78]); /// let vals = unsafe { MaybeUninit::slice_assume_init_ref(&uninit) }; /// if cfg!(target_endian = "little") { /// assert_eq!(vals, &[0x3412u16, 0x7856u16]); @@ -1321,3 +1173,145 @@ impl [MaybeUninit; N] { unsafe { super::transmute_copy(&ManuallyDrop::new(self)) } } } + +impl [MaybeUninit] { + /// Copies the elements from `src` to `this`, returning a mutable reference to the now initialized contents of `this`. + /// + /// If `T` does not implement `Copy`, use [`write_slice_cloned`](slice::write_slice_cloned) + /// + /// This is similar to [`slice::copy_from_slice`]. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths. + /// + /// # Examples + /// + /// ``` + /// #![feature(maybe_uninit_write_slice)] + /// use std::mem::MaybeUninit; + /// + /// let mut dst = [MaybeUninit::uninit(); 32]; + /// let src = [0; 32]; + /// + /// let init = dst.write_slice(&src); + /// + /// assert_eq!(init, src); + /// ``` + /// + /// ``` + /// #![feature(maybe_uninit_write_slice)] + /// let mut vec = Vec::with_capacity(32); + /// let src = [0; 16]; + /// + /// vec.spare_capacity_mut()[..src.len()].write_slice(&src); + /// + /// // SAFETY: we have just copied all the elements of len into the spare capacity + /// // the first src.len() elements of the vec are valid now. + /// unsafe { + /// vec.set_len(src.len()); + /// } + /// + /// assert_eq!(vec, src); + /// ``` + #[unstable(feature = "maybe_uninit_write_slice", issue = "79995")] + pub fn write_slice(&mut self, src: &[T]) -> &mut [T] + where + T: Copy, + { + // SAFETY: &[T] and &[MaybeUninit] have the same layout + let uninit_src: &[MaybeUninit] = unsafe { super::transmute(src) }; + + self.copy_from_slice(uninit_src); + + // SAFETY: Valid elements have just been copied into `this` so it is initialized + unsafe { MaybeUninit::slice_assume_init_mut(self) } + } + + /// Clones the elements from `src` to `this`, returning a mutable reference to the now initialized contents of `this`. + /// Any already initialized elements will not be dropped. + /// + /// If `T` implements `Copy`, use [`write_slice`](slice::write_slice) + /// + /// This is similar to [`slice::clone_from_slice`] but does not drop existing elements. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths, or if the implementation of `Clone` panics. + /// + /// If there is a panic, the already cloned elements will be dropped. + /// + /// # Examples + /// + /// ``` + /// #![feature(maybe_uninit_write_slice)] + /// use std::mem::MaybeUninit; + /// + /// let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()]; + /// let src = ["wibbly".to_string(), "wobbly".to_string(), "timey".to_string(), "wimey".to_string(), "stuff".to_string()]; + /// + /// let init = dst.write_slice_cloned(&src); + /// + /// assert_eq!(init, src); + /// ``` + /// + /// ``` + /// #![feature(maybe_uninit_write_slice)] + /// let mut vec = Vec::with_capacity(32); + /// let src = ["rust", "is", "a", "pretty", "cool", "language"]; + /// + /// vec.spare_capacity_mut()[..src.len()].write_slice_cloned(&src); + /// + /// // SAFETY: we have just cloned all the elements of len into the spare capacity + /// // the first src.len() elements of the vec are valid now. + /// unsafe { + /// vec.set_len(src.len()); + /// } + /// + /// assert_eq!(vec, src); + /// ``` + #[unstable(feature = "maybe_uninit_write_slice", issue = "79995")] + pub fn write_slice_cloned(&mut self, src: &[T]) -> &mut [T] + where + T: Clone, + { + // unlike copy_from_slice this does not call clone_from_slice on the slice + // this is because `MaybeUninit` does not implement Clone. + + struct Guard<'a, T> { + slice: &'a mut [MaybeUninit], + initialized: usize, + } + + impl<'a, T> Drop for Guard<'a, T> { + fn drop(&mut self) { + let initialized_part = &mut self.slice[..self.initialized]; + // SAFETY: this raw slice will contain only initialized objects + // that's why, it is allowed to drop it. + unsafe { + ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(initialized_part)); + } + } + } + + assert_eq!(self.len(), src.len(), "destination and source slices have different lengths"); + // NOTE: We need to explicitly slice them to the same length + // for bounds checking to be elided, and the optimizer will + // generate memcpy for simple cases (for example T = u8). + let len = self.len(); + let src = &src[..len]; + + // guard is needed b/c panic might happen during a clone + let mut guard = Guard { slice: self, initialized: 0 }; + + for i in 0..len { + guard.slice[i].write(src[i].clone()); + guard.initialized += 1; + } + + super::forget(guard); + + // SAFETY: Valid elements have just been written into `self` so it is initialized + unsafe { MaybeUninit::slice_assume_init_mut(self) } + } +} diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 6856d1a1f51ae..a9708bdccce92 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -182,7 +182,7 @@ fn uninit_write_slice() { let mut dst = [MaybeUninit::new(255); 64]; let src = [0; 64]; - assert_eq!(MaybeUninit::write_slice(&mut dst, &src), &src); + assert_eq!(dst.write_slice(&src), &src); } #[test] @@ -191,7 +191,7 @@ fn uninit_write_slice_panic_lt() { let mut dst = [MaybeUninit::uninit(); 64]; let src = [0; 32]; - MaybeUninit::write_slice(&mut dst, &src); + dst.write_slice(&src); } #[test] @@ -200,15 +200,15 @@ fn uninit_write_slice_panic_gt() { let mut dst = [MaybeUninit::uninit(); 64]; let src = [0; 128]; - MaybeUninit::write_slice(&mut dst, &src); + dst.write_slice(&src); } #[test] -fn uninit_clone_from_slice() { +fn uninit_write_slice_cloned() { let mut dst = [MaybeUninit::new(255); 64]; let src = [0; 64]; - assert_eq!(MaybeUninit::write_slice_cloned(&mut dst, &src), &src); + assert_eq!(dst.write_slice_cloned(&src), &src); } #[test] @@ -217,7 +217,7 @@ fn uninit_write_slice_cloned_panic_lt() { let mut dst = [MaybeUninit::uninit(); 64]; let src = [0; 32]; - MaybeUninit::write_slice_cloned(&mut dst, &src); + dst.write_slice_cloned(&src); } #[test] @@ -226,7 +226,7 @@ fn uninit_write_slice_cloned_panic_gt() { let mut dst = [MaybeUninit::uninit(); 64]; let src = [0; 128]; - MaybeUninit::write_slice_cloned(&mut dst, &src); + dst.write_slice_cloned(&src); } #[test] @@ -267,7 +267,7 @@ fn uninit_write_slice_cloned_mid_panic() { ]; let err = panic::catch_unwind(panic::AssertUnwindSafe(|| { - MaybeUninit::write_slice_cloned(&mut dst, &src); + dst.write_slice_cloned(&src); })); drop(src); @@ -299,7 +299,7 @@ fn uninit_write_slice_cloned_no_drop() { let mut dst = [MaybeUninit::uninit()]; let src = [Bomb]; - MaybeUninit::write_slice_cloned(&mut dst, &src); + dst.write_slice_cloned(&src); forget(src); } diff --git a/library/proc_macro/src/bridge/arena.rs b/library/proc_macro/src/bridge/arena.rs index fa72d2816ebfe..fabd4897c1542 100644 --- a/library/proc_macro/src/bridge/arena.rs +++ b/library/proc_macro/src/bridge/arena.rs @@ -104,7 +104,7 @@ impl Arena { pub(crate) fn alloc_str<'a>(&'a self, string: &str) -> &'a mut str { let alloc = self.alloc_raw(string.len()); - let bytes = MaybeUninit::write_slice(alloc, string.as_bytes()); + let bytes = alloc.write_slice(string.as_bytes()); // SAFETY: we convert from `&str` to `&[u8]`, clone it into the arena, // and immediately convert the clone back to `&str`. diff --git a/library/std/src/io/readbuf.rs b/library/std/src/io/readbuf.rs index 4800eeda022bb..0b48cd5824ef4 100644 --- a/library/std/src/io/readbuf.rs +++ b/library/std/src/io/readbuf.rs @@ -286,7 +286,7 @@ impl<'a> BorrowedCursor<'a> { // SAFETY: we do not de-initialize any of the elements of the slice unsafe { - MaybeUninit::write_slice(&mut self.as_mut()[..buf.len()], buf); + self.as_mut()[..buf.len()].write_slice(buf); } // SAFETY: We just added the entire contents of buf to the filled section. diff --git a/library/std/src/net/display_buffer.rs b/library/std/src/net/display_buffer.rs index 7aadf06e92fc6..9315ce2a32f87 100644 --- a/library/std/src/net/display_buffer.rs +++ b/library/std/src/net/display_buffer.rs @@ -30,7 +30,7 @@ impl fmt::Write for DisplayBuffer { let bytes = s.as_bytes(); if let Some(buf) = self.buf.get_mut(self.len..(self.len + bytes.len())) { - MaybeUninit::write_slice(buf, bytes); + buf.write_slice(bytes); self.len += bytes.len(); Ok(()) } else {