Skip to content

Commit c5eae56

Browse files
committed
Auto merge of rust-lang#75490 - LukasKalbertodt:add-basic-array-methods, r=dtolnay
Add `[T; N]::each_ref` and `[T; N]::each_mut` This PR adds the methods `each_ref` and `each_mut` to `[T; N]`. The ability to add methods to arrays was added in rust-lang#75212. These two methods are particularly useful with `map` which was also added in that PR. Tracking issue: rust-lang#76118 ```rust impl<T, const N: usize> [T; N] { pub fn each_ref(&self) -> [&T; N]; pub fn each_mut(&mut self) -> [&mut T; N]; } ```
2 parents 6526e5c + 4038042 commit c5eae56

File tree

1 file changed

+72
-3
lines changed

1 file changed

+72
-3
lines changed

library/core/src/array/mod.rs

+72-3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::convert::{Infallible, TryFrom};
1212
use crate::fmt;
1313
use crate::hash::{self, Hash};
1414
use crate::marker::Unsize;
15+
use crate::mem::MaybeUninit;
1516
use crate::ops::{Index, IndexMut};
1617
use crate::slice::{Iter, IterMut};
1718

@@ -429,7 +430,6 @@ impl<T, const N: usize> [T; N] {
429430
where
430431
F: FnMut(T) -> U,
431432
{
432-
use crate::mem::MaybeUninit;
433433
struct Guard<T, const N: usize> {
434434
dst: *mut T,
435435
initialized: usize,
@@ -481,8 +481,6 @@ impl<T, const N: usize> [T; N] {
481481
/// ```
482482
#[unstable(feature = "array_zip", issue = "80094")]
483483
pub fn zip<U>(self, rhs: [U; N]) -> [(T, U); N] {
484-
use crate::mem::MaybeUninit;
485-
486484
let mut dst = MaybeUninit::uninit_array::<N>();
487485
for (i, (lhs, rhs)) in IntoIter::new(self).zip(IntoIter::new(rhs)).enumerate() {
488486
dst[i].write((lhs, rhs));
@@ -506,4 +504,75 @@ impl<T, const N: usize> [T; N] {
506504
pub fn as_mut_slice(&mut self) -> &mut [T] {
507505
self
508506
}
507+
508+
/// Borrows each element and returns an array of references with the same
509+
/// size as `self`.
510+
///
511+
///
512+
/// # Example
513+
///
514+
/// ```
515+
/// #![feature(array_methods)]
516+
///
517+
/// let floats = [3.1, 2.7, -1.0];
518+
/// let float_refs: [&f64; 3] = floats.each_ref();
519+
/// assert_eq!(float_refs, [&3.1, &2.7, &-1.0]);
520+
/// ```
521+
///
522+
/// This method is particularly useful if combined with other methods, like
523+
/// [`map`](#method.map). This way, you can can avoid moving the original
524+
/// array if its elements are not `Copy`.
525+
///
526+
/// ```
527+
/// #![feature(array_methods, array_map)]
528+
///
529+
/// let strings = ["Ferris".to_string(), "♥".to_string(), "Rust".to_string()];
530+
/// let is_ascii = strings.each_ref().map(|s| s.is_ascii());
531+
/// assert_eq!(is_ascii, [true, false, true]);
532+
///
533+
/// // We can still access the original array: it has not been moved.
534+
/// assert_eq!(strings.len(), 3);
535+
/// ```
536+
#[unstable(feature = "array_methods", issue = "76118")]
537+
pub fn each_ref(&self) -> [&T; N] {
538+
// Unlike in `map`, we don't need a guard here, as dropping a reference
539+
// is a noop.
540+
let mut out = MaybeUninit::uninit_array::<N>();
541+
for (src, dst) in self.iter().zip(&mut out) {
542+
dst.write(src);
543+
}
544+
545+
// SAFETY: All elements of `dst` are properly initialized and
546+
// `MaybeUninit<T>` has the same layout as `T`, so this cast is valid.
547+
unsafe { (&mut out as *mut _ as *mut [&T; N]).read() }
548+
}
549+
550+
/// Borrows each element mutably and returns an array of mutable references
551+
/// with the same size as `self`.
552+
///
553+
///
554+
/// # Example
555+
///
556+
/// ```
557+
/// #![feature(array_methods)]
558+
///
559+
/// let mut floats = [3.1, 2.7, -1.0];
560+
/// let float_refs: [&mut f64; 3] = floats.each_mut();
561+
/// *float_refs[0] = 0.0;
562+
/// assert_eq!(float_refs, [&mut 0.0, &mut 2.7, &mut -1.0]);
563+
/// assert_eq!(floats, [0.0, 2.7, -1.0]);
564+
/// ```
565+
#[unstable(feature = "array_methods", issue = "76118")]
566+
pub fn each_mut(&mut self) -> [&mut T; N] {
567+
// Unlike in `map`, we don't need a guard here, as dropping a reference
568+
// is a noop.
569+
let mut out = MaybeUninit::uninit_array::<N>();
570+
for (src, dst) in self.iter_mut().zip(&mut out) {
571+
dst.write(src);
572+
}
573+
574+
// SAFETY: All elements of `dst` are properly initialized and
575+
// `MaybeUninit<T>` has the same layout as `T`, so this cast is valid.
576+
unsafe { (&mut out as *mut _ as *mut [&mut T; N]).read() }
577+
}
509578
}

0 commit comments

Comments
 (0)