@@ -12,7 +12,8 @@ use crate::fmt;
1212use crate :: hash:: { self , Hash } ;
1313use crate :: intrinsics:: transmute_unchecked;
1414use crate :: iter:: { UncheckedIterator , repeat_n} ;
15- use crate :: mem:: { self , MaybeUninit } ;
15+ use crate :: marker:: Destruct ;
16+ use crate :: mem:: { self , ManuallyDrop , MaybeUninit } ;
1617use crate :: ops:: {
1718 ChangeOutputType , ControlFlow , FromResidual , Index , IndexMut , NeverShortCircuit , Residual , Try ,
1819} ;
@@ -24,7 +25,6 @@ mod drain;
2425mod equality;
2526mod iter;
2627
27- pub ( crate ) use drain:: drain_array_with;
2828#[ stable( feature = "array_value_iter" , since = "1.51.0" ) ]
2929pub 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 ]
108109where
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 ] >
146148where
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 >
885938where
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
0 commit comments