Skip to content

Commit b09b6de

Browse files
committed
constify from_fn, try_from_fn, try_map, map
1 parent 40ace17 commit b09b6de

File tree

5 files changed

+123
-35
lines changed

5 files changed

+123
-35
lines changed

library/core/src/array/drain.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![allow(dead_code)]
12
use crate::iter::{TrustedLen, UncheckedIterator};
23
use crate::mem::ManuallyDrop;
34
use crate::ptr::drop_in_place;

library/core/src/array/mod.rs

Lines changed: 84 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ use crate::fmt;
1212
use crate::hash::{self, Hash};
1313
use crate::intrinsics::transmute_unchecked;
1414
use crate::iter::{UncheckedIterator, repeat_n};
15-
use crate::mem::{self, MaybeUninit};
15+
use crate::marker::Destruct;
16+
use crate::mem::{self, ManuallyDrop, MaybeUninit};
1617
use crate::ops::{
1718
ChangeOutputType, ControlFlow, FromResidual, Index, IndexMut, NeverShortCircuit, Residual, Try,
1819
};
@@ -24,7 +25,6 @@ mod drain;
2425
mod equality;
2526
mod iter;
2627

27-
pub(crate) use drain::drain_array_with;
2828
#[stable(feature = "array_value_iter", since = "1.51.0")]
2929
pub use iter::IntoIter;
3030

