@@ -11,8 +11,9 @@ use crate::cmp::Ordering;
11
11
use crate :: convert:: { Infallible , TryFrom } ;
12
12
use crate :: fmt;
13
13
use crate :: hash:: { self , Hash } ;
14
+ use crate :: iter:: TrustedLen ;
14
15
use crate :: marker:: Unsize ;
15
- use crate :: mem:: MaybeUninit ;
16
+ use crate :: mem:: { self , MaybeUninit } ;
16
17
use crate :: ops:: { Index , IndexMut } ;
17
18
use crate :: slice:: { Iter , IterMut } ;
18
19
@@ -426,41 +427,13 @@ impl<T, const N: usize> [T; N] {
426
427
/// assert_eq!(y, [6, 9, 3, 3]);
427
428
/// ```
428
429
#[ unstable( feature = "array_map" , issue = "75243" ) ]
429
- pub fn map < F , U > ( self , mut f : F ) -> [ U ; N ]
430
+ pub fn map < F , U > ( self , f : F ) -> [ U ; N ]
430
431
where
431
432
F : FnMut ( T ) -> U ,
432
433
{
433
- struct Guard < T , const N : usize > {
434
- dst : * mut T ,
435
- initialized : usize ,
436
- }
437
-
438
- impl < T , const N : usize > Drop for Guard < T , N > {
439
- fn drop ( & mut self ) {
440
- debug_assert ! ( self . initialized <= N ) ;
441
-
442
- let initialized_part =
443
- crate :: ptr:: slice_from_raw_parts_mut ( self . dst , self . initialized ) ;
444
- // SAFETY: this raw slice will contain only initialized objects
445
- // that's why, it is allowed to drop it.
446
- unsafe {
447
- crate :: ptr:: drop_in_place ( initialized_part) ;
448
- }
449
- }
450
- }
451
- let mut dst = MaybeUninit :: uninit_array :: < N > ( ) ;
452
- let mut guard: Guard < U , N > =
453
- Guard { dst : MaybeUninit :: slice_as_mut_ptr ( & mut dst) , initialized : 0 } ;
454
- for ( src, dst) in IntoIter :: new ( self ) . zip ( & mut dst) {
455
- dst. write ( f ( src) ) ;
456
- guard. initialized += 1 ;
457
- }
458
- // FIXME: Convert to crate::mem::transmute once it works with generics.
459
- // unsafe { crate::mem::transmute::<[MaybeUninit<U>; N], [U; N]>(dst) }
460
- crate :: mem:: forget ( guard) ;
461
- // SAFETY: At this point we've properly initialized the whole array
462
- // and we just need to cast it to the correct type.
463
- unsafe { crate :: mem:: transmute_copy :: < _ , [ U ; N ] > ( & dst) }
434
+ // SAFETY: we know for certain that this iterator will yield exactly `N`
435
+ // items.
436
+ unsafe { collect_into_array_unchecked ( & mut IntoIter :: new ( self ) . map ( f) ) }
464
437
}
465
438
466
439
/// 'Zips up' two arrays into a single array of pairs.
@@ -481,15 +454,11 @@ impl<T, const N: usize> [T; N] {
481
454
/// ```
482
455
#[ unstable( feature = "array_zip" , issue = "80094" ) ]
483
456
pub fn zip < U > ( self , rhs : [ U ; N ] ) -> [ ( T , U ) ; N ] {
484
- let mut dst = MaybeUninit :: uninit_array :: < N > ( ) ;
485
- for ( i, ( lhs, rhs) ) in IntoIter :: new ( self ) . zip ( IntoIter :: new ( rhs) ) . enumerate ( ) {
486
- dst[ i] . write ( ( lhs, rhs) ) ;
487
- }
488
- // FIXME: Convert to crate::mem::transmute once it works with generics.
489
- // unsafe { crate::mem::transmute::<[MaybeUninit<U>; N], [U; N]>(dst) }
490
- // SAFETY: At this point we've properly initialized the whole array
491
- // and we just need to cast it to the correct type.
492
- unsafe { crate :: mem:: transmute_copy :: < _ , [ ( T , U ) ; N ] > ( & dst) }
457
+ let mut iter = IntoIter :: new ( self ) . zip ( IntoIter :: new ( rhs) ) ;
458
+
459
+ // SAFETY: we know for certain that this iterator will yield exactly `N`
460
+ // items.
461
+ unsafe { collect_into_array_unchecked ( & mut iter) }
493
462
}
494
463
495
464
/// Returns a slice containing the entire array. Equivalent to `&s[..]`.
@@ -535,16 +504,9 @@ impl<T, const N: usize> [T; N] {
535
504
/// ```
536
505
#[ unstable( feature = "array_methods" , issue = "76118" ) ]
537
506
pub fn each_ref ( & self ) -> [ & T ; N ] {
538
- // Unlike in `map`, we don't need a guard here, as dropping a reference
539
- // is a noop.
540
- let mut out = MaybeUninit :: uninit_array :: < N > ( ) ;
541
- for ( src, dst) in self . iter ( ) . zip ( & mut out) {
542
- dst. write ( src) ;
543
- }
544
-
545
- // SAFETY: All elements of `dst` are properly initialized and
546
- // `MaybeUninit<T>` has the same layout as `T`, so this cast is valid.
547
- unsafe { ( & mut out as * mut _ as * mut [ & T ; N ] ) . read ( ) }
507
+ // SAFETY: we know for certain that this iterator will yield exactly `N`
508
+ // items.
509
+ unsafe { collect_into_array_unchecked ( & mut self . iter ( ) ) }
548
510
}
549
511
550
512
/// Borrows each element mutably and returns an array of mutable references
@@ -564,15 +526,103 @@ impl<T, const N: usize> [T; N] {
564
526
/// ```
565
527
#[ unstable( feature = "array_methods" , issue = "76118" ) ]
566
528
pub fn each_mut ( & mut self ) -> [ & mut T ; N ] {
567
- // Unlike in `map`, we don't need a guard here, as dropping a reference
568
- // is a noop.
569
- let mut out = MaybeUninit :: uninit_array :: < N > ( ) ;
570
- for ( src, dst) in self . iter_mut ( ) . zip ( & mut out) {
571
- dst. write ( src) ;
529
+ // SAFETY: we know for certain that this iterator will yield exactly `N`
530
+ // items.
531
+ unsafe { collect_into_array_unchecked ( & mut self . iter_mut ( ) ) }
532
+ }
533
+ }
534
+
535
+ /// Pulls `N` items from `iter` and returns them as an array. If the iterator
536
+ /// yields fewer than `N` items, this function exhibits undefined behavior.
537
+ ///
538
+ /// See [`collect_into_array`] for more information.
539
+ ///
540
+ ///
541
+ /// # Safety
542
+ ///
543
+ /// It is up to the caller to guarantee that `iter` yields at least `N` items.
544
+ /// Violating this condition causes undefined behavior.
545
+ unsafe fn collect_into_array_unchecked < I , const N : usize > ( iter : & mut I ) -> [ I :: Item ; N ]
546
+ where
547
+ // Note: `TrustedLen` here is somewhat of an experiment. This is just an
548
+ // internal function, so feel free to remove if this bound turns out to be a
549
+ // bad idea. In that case, remember to also remove the lower bound
550
+ // `debug_assert!` below!
551
+ I : Iterator + TrustedLen ,
552
+ {
553
+ debug_assert ! ( N <= iter. size_hint( ) . 1 . unwrap_or( usize :: MAX ) ) ;
554
+ debug_assert ! ( N <= iter. size_hint( ) . 0 ) ;
555
+
556
+ match collect_into_array ( iter) {
557
+ Some ( array) => array,
558
+ // SAFETY: covered by the function contract.
559
+ None => unsafe { crate :: hint:: unreachable_unchecked ( ) } ,
560
+ }
561
+ }
562
+
563
+ /// Pulls `N` items from `iter` and returns them as an array. If the iterator
564
+ /// yields fewer than `N` items, `None` is returned and all already yielded
565
+ /// items are dropped.
566
+ ///
567
+ /// Since the iterator is passed as mutable reference and this function calls
568
+ /// `next` at most `N` times, the iterator can still be used afterwards to
569
+ /// retrieve the remaining items.
570
+ ///
571
+ /// If `iter.next()` panicks, all items already yielded by the iterator are
572
+ /// dropped.
573
+ fn collect_into_array < I , const N : usize > ( iter : & mut I ) -> Option < [ I :: Item ; N ] >
574
+ where
575
+ I : Iterator ,
576
+ {
577
+ if N == 0 {
578
+ // SAFETY: An empty array is always inhabited and has no validity invariants.
579
+ return unsafe { Some ( mem:: zeroed ( ) ) } ;
580
+ }
581
+
582
+ struct Guard < T , const N : usize > {
583
+ ptr : * mut T ,
584
+ initialized : usize ,
585
+ }
586
+
587
+ impl < T , const N : usize > Drop for Guard < T , N > {
588
+ fn drop ( & mut self ) {
589
+ debug_assert ! ( self . initialized <= N ) ;
590
+
591
+ let initialized_part = crate :: ptr:: slice_from_raw_parts_mut ( self . ptr , self . initialized ) ;
592
+
593
+ // SAFETY: this raw slice will contain only initialized objects.
594
+ unsafe {
595
+ crate :: ptr:: drop_in_place ( initialized_part) ;
596
+ }
597
+ }
598
+ }
599
+
600
+ let mut array = MaybeUninit :: uninit_array :: < N > ( ) ;
601
+ let mut guard: Guard < _ , N > =
602
+ Guard { ptr : MaybeUninit :: slice_as_mut_ptr ( & mut array) , initialized : 0 } ;
603
+
604
+ while let Some ( item) = iter. next ( ) {
605
+ // SAFETY: `guard.initialized` starts at 0, is increased by one in the
606
+ // loop and the loop is aborted once it reaches N (which is
607
+ // `array.len()`).
608
+ unsafe {
609
+ array. get_unchecked_mut ( guard. initialized ) . write ( item) ;
572
610
}
611
+ guard. initialized += 1 ;
612
+
613
+ // Check if the whole array was initialized.
614
+ if guard. initialized == N {
615
+ mem:: forget ( guard) ;
573
616
574
- // SAFETY: All elements of `dst` are properly initialized and
575
- // `MaybeUninit<T>` has the same layout as `T`, so this cast is valid.
576
- unsafe { ( & mut out as * mut _ as * mut [ & mut T ; N ] ) . read ( ) }
617
+ // SAFETY: the condition above asserts that all elements are
618
+ // initialized.
619
+ let out = unsafe { MaybeUninit :: array_assume_init ( array) } ;
620
+ return Some ( out) ;
621
+ }
577
622
}
623
+
624
+ // This is only reached if the iterator is exhausted before
625
+ // `guard.initialized` reaches `N`. Also note that `guard` is dropped here,
626
+ // dropping all already initialized elements.
627
+ None
578
628
}
0 commit comments