@@ -1112,6 +1112,12 @@ macro_rules! nonzero_integer {
11121112 #[ must_use = "this returns the result of the operation, \
11131113 without modifying the original"]
11141114 #[ inline]
1115+ #[ requires( {
1116+ self . get( ) . checked_mul( other. get( ) ) . is_some( )
1117+ } ) ]
1118+ #[ ensures( |result: & Self | {
1119+ self . get( ) . checked_mul( other. get( ) ) . is_some_and( |product| product == result. get( ) )
1120+ } ) ]
11151121 pub const unsafe fn unchecked_mul( self , other: Self ) -> Self {
11161122 // SAFETY: The caller ensures there is no overflow.
11171123 unsafe { Self :: new_unchecked( self . get( ) . unchecked_mul( other. get( ) ) ) }
@@ -1514,6 +1520,13 @@ macro_rules! nonzero_integer_signedness_dependent_methods {
15141520 #[ must_use = "this returns the result of the operation, \
15151521 without modifying the original"]
15161522 #[ inline]
1523+ #[ requires( {
1524+ self . get( ) . checked_add( other) . is_some( )
1525+ } ) ]
1526+ #[ ensures( |result: & Self | {
1527+ // Postcondition: the result matches the expected addition
1528+ self . get( ) . checked_add( other) . is_some_and( |sum| sum == result. get( ) )
1529+ } ) ]
15171530 pub const unsafe fn unchecked_add( self , other: $Int) -> Self {
15181531 // SAFETY: The caller ensures there is no overflow.
15191532 unsafe { Self :: new_unchecked( self . get( ) . unchecked_add( other) ) }
@@ -2575,4 +2588,306 @@ mod verify {
25752588 nonzero_check_clamp_panic ! ( core:: num:: NonZeroU64 , nonzero_check_clamp_panic_for_u64) ;
25762589 nonzero_check_clamp_panic ! ( core:: num:: NonZeroU128 , nonzero_check_clamp_panic_for_u128) ;
25772590 nonzero_check_clamp_panic ! ( core:: num:: NonZeroUsize , nonzero_check_clamp_panic_for_usize) ;
2591+
2592+ macro_rules! check_mul_unchecked_small {
2593+ ( $t: ty, $nonzero_type: ty, $nonzero_check_unchecked_mul_for: ident) => {
2594+ #[ kani:: proof_for_contract( NonZero :: <$t>:: unchecked_mul) ]
2595+ pub fn $nonzero_check_unchecked_mul_for( ) {
2596+ let x: $nonzero_type = kani:: any( ) ;
2597+ let y: $nonzero_type = kani:: any( ) ;
2598+
2599+ unsafe {
2600+ x. unchecked_mul( y) ;
2601+ }
2602+ }
2603+ } ;
2604+ }
2605+
2606+ // Use for NonZero what already worked well for general numeric types (see num/mod.rs)
2607+ macro_rules! check_mul_unchecked_intervals {
2608+ ( $t: ty, $nonzero_type: ty, $nonzero_check_mul_for: ident, $min: expr, $max: expr) => {
2609+ #[ kani:: proof_for_contract( NonZero :: <$t>:: unchecked_mul) ]
2610+ pub fn $nonzero_check_mul_for( ) {
2611+ let x = kani:: any:: <$t>( ) ;
2612+ let y = kani:: any:: <$t>( ) ;
2613+
2614+ kani:: assume( x != 0 && x >= $min && x <= $max) ;
2615+ kani:: assume( y != 0 && y >= $min && y <= $max) ;
2616+
2617+ let x = <$nonzero_type>:: new( x) . unwrap( ) ;
2618+ let y = <$nonzero_type>:: new( y) . unwrap( ) ;
2619+
2620+ unsafe {
2621+ x. unchecked_mul( y) ;
2622+ }
2623+ }
2624+ } ;
2625+ }
2626+
2627+ //Calls for i32
2628+ check_mul_unchecked_intervals ! (
2629+ i32 ,
2630+ NonZeroI32 ,
2631+ check_mul_i32_small,
2632+ NonZeroI32 :: new( -10i32 ) . unwrap( ) . into( ) ,
2633+ NonZeroI32 :: new( 10i32 ) . unwrap( ) . into( )
2634+ ) ;
2635+ check_mul_unchecked_intervals ! (
2636+ i32 ,
2637+ NonZeroI32 ,
2638+ check_mul_i32_large_pos,
2639+ NonZeroI32 :: new( i32 :: MAX - 1000i32 ) . unwrap( ) . into( ) ,
2640+ NonZeroI32 :: new( i32 :: MAX ) . unwrap( ) . into( )
2641+ ) ;
2642+ check_mul_unchecked_intervals ! (
2643+ i32 ,
2644+ NonZeroI32 ,
2645+ check_mul_i32_large_neg,
2646+ NonZeroI32 :: new( i32 :: MIN + 1000i32 ) . unwrap( ) . into( ) ,
2647+ NonZeroI32 :: new( i32 :: MIN + 1 ) . unwrap( ) . into( )
2648+ ) ;
2649+ check_mul_unchecked_intervals ! (
2650+ i32 ,
2651+ NonZeroI32 ,
2652+ check_mul_i32_edge_pos,
2653+ NonZeroI32 :: new( i32 :: MAX / 2 ) . unwrap( ) . into( ) ,
2654+ NonZeroI32 :: new( i32 :: MAX ) . unwrap( ) . into( )
2655+ ) ;
2656+ check_mul_unchecked_intervals ! (
2657+ i32 ,
2658+ NonZeroI32 ,
2659+ check_mul_i32_edge_neg,
2660+ NonZeroI32 :: new( i32 :: MIN / 2 ) . unwrap( ) . into( ) ,
2661+ NonZeroI32 :: new( i32 :: MIN + 1 ) . unwrap( ) . into( )
2662+ ) ;
2663+
2664+ //Calls for i64
2665+ check_mul_unchecked_intervals ! (
2666+ i64 ,
2667+ NonZeroI64 ,
2668+ check_mul_i64_small,
2669+ NonZeroI64 :: new( -10i64 ) . unwrap( ) . into( ) ,
2670+ NonZeroI64 :: new( 10i64 ) . unwrap( ) . into( )
2671+ ) ;
2672+ check_mul_unchecked_intervals ! (
2673+ i64 ,
2674+ NonZeroI64 ,
2675+ check_mul_i64_large_pos,
2676+ NonZeroI64 :: new( i64 :: MAX - 1000i64 ) . unwrap( ) . into( ) ,
2677+ NonZeroI64 :: new( i64 :: MAX ) . unwrap( ) . into( )
2678+ ) ;
2679+ check_mul_unchecked_intervals ! (
2680+ i64 ,
2681+ NonZeroI64 ,
2682+ check_mul_i64_large_neg,
2683+ NonZeroI64 :: new( i64 :: MIN + 1000i64 ) . unwrap( ) . into( ) ,
2684+ NonZeroI64 :: new( i64 :: MIN + 1 ) . unwrap( ) . into( )
2685+ ) ;
2686+ check_mul_unchecked_intervals ! (
2687+ i64 ,
2688+ NonZeroI64 ,
2689+ check_mul_i64_edge_pos,
2690+ NonZeroI64 :: new( i64 :: MAX / 2 ) . unwrap( ) . into( ) ,
2691+ NonZeroI64 :: new( i64 :: MAX ) . unwrap( ) . into( )
2692+ ) ;
2693+ check_mul_unchecked_intervals ! (
2694+ i64 ,
2695+ NonZeroI64 ,
2696+ check_mul_i64_edge_neg,
2697+ NonZeroI64 :: new( i64 :: MIN / 2 ) . unwrap( ) . into( ) ,
2698+ NonZeroI64 :: new( i64 :: MIN + 1 ) . unwrap( ) . into( )
2699+ ) ;
2700+
2701+ //calls for i128
2702+ check_mul_unchecked_intervals ! (
2703+ i128 ,
2704+ NonZeroI128 ,
2705+ check_mul_i128_small,
2706+ NonZeroI128 :: new( -10i128 ) . unwrap( ) . into( ) ,
2707+ NonZeroI128 :: new( 10i128 ) . unwrap( ) . into( )
2708+ ) ;
2709+ check_mul_unchecked_intervals ! (
2710+ i128 ,
2711+ NonZeroI128 ,
2712+ check_mul_i128_large_pos,
2713+ NonZeroI128 :: new( i128 :: MAX - 1000i128 ) . unwrap( ) . into( ) ,
2714+ NonZeroI128 :: new( i128 :: MAX ) . unwrap( ) . into( )
2715+ ) ;
2716+ check_mul_unchecked_intervals ! (
2717+ i128 ,
2718+ NonZeroI128 ,
2719+ check_mul_i128_large_neg,
2720+ NonZeroI128 :: new( i128 :: MIN + 1000i128 ) . unwrap( ) . into( ) ,
2721+ NonZeroI128 :: new( i128 :: MIN + 1 ) . unwrap( ) . into( )
2722+ ) ;
2723+ check_mul_unchecked_intervals ! (
2724+ i128 ,
2725+ NonZeroI128 ,
2726+ check_mul_i128_edge_pos,
2727+ NonZeroI128 :: new( i128 :: MAX / 2 ) . unwrap( ) . into( ) ,
2728+ NonZeroI128 :: new( i128 :: MAX ) . unwrap( ) . into( )
2729+ ) ;
2730+ check_mul_unchecked_intervals ! (
2731+ i128 ,
2732+ NonZeroI128 ,
2733+ check_mul_i128_edge_neg,
2734+ NonZeroI128 :: new( i128 :: MIN / 2 ) . unwrap( ) . into( ) ,
2735+ NonZeroI128 :: new( i128 :: MIN + 1 ) . unwrap( ) . into( )
2736+ ) ;
2737+
2738+ //calls for isize
2739+ check_mul_unchecked_intervals ! (
2740+ isize ,
2741+ NonZeroIsize ,
2742+ check_mul_isize_small,
2743+ NonZeroIsize :: new( -10isize ) . unwrap( ) . into( ) ,
2744+ NonZeroIsize :: new( 10isize ) . unwrap( ) . into( )
2745+ ) ;
2746+ check_mul_unchecked_intervals ! (
2747+ isize ,
2748+ NonZeroIsize ,
2749+ check_mul_isize_large_pos,
2750+ NonZeroIsize :: new( isize :: MAX - 1000isize ) . unwrap( ) . into( ) ,
2751+ NonZeroIsize :: new( isize :: MAX ) . unwrap( ) . into( )
2752+ ) ;
2753+ check_mul_unchecked_intervals ! (
2754+ isize ,
2755+ NonZeroIsize ,
2756+ check_mul_isize_large_neg,
2757+ NonZeroIsize :: new( isize :: MIN + 1000isize ) . unwrap( ) . into( ) ,
2758+ NonZeroIsize :: new( isize :: MIN + 1 ) . unwrap( ) . into( )
2759+ ) ;
2760+ check_mul_unchecked_intervals ! (
2761+ isize ,
2762+ NonZeroIsize ,
2763+ check_mul_isize_edge_pos,
2764+ NonZeroIsize :: new( isize :: MAX / 2 ) . unwrap( ) . into( ) ,
2765+ NonZeroIsize :: new( isize :: MAX ) . unwrap( ) . into( )
2766+ ) ;
2767+ check_mul_unchecked_intervals ! (
2768+ isize ,
2769+ NonZeroIsize ,
2770+ check_mul_isize_edge_neg,
2771+ NonZeroIsize :: new( isize :: MIN / 2 ) . unwrap( ) . into( ) ,
2772+ NonZeroIsize :: new( isize :: MIN + 1 ) . unwrap( ) . into( )
2773+ ) ;
2774+
2775+ //calls for u32
2776+ check_mul_unchecked_intervals ! (
2777+ u32 ,
2778+ NonZeroU32 ,
2779+ check_mul_u32_small,
2780+ NonZeroU32 :: new( 1u32 ) . unwrap( ) . into( ) ,
2781+ NonZeroU32 :: new( 10u32 ) . unwrap( ) . into( )
2782+ ) ;
2783+ check_mul_unchecked_intervals ! (
2784+ u32 ,
2785+ NonZeroU32 ,
2786+ check_mul_u32_large,
2787+ NonZeroU32 :: new( u32 :: MAX - 1000u32 ) . unwrap( ) . into( ) ,
2788+ NonZeroU32 :: new( u32 :: MAX ) . unwrap( ) . into( )
2789+ ) ;
2790+ check_mul_unchecked_intervals ! (
2791+ u32 ,
2792+ NonZeroU32 ,
2793+ check_mul_u32_edge,
2794+ NonZeroU32 :: new( u32 :: MAX / 2 ) . unwrap( ) . into( ) ,
2795+ NonZeroU32 :: new( u32 :: MAX ) . unwrap( ) . into( )
2796+ ) ;
2797+
2798+ //calls for u64
2799+ check_mul_unchecked_intervals ! (
2800+ u64 ,
2801+ NonZeroU64 ,
2802+ check_mul_u64_small,
2803+ NonZeroU64 :: new( 1u64 ) . unwrap( ) . into( ) ,
2804+ NonZeroU64 :: new( 10u64 ) . unwrap( ) . into( )
2805+ ) ;
2806+ check_mul_unchecked_intervals ! (
2807+ u64 ,
2808+ NonZeroU64 ,
2809+ check_mul_u64_large,
2810+ NonZeroU64 :: new( u64 :: MAX - 1000u64 ) . unwrap( ) . into( ) ,
2811+ NonZeroU64 :: new( u64 :: MAX ) . unwrap( ) . into( )
2812+ ) ;
2813+ check_mul_unchecked_intervals ! (
2814+ u64 ,
2815+ NonZeroU64 ,
2816+ check_mul_u64_edge,
2817+ NonZeroU64 :: new( u64 :: MAX / 2 ) . unwrap( ) . into( ) ,
2818+ NonZeroU64 :: new( u64 :: MAX ) . unwrap( ) . into( )
2819+ ) ;
2820+
2821+ //calls for u128
2822+ check_mul_unchecked_intervals ! (
2823+ u128 ,
2824+ NonZeroU128 ,
2825+ check_mul_u128_small,
2826+ NonZeroU128 :: new( 1u128 ) . unwrap( ) . into( ) ,
2827+ NonZeroU128 :: new( 10u128 ) . unwrap( ) . into( )
2828+ ) ;
2829+ check_mul_unchecked_intervals ! (
2830+ u128 ,
2831+ NonZeroU128 ,
2832+ check_mul_u128_large,
2833+ NonZeroU128 :: new( u128 :: MAX - 1000u128 ) . unwrap( ) . into( ) ,
2834+ NonZeroU128 :: new( u128 :: MAX ) . unwrap( ) . into( )
2835+ ) ;
2836+ check_mul_unchecked_intervals ! (
2837+ u128 ,
2838+ NonZeroU128 ,
2839+ check_mul_u128_edge,
2840+ NonZeroU128 :: new( u128 :: MAX / 2 ) . unwrap( ) . into( ) ,
2841+ NonZeroU128 :: new( u128 :: MAX ) . unwrap( ) . into( )
2842+ ) ;
2843+
2844+ //calls for usize
2845+ check_mul_unchecked_intervals ! (
2846+ usize ,
2847+ NonZeroUsize ,
2848+ check_mul_usize_small,
2849+ NonZeroUsize :: new( 1usize ) . unwrap( ) . into( ) ,
2850+ NonZeroUsize :: new( 10usize ) . unwrap( ) . into( )
2851+ ) ;
2852+ check_mul_unchecked_intervals ! (
2853+ usize ,
2854+ NonZeroUsize ,
2855+ check_mul_usize_large,
2856+ NonZeroUsize :: new( usize :: MAX - 1000usize ) . unwrap( ) . into( ) ,
2857+ NonZeroUsize :: new( usize :: MAX ) . unwrap( ) . into( )
2858+ ) ;
2859+ check_mul_unchecked_intervals ! (
2860+ usize ,
2861+ NonZeroUsize ,
2862+ check_mul_usize_edge,
2863+ NonZeroUsize :: new( usize :: MAX / 2 ) . unwrap( ) . into( ) ,
2864+ NonZeroUsize :: new( usize :: MAX ) . unwrap( ) . into( )
2865+ ) ;
2866+
2867+ //calls for i8, i16, u8, u16
2868+ check_mul_unchecked_small ! ( i8 , NonZeroI8 , nonzero_check_mul_for_i8) ;
2869+ check_mul_unchecked_small ! ( i16 , NonZeroI16 , nonzero_check_mul_for_i16) ;
2870+ check_mul_unchecked_small ! ( u8 , NonZeroU8 , nonzero_check_mul_for_u8) ;
2871+ check_mul_unchecked_small ! ( u16 , NonZeroU16 , nonzero_check_mul_for_u16) ;
2872+
2873+ macro_rules! nonzero_check_add {
2874+ ( $t: ty, $nonzero_type: ty, $nonzero_check_unchecked_add_for: ident) => {
2875+ #[ kani:: proof_for_contract( NonZero :: <$t>:: unchecked_add) ]
2876+ pub fn $nonzero_check_unchecked_add_for( ) {
2877+ let x: $nonzero_type = kani:: any( ) ;
2878+ let y: $t = kani:: any( ) ;
2879+
2880+ unsafe {
2881+ x. unchecked_add( y) ;
2882+ }
2883+ }
2884+ } ;
2885+ }
2886+
2887+ nonzero_check_add ! ( u8 , core:: num:: NonZeroU8 , nonzero_check_unchecked_add_for_u8) ;
2888+ nonzero_check_add ! ( u16 , core:: num:: NonZeroU16 , nonzero_check_unchecked_add_for_u16) ;
2889+ nonzero_check_add ! ( u32 , core:: num:: NonZeroU32 , nonzero_check_unchecked_add_for_u32) ;
2890+ nonzero_check_add ! ( u64 , core:: num:: NonZeroU64 , nonzero_check_unchecked_add_for_u64) ;
2891+ nonzero_check_add ! ( u128 , core:: num:: NonZeroU128 , nonzero_check_unchecked_add_for_u128) ;
2892+ nonzero_check_add ! ( usize , core:: num:: NonZeroUsize , nonzero_check_unchecked_add_for_usize) ;
25782893}
0 commit comments