@@ -11,7 +11,9 @@ use crate::fmt;
1111use crate :: hash:: { self , Hash } ;
1212use crate :: iter:: TrustedLen ;
1313use crate :: mem:: { self , MaybeUninit } ;
14- use crate :: ops:: { Index , IndexMut } ;
14+ use crate :: ops:: {
15+ ChangeOutputType , ControlFlow , FromResidual , Index , IndexMut , NeverShortCircuit , Residual , Try ,
16+ } ;
1517use crate :: slice:: { Iter , IterMut } ;
1618
1719mod equality;
4951}
5052
5153/// Creates an array `[T; N]` where each fallible array element `T` is returned by the `cb` call.
52- /// Unlike `core::array:: from_fn`, where the element creation can't fail, this version will return an error
54+ /// Unlike [` from_fn`] , where the element creation can't fail, this version will return an error
5355/// if any element creation was unsuccessful.
5456///
57+ /// The return type of this function depends on the return type of the closure.
58+ /// If you return `Result<T, E>` from the closure, you'll get a `Result<[T; N]; E>`.
59+ /// If you return `Option<T>` from the closure, you'll get an `Option<[T; N]>`.
60+ ///
5561/// # Arguments
5662///
5763/// * `cb`: Callback where the passed argument is the current array index.
@@ -60,27 +66,32 @@ where
6066///
6167/// ```rust
6268/// #![feature(array_from_fn)]
69+ /// # // Apparently these doc tests are still on edition2018
70+ /// # use std::convert::TryInto;
6371///
64- /// #[derive(Debug, PartialEq)]
65- /// enum SomeError {
66- /// Foo,
67- /// }
68- ///
69- /// let array = core::array::try_from_fn(|i| Ok::<_, SomeError>(i));
72+ /// let array: Result<[u8; 5], _> = std::array::try_from_fn(|i| i.try_into());
7073/// assert_eq!(array, Ok([0, 1, 2, 3, 4]));
7174///
72- /// let another_array = core::array::try_from_fn::<SomeError, _, (), 2>(|_| Err(SomeError::Foo));
73- /// assert_eq!(another_array, Err(SomeError::Foo));
75+ /// let array: Result<[i8; 200], _> = std::array::try_from_fn(|i| i.try_into());
76+ /// assert!(array.is_err());
77+ ///
78+ /// let array: Option<[_; 4]> = std::array::try_from_fn(|i| i.checked_add(100));
79+ /// assert_eq!(array, Some([100, 101, 102, 103]));
80+ ///
81+ /// let array: Option<[_; 4]> = std::array::try_from_fn(|i| i.checked_sub(100));
82+ /// assert_eq!(array, None);
7483/// ```
7584#[ inline]
7685#[ unstable( feature = "array_from_fn" , issue = "89379" ) ]
77- pub fn try_from_fn < E , F , T , const N : usize > ( cb : F ) -> Result < [ T ; N ] , E >
86+ pub fn try_from_fn < F , R , const N : usize > ( cb : F ) -> ChangeOutputType < R , [ R :: Output ; N ] >
7887where
79- F : FnMut ( usize ) -> Result < T , E > ,
88+ F : FnMut ( usize ) -> R ,
89+ R : Try ,
90+ R :: Residual : Residual < [ R :: Output ; N ] > ,
8091{
8192 // SAFETY: we know for certain that this iterator will yield exactly `N`
8293 // items.
83- unsafe { collect_into_array_rslt_unchecked ( & mut ( 0 ..N ) . map ( cb) ) }
94+ unsafe { try_collect_into_array_unchecked ( & mut ( 0 ..N ) . map ( cb) ) }
8495}
8596
8697/// Converts a reference to `T` into a reference to an array of length 1 (without copying).
@@ -444,6 +455,45 @@ impl<T, const N: usize> [T; N] {
444455 unsafe { collect_into_array_unchecked ( & mut IntoIterator :: into_iter ( self ) . map ( f) ) }
445456 }
446457
458+ /// A fallible function `f` applied to each element on array `self` in order to
459+ /// return an array the same size as `self` or the first error encountered.
460+ ///
461+ /// The return type of this function depends on the return type of the closure.
462+ /// If you return `Result<T, E>` from the closure, you'll get a `Result<[T; N]; E>`.
463+ /// If you return `Option<T>` from the closure, you'll get an `Option<[T; N]>`.
464+ ///
465+ /// # Examples
466+ ///
467+ /// ```
468+ /// #![feature(array_try_map)]
469+ /// let a = ["1", "2", "3"];
470+ /// let b = a.try_map(|v| v.parse::<u32>()).unwrap().map(|v| v + 1);
471+ /// assert_eq!(b, [2, 3, 4]);
472+ ///
473+ /// let a = ["1", "2a", "3"];
474+ /// let b = a.try_map(|v| v.parse::<u32>());
475+ /// assert!(b.is_err());
476+ ///
477+ /// use std::num::NonZeroU32;
478+ /// let z = [1, 2, 0, 3, 4];
479+ /// assert_eq!(z.try_map(NonZeroU32::new), None);
480+ /// let a = [1, 2, 3];
481+ /// let b = a.try_map(NonZeroU32::new);
482+ /// let c = b.map(|x| x.map(NonZeroU32::get));
483+ /// assert_eq!(c, Some(a));
484+ /// ```
485+ #[ unstable( feature = "array_try_map" , issue = "79711" ) ]
486+ pub fn try_map < F , R > ( self , f : F ) -> ChangeOutputType < R , [ R :: Output ; N ] >
487+ where
488+ F : FnMut ( T ) -> R ,
489+ R : Try ,
490+ R :: Residual : Residual < [ R :: Output ; N ] > ,
491+ {
492+ // SAFETY: we know for certain that this iterator will yield exactly `N`
493+ // items.
494+ unsafe { try_collect_into_array_unchecked ( & mut IntoIterator :: into_iter ( self ) . map ( f) ) }
495+ }
496+
447497 /// 'Zips up' two arrays into a single array of pairs.
448498 ///
449499 /// `zip()` returns a new array where every element is a tuple where the
@@ -621,42 +671,42 @@ impl<T, const N: usize> [T; N] {
621671/// Pulls `N` items from `iter` and returns them as an array. If the iterator
622672/// yields fewer than `N` items, this function exhibits undefined behavior.
623673///
624- /// See [`collect_into_array `] for more information.
674+ /// See [`try_collect_into_array `] for more information.
625675///
626676///
627677/// # Safety
628678///
629679/// It is up to the caller to guarantee that `iter` yields at least `N` items.
630680/// Violating this condition causes undefined behavior.
631- unsafe fn collect_into_array_rslt_unchecked < E , I , T , const N : usize > (
632- iter : & mut I ,
633- ) -> Result < [ T ; N ] , E >
681+ unsafe fn try_collect_into_array_unchecked < I , T , R , const N : usize > ( iter : & mut I ) -> R :: TryType
634682where
635683 // Note: `TrustedLen` here is somewhat of an experiment. This is just an
636684 // internal function, so feel free to remove if this bound turns out to be a
637685 // bad idea. In that case, remember to also remove the lower bound
638686 // `debug_assert!` below!
639- I : Iterator < Item = Result < T , E > > + TrustedLen ,
687+ I : Iterator + TrustedLen ,
688+ I :: Item : Try < Output = T , Residual = R > ,
689+ R : Residual < [ T ; N ] > ,
640690{
641691 debug_assert ! ( N <= iter. size_hint( ) . 1 . unwrap_or( usize :: MAX ) ) ;
642692 debug_assert ! ( N <= iter. size_hint( ) . 0 ) ;
643693
644694 // SAFETY: covered by the function contract.
645- unsafe { collect_into_array ( iter) . unwrap_unchecked ( ) }
695+ unsafe { try_collect_into_array ( iter) . unwrap_unchecked ( ) }
646696}
647697
648- // Infallible version of `collect_into_array_rslt_unchecked `.
698+ // Infallible version of `try_collect_into_array_unchecked `.
649699unsafe fn collect_into_array_unchecked < I , const N : usize > ( iter : & mut I ) -> [ I :: Item ; N ]
650700where
651701 I : Iterator + TrustedLen ,
652702{
653- let mut map = iter. map ( Ok :: < _ , Infallible > ) ;
703+ let mut map = iter. map ( NeverShortCircuit ) ;
654704
655705 // SAFETY: The same safety considerations w.r.t. the iterator length
656- // apply for `collect_into_array_rslt_unchecked ` as for
706+ // apply for `try_collect_into_array_unchecked ` as for
657707 // `collect_into_array_unchecked`
658- match unsafe { collect_into_array_rslt_unchecked ( & mut map) } {
659- Ok ( array) => array,
708+ match unsafe { try_collect_into_array_unchecked ( & mut map) } {
709+ NeverShortCircuit ( array) => array,
660710 }
661711}
662712
@@ -670,13 +720,15 @@ where
670720///
671721/// If `iter.next()` panicks, all items already yielded by the iterator are
672722/// dropped.
673- fn collect_into_array < E , I , T , const N : usize > ( iter : & mut I ) -> Option < Result < [ T ; N ] , E > >
723+ fn try_collect_into_array < I , T , R , const N : usize > ( iter : & mut I ) -> Option < R :: TryType >
674724where
675- I : Iterator < Item = Result < T , E > > ,
725+ I : Iterator ,
726+ I :: Item : Try < Output = T , Residual = R > ,
727+ R : Residual < [ T ; N ] > ,
676728{
677729 if N == 0 {
678730 // SAFETY: An empty array is always inhabited and has no validity invariants.
679- return unsafe { Some ( Ok ( mem:: zeroed ( ) ) ) } ;
731+ return unsafe { Some ( Try :: from_output ( mem:: zeroed ( ) ) ) } ;
680732 }
681733
682734 struct Guard < ' a , T , const N : usize > {
@@ -701,11 +753,11 @@ where
701753 let mut guard = Guard { array_mut : & mut array, initialized : 0 } ;
702754
703755 while let Some ( item_rslt) = iter. next ( ) {
704- let item = match item_rslt {
705- Err ( err ) => {
706- return Some ( Err ( err ) ) ;
756+ let item = match item_rslt. branch ( ) {
757+ ControlFlow :: Break ( r ) => {
758+ return Some ( FromResidual :: from_residual ( r ) ) ;
707759 }
708- Ok ( elem) => elem,
760+ ControlFlow :: Continue ( elem) => elem,
709761 } ;
710762
711763 // SAFETY: `guard.initialized` starts at 0, is increased by one in the
@@ -723,7 +775,7 @@ where
723775 // SAFETY: the condition above asserts that all elements are
724776 // initialized.
725777 let out = unsafe { MaybeUninit :: array_assume_init ( array) } ;
726- return Some ( Ok ( out) ) ;
778+ return Some ( Try :: from_output ( out) ) ;
727779 }
728780 }
729781
0 commit comments