@@ -11,7 +11,9 @@ use crate::fmt;
11
11
use crate :: hash:: { self , Hash } ;
12
12
use crate :: iter:: TrustedLen ;
13
13
use crate :: mem:: { self , MaybeUninit } ;
14
- use crate :: ops:: { Index , IndexMut } ;
14
+ use crate :: ops:: {
15
+ ChangeOutputType , ControlFlow , FromResidual , Index , IndexMut , NeverShortCircuit , Residual , Try ,
16
+ } ;
15
17
use crate :: slice:: { Iter , IterMut } ;
16
18
17
19
mod equality;
49
51
}
50
52
51
53
/// 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
53
55
/// if any element creation was unsuccessful.
54
56
///
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
+ ///
55
61
/// # Arguments
56
62
///
57
63
/// * `cb`: Callback where the passed argument is the current array index.
@@ -60,27 +66,32 @@ where
60
66
///
61
67
/// ```rust
62
68
/// #![feature(array_from_fn)]
69
+ /// # // Apparently these doc tests are still on edition2018
70
+ /// # use std::convert::TryInto;
63
71
///
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());
70
73
/// assert_eq!(array, Ok([0, 1, 2, 3, 4]));
71
74
///
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);
74
83
/// ```
75
84
#[ inline]
76
85
#[ 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 ] >
78
87
where
79
- F : FnMut ( usize ) -> Result < T , E > ,
88
+ F : FnMut ( usize ) -> R ,
89
+ R : Try ,
90
+ R :: Residual : Residual < [ R :: Output ; N ] > ,
80
91
{
81
92
// SAFETY: we know for certain that this iterator will yield exactly `N`
82
93
// 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) ) }
84
95
}
85
96
86
97
/// 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] {
444
455
unsafe { collect_into_array_unchecked ( & mut IntoIterator :: into_iter ( self ) . map ( f) ) }
445
456
}
446
457
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
+
447
497
/// 'Zips up' two arrays into a single array of pairs.
448
498
///
449
499
/// `zip()` returns a new array where every element is a tuple where the
@@ -621,42 +671,42 @@ impl<T, const N: usize> [T; N] {
621
671
/// Pulls `N` items from `iter` and returns them as an array. If the iterator
622
672
/// yields fewer than `N` items, this function exhibits undefined behavior.
623
673
///
624
- /// See [`collect_into_array `] for more information.
674
+ /// See [`try_collect_into_array `] for more information.
625
675
///
626
676
///
627
677
/// # Safety
628
678
///
629
679
/// It is up to the caller to guarantee that `iter` yields at least `N` items.
630
680
/// 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
634
682
where
635
683
// Note: `TrustedLen` here is somewhat of an experiment. This is just an
636
684
// internal function, so feel free to remove if this bound turns out to be a
637
685
// bad idea. In that case, remember to also remove the lower bound
638
686
// `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 ] > ,
640
690
{
641
691
debug_assert ! ( N <= iter. size_hint( ) . 1 . unwrap_or( usize :: MAX ) ) ;
642
692
debug_assert ! ( N <= iter. size_hint( ) . 0 ) ;
643
693
644
694
// SAFETY: covered by the function contract.
645
- unsafe { collect_into_array ( iter) . unwrap_unchecked ( ) }
695
+ unsafe { try_collect_into_array ( iter) . unwrap_unchecked ( ) }
646
696
}
647
697
648
- // Infallible version of `collect_into_array_rslt_unchecked `.
698
+ // Infallible version of `try_collect_into_array_unchecked `.
649
699
unsafe fn collect_into_array_unchecked < I , const N : usize > ( iter : & mut I ) -> [ I :: Item ; N ]
650
700
where
651
701
I : Iterator + TrustedLen ,
652
702
{
653
- let mut map = iter. map ( Ok :: < _ , Infallible > ) ;
703
+ let mut map = iter. map ( NeverShortCircuit ) ;
654
704
655
705
// 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
657
707
// `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,
660
710
}
661
711
}
662
712
@@ -670,13 +720,15 @@ where
670
720
///
671
721
/// If `iter.next()` panicks, all items already yielded by the iterator are
672
722
/// 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 >
674
724
where
675
- I : Iterator < Item = Result < T , E > > ,
725
+ I : Iterator ,
726
+ I :: Item : Try < Output = T , Residual = R > ,
727
+ R : Residual < [ T ; N ] > ,
676
728
{
677
729
if N == 0 {
678
730
// 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 ( ) ) ) } ;
680
732
}
681
733
682
734
struct Guard < ' a , T , const N : usize > {
@@ -701,11 +753,11 @@ where
701
753
let mut guard = Guard { array_mut : & mut array, initialized : 0 } ;
702
754
703
755
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 ) ) ;
707
759
}
708
- Ok ( elem) => elem,
760
+ ControlFlow :: Continue ( elem) => elem,
709
761
} ;
710
762
711
763
// SAFETY: `guard.initialized` starts at 0, is increased by one in the
@@ -723,7 +775,7 @@ where
723
775
// SAFETY: the condition above asserts that all elements are
724
776
// initialized.
725
777
let out = unsafe { MaybeUninit :: array_assume_init ( array) } ;
726
- return Some ( Ok ( out) ) ;
778
+ return Some ( Try :: from_output ( out) ) ;
727
779
}
728
780
}
729
781
0 commit comments