From d6db2de65178d048e4956bfa893b4cea7118f5fd Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 1 Sep 2020 22:32:42 -0700 Subject: [PATCH 1/2] Add <[T; N]>::copied --- library/core/src/array/mod.rs | 81 +++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 4 deletions(-) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index f85be5584e3f1..7ad8cb7feffcb 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -12,6 +12,7 @@ use crate::convert::{Infallible, TryFrom}; use crate::fmt; use crate::hash::{self, Hash}; use crate::marker::Unsize; +use crate::mem::MaybeUninit; use crate::slice::{Iter, IterMut}; mod iter; @@ -389,7 +390,6 @@ impl [T; N] { where F: FnMut(T) -> U, { - use crate::mem::MaybeUninit; struct Guard { dst: *mut T, initialized: usize, @@ -415,11 +415,84 @@ impl [T; N] { dst.write(f(src)); guard.initialized += 1; } - // FIXME: Convert to crate::mem::transmute once it works with generics. - // unsafe { crate::mem::transmute::<[MaybeUninit; N], [U; N]>(dst) } crate::mem::forget(guard); // SAFETY: At this point we've properly initialized the whole array // and we just need to cast it to the correct type. - unsafe { crate::mem::transmute_copy::<_, [U; N]>(&dst) } + unsafe { assume_init_array(dst) } + } + + /// Maps an `[&T; N]` or `[&mut T; N]` to a `[T; N]` by copying the contents of the array. + /// + /// # Examples + /// + /// ``` + /// #![feature(array_methods)] + /// + /// let x = 12; + /// let ref_array = [&x, &2, &3]; + /// let copied = ref_array.copied(); + /// assert_eq!(copied, [12, 2, 3]); + /// ``` + /// + /// ``` + /// #![feature(array_methods)] + /// + /// let mut x = 12; + /// let ref_array = [&mut x, &mut 2, &mut 3]; + /// let copied = ref_array.copied(); + /// assert_eq!(copied, [12, 2, 3]); + /// + /// *ref_array[0] += 1; + /// let copied_again = ref_array.copied(); + /// assert_eq!(copied_again, [13, 2, 3]); + /// ``` + #[unstable(feature = "array_methods", issue = "76118")] + pub fn copied(&self) -> [::Pointee; N] + where T: Reference + { + // No guard needed here because these are all bitwise copies, which cannot fail. + // (And things that are `Copy` can't be `Drop` anyway.) + let mut dst = MaybeUninit::uninit_array::(); + for i in 0..N { + dst[i].write(self[i].copy()); + } + + // SAFETY: all N elements were initialized above + unsafe { assume_init_array(dst) } + } +} + +/// A convenience wrapper around `transmute` for better readability in the other methods. +/// +/// Safety: +/// - Requires that all N elements of the array have been initialized +unsafe fn assume_init_array(a: [MaybeUninit; N]) -> [T; N] { + // FIXME: Convert to crate::mem::transmute once it works with generics. + // unsafe { crate::mem::transmute(a) } + unsafe { crate::mem::transmute_copy(&a) } +} + +// This allows us to implement methods like `copied` and `cloned` above +// without needing to add support for 2 new interent impl blocks. +use temporary_hacks::Reference; +mod temporary_hacks { + #[unstable(feature = "temporary_hacks", issue = "none")] + pub trait Reference { + #[unstable(feature = "temporary_hacks", issue = "none")] + type Pointee; + #[unstable(feature = "temporary_hacks", issue = "none")] + fn copy(&self) -> Self::Pointee where Self::Pointee: Copy; + } + + #[unstable(feature = "temporary_hacks", issue = "none")] + impl Reference for &T { + type Pointee = T; + fn copy(&self) -> T where T: Copy { **self } + } + + #[unstable(feature = "temporary_hacks", issue = "none")] + impl Reference for &mut T { + type Pointee = T; + fn copy(&self) -> T where T: Copy { **self } } } From 779369805bfe364c1d7c494ccabf48a48f20abec Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 1 Sep 2020 23:07:10 -0700 Subject: [PATCH 2/2] Gah, tidy makes the code so long :( --- library/core/src/array/mod.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 7ad8cb7feffcb..08b1b5afd4055 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -448,7 +448,8 @@ impl [T; N] { /// ``` #[unstable(feature = "array_methods", issue = "76118")] pub fn copied(&self) -> [::Pointee; N] - where T: Reference + where + T: Reference, { // No guard needed here because these are all bitwise copies, which cannot fail. // (And things that are `Copy` can't be `Drop` anyway.) @@ -469,6 +470,7 @@ impl [T; N] { unsafe fn assume_init_array(a: [MaybeUninit; N]) -> [T; N] { // FIXME: Convert to crate::mem::transmute once it works with generics. // unsafe { crate::mem::transmute(a) } + // SAFETY: layouts are guaranteed compatible unsafe { crate::mem::transmute_copy(&a) } } @@ -481,18 +483,30 @@ mod temporary_hacks { #[unstable(feature = "temporary_hacks", issue = "none")] type Pointee; #[unstable(feature = "temporary_hacks", issue = "none")] - fn copy(&self) -> Self::Pointee where Self::Pointee: Copy; + fn copy(&self) -> Self::Pointee + where + Self::Pointee: Copy; } #[unstable(feature = "temporary_hacks", issue = "none")] impl Reference for &T { type Pointee = T; - fn copy(&self) -> T where T: Copy { **self } + fn copy(&self) -> T + where + T: Copy, + { + **self + } } #[unstable(feature = "temporary_hacks", issue = "none")] impl Reference for &mut T { type Pointee = T; - fn copy(&self) -> T where T: Copy { **self } + fn copy(&self) -> T + where + T: Copy, + { + **self + } } }