@@ -16,6 +16,7 @@ macro_rules! unsafe_impl_trusted_step {
16
16
) * } ;
17
17
}
18
18
unsafe_impl_trusted_step ! [ AsciiChar char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize Ipv4Addr Ipv6Addr ] ;
19
+ unsafe_impl_trusted_step ! [ NonZero <u8 > NonZero <u16 > NonZero <u32 > NonZero <u64 > NonZero <u128 > NonZero <usize >] ;
19
20
20
21
/// Objects that have a notion of *successor* and *predecessor* operations.
21
22
///
@@ -431,6 +432,138 @@ step_integer_impls! {
431
432
wider than usize : [ u32 i32 ] , [ u64 i64 ] , [ u128 i128 ] ;
432
433
}
433
434
435
+ // These are still macro-generated because the integer literals resolve to different types.
436
+ macro_rules! step_nonzero_identical_methods {
437
+ ( $int: ident) => {
438
+ #[ inline]
439
+ unsafe fn forward_unchecked( start: Self , n: usize ) -> Self {
440
+ // SAFETY: the caller has to guarantee that `start + n` doesn't overflow.
441
+ unsafe { Self :: new_unchecked( start. get( ) . unchecked_add( n as $int) ) }
442
+ }
443
+
444
+ #[ inline]
445
+ unsafe fn backward_unchecked( start: Self , n: usize ) -> Self {
446
+ // SAFETY: the caller has to guarantee that `start - n` doesn't overflow or hit zero.
447
+ unsafe { Self :: new_unchecked( start. get( ) . unchecked_sub( n as $int) ) }
448
+ }
449
+
450
+ #[ inline]
451
+ #[ allow( arithmetic_overflow) ]
452
+ #[ rustc_inherit_overflow_checks]
453
+ fn forward( start: Self , n: usize ) -> Self {
454
+ // In debug builds, trigger a panic on overflow.
455
+ // This should optimize completely out in release builds.
456
+ if Self :: forward_checked( start, n) . is_none( ) {
457
+ let _ = $int:: MAX + 1 ;
458
+ }
459
+ // Do saturating math (wrapping math causes UB if it wraps to Zero)
460
+ start. saturating_add( n as $int)
461
+ }
462
+
463
+ #[ inline]
464
+ #[ allow( arithmetic_overflow) ]
465
+ #[ rustc_inherit_overflow_checks]
466
+ fn backward( start: Self , n: usize ) -> Self {
467
+ // In debug builds, trigger a panic on overflow.
468
+ // This should optimize completely out in release builds.
469
+ if Self :: backward_checked( start, n) . is_none( ) {
470
+ let _ = $int:: MIN - 1 ;
471
+ }
472
+ // Do saturating math (wrapping math causes UB if it wraps to Zero)
473
+ Self :: new( start. get( ) . saturating_sub( n as $int) ) . unwrap_or( Self :: MIN )
474
+ }
475
+ } ;
476
+ }
477
+
478
+ macro_rules! step_nonzero_impls {
479
+ {
480
+ narrower than or same width as usize :
481
+ $( $narrower: ident ) ,+;
482
+ wider than usize :
483
+ $( $wider: ident ) ,+;
484
+ } => {
485
+ $(
486
+ #[ allow( unreachable_patterns) ]
487
+ #[ unstable( feature = "step_trait" , reason = "recently redesigned" , issue = "42168" ) ]
488
+ impl Step for NonZero <$narrower> {
489
+ step_nonzero_identical_methods!( $narrower) ;
490
+
491
+ #[ inline]
492
+ fn steps_between( start: & Self , end: & Self ) -> Option <usize > {
493
+ if * start <= * end {
494
+ // This relies on $u_narrower <= usize
495
+ Some ( ( end. get( ) - start. get( ) ) as usize )
496
+ } else {
497
+ None
498
+ }
499
+ }
500
+
501
+ #[ inline]
502
+ fn forward_checked( start: Self , n: usize ) -> Option <Self > {
503
+ match $narrower:: try_from( n) {
504
+ Ok ( n) => start. checked_add( n) ,
505
+ Err ( _) => None , // if n is out of range, `unsigned_start + n` is too
506
+ }
507
+ }
508
+
509
+ #[ inline]
510
+ fn backward_checked( start: Self , n: usize ) -> Option <Self > {
511
+ match $narrower:: try_from( n) {
512
+ // *_sub() is not implemented on NonZero<T>
513
+ Ok ( n) => start. get( ) . checked_sub( n) . and_then( Self :: new) ,
514
+ Err ( _) => None , // if n is out of range, `unsigned_start - n` is too
515
+ }
516
+ }
517
+ }
518
+ ) +
519
+
520
+ $(
521
+ #[ allow( unreachable_patterns) ]
522
+ #[ unstable( feature = "step_trait" , reason = "recently redesigned" , issue = "42168" ) ]
523
+ impl Step for NonZero <$wider> {
524
+ step_nonzero_identical_methods!( $wider) ;
525
+
526
+ #[ inline]
527
+ fn steps_between( start: & Self , end: & Self ) -> Option <usize > {
528
+ if * start <= * end {
529
+ usize :: try_from( end. get( ) - start. get( ) ) . ok( )
530
+ } else {
531
+ None
532
+ }
533
+ }
534
+
535
+ #[ inline]
536
+ fn forward_checked( start: Self , n: usize ) -> Option <Self > {
537
+ start. checked_add( n as $wider)
538
+ }
539
+
540
+ #[ inline]
541
+ fn backward_checked( start: Self , n: usize ) -> Option <Self > {
542
+ start. get( ) . checked_sub( n as $wider) . and_then( Self :: new)
543
+ }
544
+ }
545
+ ) +
546
+ } ;
547
+ }
548
+
549
+ #[ cfg( target_pointer_width = "64" ) ]
550
+ step_nonzero_impls ! {
551
+ narrower than or same width as usize : u8 , u16 , u32 , u64 , usize ;
552
+ wider than usize : u128 ;
553
+ }
554
+
555
+ #[ cfg( target_pointer_width = "32" ) ]
556
+ step_nonzero_impls ! {
557
+ narrower than or same width as usize : u8 , u16 , u32 , usize ;
558
+ wider than usize : u64 , u128 ;
559
+ }
560
+
561
+ #[ cfg( target_pointer_width = "16" ) ]
562
+ step_nonzero_impls ! {
563
+ narrower than or same width as usize : u8 , u16 , usize ;
564
+ wider than usize : u32 , u64 , u128 ;
565
+ }
566
+
434
567
#[ unstable( feature = "step_trait" , reason = "recently redesigned" , issue = "42168" ) ]
435
568
impl Step for char {
436
569
#[ inline]
0 commit comments