@@ -20,6 +20,69 @@ mod iter;
20
20
#[ stable( feature = "array_value_iter" , since = "1.51.0" ) ]
21
21
pub use iter:: IntoIter ;
22
22
23
+ /// Creates an array `[T; N]` where each array element `T` is returned by the `cb` call.
24
+ ///
25
+ /// # Arguments
26
+ ///
27
+ /// * `cb`: Callback where the passed argument is the current array index.
28
+ ///
29
+ /// # Example
30
+ ///
31
+ /// ```rust
32
+ /// #![feature(array_from_fn)]
33
+ ///
34
+ /// let array = core::array::from_fn(|i| i);
35
+ /// assert_eq!(array, [0, 1, 2, 3, 4]);
36
+ /// ```
37
+ #[ inline]
38
+ #[ unstable( feature = "array_from_fn" , issue = "89379" ) ]
39
+ pub fn from_fn < F , T , const N : usize > ( mut cb : F ) -> [ T ; N ]
40
+ where
41
+ F : FnMut ( usize ) -> T ,
42
+ {
43
+ let mut idx = 0 ;
44
+ [ ( ) ; N ] . map ( |_| {
45
+ let res = cb ( idx) ;
46
+ idx += 1 ;
47
+ res
48
+ } )
49
+ }
50
+
51
+ /// 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
53
+ /// if any element creation was unsuccessful.
54
+ ///
55
+ /// # Arguments
56
+ ///
57
+ /// * `cb`: Callback where the passed argument is the current array index.
58
+ ///
59
+ /// # Example
60
+ ///
61
+ /// ```rust
62
+ /// #![feature(array_from_fn)]
63
+ ///
64
+ /// #[derive(Debug, PartialEq)]
65
+ /// enum SomeError {
66
+ /// Foo,
67
+ /// }
68
+ ///
69
+ /// let array = core::array::try_from_fn(|i| Ok::<_, SomeError>(i));
70
+ /// assert_eq!(array, Ok([0, 1, 2, 3, 4]));
71
+ ///
72
+ /// let another_array = core::array::try_from_fn::<SomeError, _, (), 2>(|_| Err(SomeError::Foo));
73
+ /// assert_eq!(another_array, Err(SomeError::Foo));
74
+ /// ```
75
+ #[ inline]
76
+ #[ 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 >
78
+ where
79
+ F : FnMut ( usize ) -> Result < T , E > ,
80
+ {
81
+ // SAFETY: we know for certain that this iterator will yield exactly `N`
82
+ // items.
83
+ unsafe { collect_into_array_rslt_unchecked ( & mut ( 0 ..N ) . map ( cb) ) }
84
+ }
85
+
23
86
/// Converts a reference to `T` into a reference to an array of length 1 (without copying).
24
87
#[ stable( feature = "array_from_ref" , since = "1.53.0" ) ]
25
88
pub fn from_ref < T > ( s : & T ) -> & [ T ; 1 ] {
@@ -448,13 +511,15 @@ impl<T, const N: usize> [T; N] {
448
511
///
449
512
/// It is up to the caller to guarantee that `iter` yields at least `N` items.
450
513
/// Violating this condition causes undefined behavior.
451
- unsafe fn collect_into_array_unchecked < I , const N : usize > ( iter : & mut I ) -> [ I :: Item ; N ]
514
+ unsafe fn collect_into_array_rslt_unchecked < E , I , T , const N : usize > (
515
+ iter : & mut I ,
516
+ ) -> Result < [ T ; N ] , E >
452
517
where
453
518
// Note: `TrustedLen` here is somewhat of an experiment. This is just an
454
519
// internal function, so feel free to remove if this bound turns out to be a
455
520
// bad idea. In that case, remember to also remove the lower bound
456
521
// `debug_assert!` below!
457
- I : Iterator + TrustedLen ,
522
+ I : Iterator < Item = Result < T , E > > + TrustedLen ,
458
523
{
459
524
debug_assert ! ( N <= iter. size_hint( ) . 1 . unwrap_or( usize :: MAX ) ) ;
460
525
debug_assert ! ( N <= iter. size_hint( ) . 0 ) ;
@@ -463,6 +528,18 @@ where
463
528
unsafe { collect_into_array ( iter) . unwrap_unchecked ( ) }
464
529
}
465
530
531
+ // Infallible version of `collect_into_array_rslt_unchecked`.
532
+ unsafe fn collect_into_array_unchecked < I , const N : usize > ( iter : & mut I ) -> [ I :: Item ; N ]
533
+ where
534
+ I : Iterator + TrustedLen ,
535
+ {
536
+ let mut map = iter. map ( |el| Ok :: < _ , Infallible > ( el) ) ;
537
+
538
+ // SAFETY: Valid array elements are covered by the fact that all passed values
539
+ // to `collect_into_array` are `Ok`.
540
+ unsafe { collect_into_array_rslt_unchecked ( & mut map) . unwrap_unchecked ( ) }
541
+ }
542
+
466
543
/// Pulls `N` items from `iter` and returns them as an array. If the iterator
467
544
/// yields fewer than `N` items, `None` is returned and all already yielded
468
545
/// items are dropped.
@@ -473,13 +550,13 @@ where
473
550
///
474
551
/// If `iter.next()` panicks, all items already yielded by the iterator are
475
552
/// dropped.
476
- fn collect_into_array < I , const N : usize > ( iter : & mut I ) -> Option < [ I :: Item ; N ] >
553
+ fn collect_into_array < E , I , T , const N : usize > ( iter : & mut I ) -> Option < Result < [ T ; N ] , E > >
477
554
where
478
- I : Iterator ,
555
+ I : Iterator < Item = Result < T , E > > ,
479
556
{
480
557
if N == 0 {
481
558
// SAFETY: An empty array is always inhabited and has no validity invariants.
482
- return unsafe { Some ( mem:: zeroed ( ) ) } ;
559
+ return unsafe { Some ( Ok ( mem:: zeroed ( ) ) ) } ;
483
560
}
484
561
485
562
struct Guard < T , const N : usize > {
@@ -504,7 +581,14 @@ where
504
581
let mut guard: Guard < _ , N > =
505
582
Guard { ptr : MaybeUninit :: slice_as_mut_ptr ( & mut array) , initialized : 0 } ;
506
583
507
- while let Some ( item) = iter. next ( ) {
584
+ while let Some ( item_rslt) = iter. next ( ) {
585
+ let item = match item_rslt {
586
+ Err ( err) => {
587
+ return Some ( Err ( err) ) ;
588
+ }
589
+ Ok ( elem) => elem,
590
+ } ;
591
+
508
592
// SAFETY: `guard.initialized` starts at 0, is increased by one in the
509
593
// loop and the loop is aborted once it reaches N (which is
510
594
// `array.len()`).
@@ -520,7 +604,7 @@ where
520
604
// SAFETY: the condition above asserts that all elements are
521
605
// initialized.
522
606
let out = unsafe { MaybeUninit :: array_assume_init ( array) } ;
523
- return Some ( out) ;
607
+ return Some ( Ok ( out) ) ;
524
608
}
525
609
}
526
610
0 commit comments