Skip to content

Commit 4f6ca37

Browse files
committed
Mark and implement 'each_ref' and 'each_mut' in '[T; N]' as const;
1 parent 4fd2c8d commit 4f6ca37

File tree

1 file changed

+30
-4
lines changed

1 file changed

+30
-4
lines changed

core/src/array/mod.rs

+30-4
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ use crate::convert::Infallible;
1010
use crate::error::Error;
1111
use crate::fmt;
1212
use crate::hash::{self, Hash};
13+
use crate::intrinsics::transmute_unchecked;
1314
use crate::iter::{UncheckedIterator, repeat_n};
1415
use crate::mem::{self, MaybeUninit};
1516
use crate::ops::{
1617
ChangeOutputType, ControlFlow, FromResidual, Index, IndexMut, NeverShortCircuit, Residual, Try,
1718
};
19+
use crate::ptr::{null, null_mut};
1820
use crate::slice::{Iter, IterMut};
1921

2022
mod ascii;
@@ -606,8 +608,20 @@ impl<T, const N: usize> [T; N] {
606608
/// assert_eq!(strings.len(), 3);
607609
/// ```
608610
#[stable(feature = "array_methods", since = "1.77.0")]
609-
pub fn each_ref(&self) -> [&T; N] {
610-
from_trusted_iterator(self.iter())
611+
#[rustc_const_unstable(feature = "const_array_each_ref", issue = "133289")]
612+
pub const fn each_ref(&self) -> [&T; N] {
613+
let mut buf = [null::<T>(); N];
614+
615+
// FIXME(const-hack): We would like to simply use iterators for this (as in the original implementation), but this is not allowed in constant expressions.
616+
let mut i = 0;
617+
while i < N {
618+
buf[i] = &raw const self[i];
619+
620+
i += 1;
621+
}
622+
623+
// SAFETY: `*const T` has the same layout as `&T`, and we've also initialised each pointer as a valid reference.
624+
unsafe { transmute_unchecked(buf) }
611625
}
612626

613627
/// Borrows each element mutably and returns an array of mutable references
@@ -625,8 +639,20 @@ impl<T, const N: usize> [T; N] {
625639
/// assert_eq!(floats, [0.0, 2.7, -1.0]);
626640
/// ```
627641
#[stable(feature = "array_methods", since = "1.77.0")]
628-
pub fn each_mut(&mut self) -> [&mut T; N] {
629-
from_trusted_iterator(self.iter_mut())
642+
#[rustc_const_unstable(feature = "const_array_each_ref", issue = "133289")]
643+
pub const fn each_mut(&mut self) -> [&mut T; N] {
644+
let mut buf = [null_mut::<T>(); N];
645+
646+
// FIXME(const-hack): We would like to simply use iterators for this (as in the original implementation), but this is not allowed in constant expressions.
647+
let mut i = 0;
648+
while i < N {
649+
buf[i] = &raw mut self[i];
650+
651+
i += 1;
652+
}
653+
654+
// SAFETY: `*mut T` has the same layout as `&mut T`, and we've also initialised each pointer as a valid reference.
655+
unsafe { transmute_unchecked(buf) }
630656
}
631657

632658
/// Divides one array reference into two at an index.

0 commit comments

Comments
 (0)