@@ -104,9 +104,10 @@ pub fn repeat<T: Clone, const N: usize>(val: T) -> [T; N] {
104104
/// ```
105105
#[inline]
106106
#[stable(feature = "array_from_fn", since = "1.63.0")]
107-
pub fn from_fn<T, const N: usize, F>(f: F) -> [T; N]
107+
#[rustc_const_unstable(feature = "const_array", issue = "none")]
108+
pub const fn from_fn<T, const N: usize, F>(f: F) -> [T; N]
108109
where
109-
F: FnMut(usize) -> T,
110+
F: [const] FnMut(usize) -> T + [const] Destruct,
110111
{
111112
try_from_fn(NeverShortCircuit::wrap_mut_1(f)).0
112113
}
@@ -142,11 +143,12 @@ where
142143
/// ```
143144
#[inline]
144145
#[unstable(feature = "array_try_from_fn", issue = "89379")]
145-
pub fn try_from_fn<R, const N: usize, F>(cb: F) -> ChangeOutputType<R, [R::Output; N]>
146+
#[rustc_const_unstable(feature = "try_from_fn", issue = "89379")]
147+
pub const fn try_from_fn<R, const N: usize, F>(cb: F) -> ChangeOutputType<R, [R::Output; N]>
146148
where
147-
F: FnMut(usize) -> R,
148-
R: Try,
149-
R::Residual: Residual<[R::Output; N]>,
149+
F: [const] FnMut(usize) -> R + [const] Destruct,
150+
R: [const] Try<Residual: Residual<[R::Output; N]>>,
151+
<R::Residual as Residual<[R::Output; N]>>::TryType: [const] Try,
150152
{
151153
let mut array = [const { MaybeUninit::uninit() }; N];
152154
match try_from_fn_erased(&mut array, cb) {
@@ -542,9 +544,10 @@ impl<T, const N: usize> [T; N] {
542544
/// ```
543545
#[must_use]
544546
#[stable(feature = "array_map", since = "1.55.0")]
545-
pub fn map<F, U>(self, f: F) -> [U; N]
547+
#[rustc_const_unstable(feature = "const_array", issue = "none")]
548+
pub const fn map<F, U>(self, f: F) -> [U; N]
546549
where
547-
F: FnMut(T) -> U,
550+
F: [const] FnMut(T) -> U + [const] Destruct,
548551
{
549552
self.try_map(NeverShortCircuit::wrap_mut_1(f)).0
550553
}
@@ -580,11 +583,60 @@ impl<T, const N: usize> [T; N] {
580583
/// assert_eq!(c, Some(a));
581584
/// ```
582585
#[unstable(feature = "array_try_map", issue = "79711")]
583-
pub fn try_map<R>(self, f: impl FnMut(T) -> R) -> ChangeOutputType<R, [R::Output; N]>
586+
#[rustc_const_unstable(feature = "array_try_map", issue = "78711")]
587+
pub const fn try_map<R, F>(self, mut f: F) -> ChangeOutputType<R, [R::Output; N]>
584588
where
585-
R: Try<Residual: Residual<[R::Output; N]>>,
589+
F: [const] FnMut(T) -> R + [const] Destruct,
590+
R: [const] Try<Residual: Residual<[R::Output; N]>>,
591+
<R::Residual as Residual<[R::Output; N]>>::TryType: [const] Try,
586592
{
587-
drain_array_with(self, |iter| try_from_trusted_iterator(iter.map(f)))
593+
#[rustc_const_unstable(feature = "array_try_map", issue = "78711")]
594+
struct Guardian<'a, T, U, const N: usize, F: FnMut(T) -> U> {
595+
array: ManuallyDrop<[T; N]>,
596+
moved: usize,
597+
f: &'a mut F,
598+
}
599+
#[rustc_const_unstable(feature = "array_try_map", issue = "78711")]
600+
impl<T, U, const N: usize, F> const FnOnce<(usize,)> for &mut Guardian<'_, T, U, N, F>
601+
where
602+
F: [const] FnMut(T) -> U,
603+
{
604+
type Output = U;
605+
606+
extern "rust-call" fn call_once(mut self, args: (usize,)) -> Self::Output {
607+
self.call_mut(args)
608+
}
609+
}
610+
#[rustc_const_unstable(feature = "array_try_map", issue = "78711")]
611+
impl<T, U, const N: usize, F> const FnMut<(usize,)> for &mut Guardian<'_, T, U, N, F>
612+
where
613+
F: [const] FnMut(T) -> U,
614+
{
615+
extern "rust-call" fn call_mut(&mut self, (x,): (usize,)) -> Self::Output {
616+
// SAFETY: increment moved before moving. if `f` panics, we drop the rest.
617+
self.moved += 1;
618+
// SAFETY: caller guarantees never called with number >= N
619+
(self.f)(unsafe { self.array.as_ptr().add(x).read() })
620+
}
621+
}
622+
#[rustc_const_unstable(feature = "array_try_map", issue = "78711")]
623+
impl<T: [const] Destruct, U, const N: usize, F: FnMut(T) -> U> const Drop
624+
for Guardian<'_, T, U, N, F>
625+
{
626+
fn drop(&mut self) {
627+
let mut n = self.moved;
628+
while n != N {
629+
// SAFETY: moved must always be < N
630+
unsafe { self.array.as_mut_ptr().add(n).drop_in_place() };
631+
n += 1;
632+
}
633+
}
634+
}
635+
let mut f = Guardian { array: ManuallyDrop::new(self), moved: 0, f: &mut f };
636+
// SAFETY: try_from_fn calls `f` with 0..N.
637+
let out = try_from_fn(&mut f);
638+
mem::forget(f); // it doesnt like being remembered
639+
out
588640
}
589641

590642
/// Returns a slice containing the entire array. Equivalent to `&s[..]`.
@@ -878,12 +930,14 @@ where
878930
/// not optimizing away. So if you give it a shot, make sure to watch what
879931
/// happens in the codegen tests.
880932
#[inline]
881-
fn try_from_fn_erased<T, R>(
933+
#[rustc_const_unstable(feature = "try_from_fn", issue = "89379")]
934+
const fn try_from_fn_erased<T, R, F>(
882935
buffer: &mut [MaybeUninit<T>],
883-
mut generator: impl FnMut(usize) -> R,
936+
mut generator: F,
884937
) -> ControlFlow<R::Residual>
885938
where
886-
R: Try<Output = T>,
939+
R: [const] Try<Output = T>,
940+
F: [const] FnMut(usize) -> R + [const] Destruct,
887941
{
888942
let mut guard = Guard { array_mut: buffer, initialized: 0 };
889943

@@ -923,7 +977,8 @@ impl<T> Guard<'_, T> {
923977
///
924978
/// No more than N elements must be initialized.
925979
#[inline]
926-
pub(crate) unsafe fn push_unchecked(&mut self, item: T) {
980+
#[rustc_const_unstable(feature = "try_from_fn", issue = "89379")]
981+
pub(crate) const unsafe fn push_unchecked(&mut self, item: T) {
927982
// SAFETY: If `initialized` was correct before and the caller does not
928983
// invoke this method more than N times then writes will be in-bounds
929984
// and slots will not be initialized more than once.
@@ -934,15 +989,21 @@ impl<T> Guard<'_, T> {
934989
}
935990
}
936991

937-
impl<T> Drop for Guard<'_, T> {
992+
#[rustc_const_unstable(feature = "try_from_fn", issue = "89379")]
993+
impl<T> const Drop for Guard<'_, T> {
938994
#[inline]
939995
fn drop(&mut self) {
940996
debug_assert!(self.initialized <= self.array_mut.len());
941-
942-
// SAFETY: this slice will contain only initialized objects.
943-
unsafe {
944-
self.array_mut.get_unchecked_mut(..self.initialized).assume_init_drop();
945-
}
997+
crate::intrinsics::const_eval_select!(
998+
@capture [T] { x: &mut Guard<'_, T> = self } -> ():
999+
if const {}
1000+
else {
1001+
// SAFETY: this slice will contain only initialized objects.
1002+
unsafe {
1003+
x.array_mut.get_unchecked_mut(..x.initialized).assume_init_drop();
1004+
}
1005+
}
1006+
);
9461007
}
9471008
}
9481009

library/core/src/ops/try_trait.rs

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::marker::{Destruct, PhantomData};
12
use crate::ops::ControlFlow;
23

34
/// The `?` operator and `try {}` blocks.
@@ -380,17 +381,36 @@ pub(crate) type ChangeOutputType<T: Try<Residual: Residual<V>>, V> =
380381
/// Not currently planned to be exposed publicly, so just `pub(crate)`.
381382
#[repr(transparent)]
382383
pub(crate) struct NeverShortCircuit<T>(pub T);
384+
pub(crate) struct Wrapped<T, A, F: FnMut(A) -> T> {
385+
f: F,
386+
p: PhantomData<(T, A)>,
387+
}
388+
#[rustc_const_unstable(feature = "const_never_short_circuit", issue = "none")]
389+
impl<T, A, F: [const] FnMut(A) -> T + [const] Destruct> const FnOnce<(A,)> for Wrapped<T, A, F> {
390+
type Output = NeverShortCircuit<T>;
391+
392+
extern "rust-call" fn call_once(mut self, args: (A,)) -> Self::Output {
393+
self.call_mut(args)
394+
}
395+
}
396+
#[rustc_const_unstable(feature = "const_never_short_circuit", issue = "none")]
397+
impl<T, A, F: [const] FnMut(A) -> T> const FnMut<(A,)> for Wrapped<T, A, F> {
398+
extern "rust-call" fn call_mut(&mut self, (args,): (A,)) -> Self::Output {
399+
NeverShortCircuit((self.f)(args))
400+
}
401+
}
383402

384403
impl<T> NeverShortCircuit<T> {
385404
/// Wraps a unary function to produce one that wraps the output into a `NeverShortCircuit`.
386405
///
387406
/// This is useful for implementing infallible functions in terms of the `try_` ones,
388407
/// without accidentally capturing extra generic parameters in a closure.
389408
#[inline]
390-
pub(crate) fn wrap_mut_1<A>(
391-
mut f: impl FnMut(A) -> T,
392-
) -> impl FnMut(A) -> NeverShortCircuit<T> {
393-
move |a| NeverShortCircuit(f(a))
409+
pub(crate) const fn wrap_mut_1<A, F>(f: F) -> Wrapped<T, A, F>
410+
where
411+
F: [const] FnMut(A) -> T,
412+
{
413+
Wrapped { f, p: PhantomData }
394414
}
395415

396416
#[inline]
@@ -401,7 +421,8 @@ impl<T> NeverShortCircuit<T> {
401421

402422
pub(crate) enum NeverShortCircuitResidual {}
403423

404-
impl<T> Try for NeverShortCircuit<T> {
424+
#[rustc_const_unstable(feature = "const_never_short_circuit", issue = "none")]
425+
impl<T> const Try for NeverShortCircuit<T> {
405426
type Output = T;
406427
type Residual = NeverShortCircuitResidual;
407428

@@ -415,15 +436,15 @@ impl<T> Try for NeverShortCircuit<T> {
415436
NeverShortCircuit(x)
416437
}
417438
}
418-
419-
impl<T> FromResidual for NeverShortCircuit<T> {
439+
#[rustc_const_unstable(feature = "const_never_short_circuit", issue = "none")]
440+
impl<T> const FromResidual for NeverShortCircuit<T> {
420441
#[inline]
421442
fn from_residual(never: NeverShortCircuitResidual) -> Self {
422443
match never {}
423444
}
424445
}
425-
426-
impl<T> Residual<T> for NeverShortCircuitResidual {
446+
#[rustc_const_unstable(feature = "const_never_short_circuit", issue = "none")]
447+
impl<T> const Residual<T> for NeverShortCircuitResidual {
427448
type TryType = NeverShortCircuit<T>;
428449
}
429450

library/core/src/ptr/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@
403403

404404
use crate::cmp::Ordering;
405405
use crate::intrinsics::const_eval_select;
406-
use crate::marker::{FnPtr, PointeeSized};
406+
use crate::marker::{Destruct, FnPtr, PointeeSized};
407407
use crate::mem::{self, MaybeUninit, SizedTypeProperties};
408408
use crate::num::NonZero;
409409
use crate::{fmt, hash, intrinsics, ub_checks};
@@ -801,7 +801,8 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
801801
#[lang = "drop_in_place"]
802802
#[allow(unconditional_recursion)]
803803
#[rustc_diagnostic_item = "ptr_drop_in_place"]
804-
pub unsafe fn drop_in_place<T: PointeeSized>(to_drop: *mut T) {
804+
#[rustc_const_unstable(feature = "const_drop_in_place", issue = "none")]
805+
pub const unsafe fn drop_in_place<T: PointeeSized + [const] Destruct>(to_drop: *mut T) {
805806
// Code here does not matter - this is replaced by the
806807
// real drop glue by the compiler.
807808

library/core/src/ptr/mut_ptr.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1390,8 +1390,12 @@ impl<T: PointeeSized> *mut T {
13901390
///
13911391
/// [`ptr::drop_in_place`]: crate::ptr::drop_in_place()
13921392
#[stable(feature = "pointer_methods", since = "1.26.0")]
1393+
#[rustc_const_unstable(feature = "const_drop_in_place", issue = "none")]
13931394
#[inline(always)]
1394-
pub unsafe fn drop_in_place(self) {
1395+
pub const unsafe fn drop_in_place(self)
1396+
where
1397+
T: [const] crate::marker::Destruct,
1398+
{
13951399
// SAFETY: the caller must uphold the safety contract for `drop_in_place`.
13961400
unsafe { drop_in_place(self) }
13971401
}

0 commit comments

Comments
 (0)