diff options
| author | bors <bors@rust-lang.org> | 2020-08-13 12:43:12 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2020-08-13 12:43:12 +0000 |
| commit | a0c290f951076d781b0ff08370445517446cee05 (patch) | |
| tree | 19eb1d8ba7b30c480dddd4a86dcb3e8de42f5b91 /library/core/src/array | |
| parent | 1a7d9f52bc3545631c7485dce65b31742ef81c4d (diff) | |
| parent | af32db21c8e1b1970886eb64b9955f9590e4c445 (diff) | |
| download | rust-a0c290f951076d781b0ff08370445517446cee05.tar.gz rust-a0c290f951076d781b0ff08370445517446cee05.zip | |
Auto merge of #75212 - JulianKnodt:array_map, r=LukasKalbertodt
Add `array` lang item and `[T; N]::map(f: FnMut(T) -> S)` This introduces an `array` lang item so functions can be defined on top of `[T; N]`. This was previously not done because const-generics was not complete enough to allow for this. Now it is in a state that is usable enough to start adding functions. The function added is a monadic (I think?) map from `[T; N] -> [S; N]`. Until transmute can function on arrays, it also allocates an extra temporary array, but this can be removed at some point. r? @lcnr
Diffstat (limited to 'library/core/src/array')
| -rw-r--r-- | library/core/src/array/mod.rs | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index c0bf3833b9c..6b28ab7d755 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -364,3 +364,66 @@ macro_rules! array_impl_default { } array_impl_default! {32, T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T} + +#[cfg(not(bootstrap))] +#[lang = "array"] +impl<T, const N: usize> [T; N] { + /// Returns an array of the same size as `self`, with function `f` applied to each element + /// in order. + /// + /// # Examples + /// + /// ``` + /// #![feature(array_map)] + /// let x = [1, 2, 3]; + /// let y = x.map(|v| v + 1); + /// assert_eq!(y, [2, 3, 4]); + /// + /// let x = [1, 2, 3]; + /// let mut temp = 0; + /// let y = x.map(|v| { temp += 1; v * temp }); + /// assert_eq!(y, [1, 4, 9]); + /// + /// let x = ["Ferris", "Bueller's", "Day", "Off"]; + /// let y = x.map(|v| v.len()); + /// assert_eq!(y, [6, 9, 3, 3]); + /// ``` + #[unstable(feature = "array_map", issue = "75243")] + pub fn map<F, U>(self, mut f: F) -> [U; N] + where + F: FnMut(T) -> U, + { + use crate::mem::MaybeUninit; + struct Guard<T, const N: usize> { + dst: *mut T, + initialized: usize, + } + + impl<T, const N: usize> Drop for Guard<T, N> { + fn drop(&mut self) { + debug_assert!(self.initialized <= N); + + let initialized_part = + crate::ptr::slice_from_raw_parts_mut(self.dst, 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(initialized_part); + } + } + } + let mut dst = MaybeUninit::uninit_array::<N>(); + let mut guard: Guard<U, N> = + Guard { dst: MaybeUninit::first_ptr_mut(&mut dst), initialized: 0 }; + for (src, dst) in IntoIter::new(self).zip(&mut dst) { + dst.write(f(src)); + guard.initialized += 1; + } + // FIXME: Convert to crate::mem::transmute once it works with generics. + // unsafe { crate::mem::transmute::<[MaybeUninit<U>; 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) } + } +} |
