@@ -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,14 @@ 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 > (
148+ cb : F ,
149+ ) -> <R :: Residual as Residual < [ R :: Output ; N ] > >:: TryType
146150where
147- F : FnMut ( usize ) -> R ,
148- R : Try ,
149- R :: Residual : Residual < [ R :: Output ; N ] > ,
151+ F : [ const ] FnMut ( usize ) -> R + [ const ] Destruct ,
152+ R : [ const ] Try < Residual : Residual < [ R :: Output ; N ] > > ,
153+ < R :: Residual as Residual < [ R :: Output ; N ] > > :: TryType : [ const ] Try ,
150154{
151155 let mut array = [ const { MaybeUninit :: uninit ( ) } ; N ] ;
152156 match try_from_fn_erased ( & mut array, cb) {
@@ -542,9 +546,10 @@ impl<T, const N: usize> [T; N] {
542546 /// ```
543547 #[ must_use]
544548 #[ stable( feature = "array_map" , since = "1.55.0" ) ]
545- pub fn map < F , U > ( self , f : F ) -> [ U ; N ]
549+ #[ rustc_const_unstable( feature = "const_array" , issue = "none" ) ]
550+ pub const fn map< F , U > ( self , f : F ) -> [ U ; N ]
546551 where
547- F : FnMut ( T ) -> U ,
552+ F : [ const ] FnMut ( T ) -> U + [ const ] Destruct ,
548553 {
549554 self . try_map ( NeverShortCircuit :: wrap_mut_1 ( f ) ) . 0
550555 }
@@ -580,11 +585,60 @@ impl<T, const N: usize> [T; N] {
580585 /// assert_eq!(c, Some(a));
581586 /// ```
582587 #[ unstable( feature = "array_try_map" , issue = "79711" ) ]
583- pub fn try_map < R > ( self , f : impl FnMut ( T ) -> R ) -> ChangeOutputType < R , [ R :: Output ; N ] >
588+ #[ rustc_const_unstable( feature = "array_try_map" , issue = "78711" ) ]
589+ pub const fn try_map < R , F > ( self , mut f : F ) -> <R :: Residual as Residual < [ R :: Output ; N ] > >:: TryType
584590 where
585- R : Try < Residual : Residual < [ R :: Output ; N ] > > ,
591+ F : [ const ] FnMut ( T ) -> R + [ const ] Destruct ,
592+ R : [ const ] Try < Residual : Residual < [ R :: Output ; N ] > > ,
593+ <R :: Residual as Residual < [ R :: Output ; N ] > >:: TryType : [ const ] Try ,
586594 {
587- drain_array_with ( self , |iter| try_from_trusted_iterator ( iter. map ( f) ) )
595+ #[ rustc_const_unstable ( feature = "array_try_map" , issue = "78711" ) ]
596+ struct Guardian < ' a , T , U , const N : usize , F : FnMut ( T ) -> U > {
597+ array : ManuallyDrop < [ T ; N ] > ,
598+ moved : usize ,
599+ f : & ' a mut F ,
600+ }
601+ #[ rustc_const_unstable ( feature = "array_try_map" , issue = "78711" ) ]
602+ impl <T , U , const N : usize , F > const FnOnce < ( usize , ) > for & mut Guardian < ' _ , T , U , N , F >
603+ where
604+ F : [ const ] FnMut ( T ) -> U ,
605+ {
606+ type Output = U ;
607+
608+ extern "rust-call" fn call_once ( mut self , args : ( usize, ) ) -> Self :: Output {
609+ self. call_mut ( args)
610+ }
611+ }
612+ #[ rustc_const_unstable ( feature = "array_try_map" , issue = "78711" ) ]
613+ impl<T , U , const N : usize, F > const FnMut <( usize, ) > for & mut Guardian < ' _ , T , U , N , F >
614+ where
615+ F : [ const ] FnMut ( T ) -> U ,
616+ {
617+ extern "rust-call" fn call_mut( & mut self , ( x, ) : ( usize, ) ) -> Self :: Output {
618+ // SAFETY: increment moved before moving. if `f` panics, we drop the rest.
619+ self. moved += 1 ;
620+ // SAFETY: caller guarantees never called with number >= N
621+ ( self . f) ( unsafe { self. array. as_ptr( ) . add( x) . read( ) } )
622+ }
623+ }
624+ #[ rustc_const_unstable( feature = "array_try_map" , issue = "78711" ) ]
625+ impl < T : [ const ] Destruct , U , const N : usize , F : FnMut ( T ) -> U > const Drop
626+ for Guardian < ' _ , T , U , N , F >
627+ {
628+ fn drop( & mut self ) {
629+ let mut n = self . moved;
630+ while n != N {
631+ // SAFETY: moved must always be < N
632+ unsafe { self . array. as_mut_ptr( ) . add( n) . drop_in_place( ) } ;
633+ n += 1 ;
634+ }
635+ }
636+ }
637+ let mut f = Guardian { array : ManuallyDrop :: new( self ) , moved : 0 , f : & mut f } ;
638+ // SAFETY: try_from_fn calls `f` with 0..N.
639+ let out = try_from_fn( & mut f) ;
640+ mem:: forget( f) ; // it doesnt like being remembered
641+ out
588642 }
589643
590644 /// Returns a slice containing the entire array. Equivalent to `&s[..]`.
@@ -878,12 +932,14 @@ where
878932 /// not optimizing away. So if you give it a shot, make sure to watch what
879933/// happens in the codegen tests.
880934 #[ inline]
881- fn try_from_fn_erased < T , R > (
935+ #[ rustc_const_unstable( feature = "try_from_fn", issue = "89379 ") ]
936+ const fn try_from_fn_erased<T , R , F >(
882937 buffer: & mut [ MaybeUninit <T >] ,
883- mut generator : impl FnMut ( usize ) -> R ,
938+ mut generator: F ,
884939) -> ControlFlow <R :: Residual >
885940where
886- R : Try < Output = T > ,
941+ R : [ const ] Try <Output = T >,
942+ F : [ const ] FnMut ( usize ) -> R + [ const ] Destruct ,
887943{
888944 let mut guard = Guard { array_mut: buffer, initialized: 0 } ;
889945
@@ -923,7 +979,8 @@ impl<T> Guard<'_, T> {
923979 ///
924980 /// No more than N elements must be initialized.
925981 #[ inline]
926- pub ( crate ) unsafe fn push_unchecked ( & mut self , item : T ) {
982+ #[ rustc_const_unstable( feature = "try_from_fn", issue = "89379 ") ]
983+ pub ( crate ) const unsafe fn push_unchecked( & mut self , item: T ) {
927984 // SAFETY: If `initialized` was correct before and the caller does not
928985 // invoke this method more than N times then writes will be in-bounds
929986 // and slots will not be initialized more than once.
@@ -934,15 +991,21 @@ impl<T> Guard<'_, T> {
934991 }
935992}
936993
937- impl < T > Drop for Guard < ' _ , T > {
994+ #[ rustc_const_unstable( feature = "try_from_fn", issue = "89379 ") ]
995+ impl <T > const Drop for Guard <' _, T > {
938996 #[ inline]
939997 fn drop( & mut self ) {
940998 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- }
999+ crate :: intrinsics:: const_eval_select!(
1000+ @capture [ T ] { x: & mut Guard <' _, T > = self } -> ( ) :
1001+ if const { }
1002+ else {
1003+ // SAFETY: this slice will contain only initialized objects.
1004+ unsafe {
1005+ x. array_mut. get_unchecked_mut( ..x. initialized) . assume_init_drop( ) ;
1006+ }
1007+ }
1008+ ) ;
9461009 }
9471010}
9481011
0 commit comments