19
19
//! assert_eq!(total, Duration::new(10, 7));
20
20
//! ```
21
21
22
+ use safety:: { ensures, Invariant } ;
22
23
use crate :: fmt;
23
24
use crate :: iter:: Sum ;
24
25
use crate :: ops:: { Add , AddAssign , Div , DivAssign , Mul , MulAssign , Sub , SubAssign } ;
25
26
27
+ #[ cfg( kani) ]
28
+ use crate :: kani;
29
+
30
+ use crate :: ub_checks:: Invariant ;
31
+
26
32
const NANOS_PER_SEC : u32 = 1_000_000_000 ;
27
33
const NANOS_PER_MILLI : u32 = 1_000_000 ;
28
34
const NANOS_PER_MICRO : u32 = 1_000 ;
@@ -43,6 +49,12 @@ const DAYS_PER_WEEK: u64 = 7;
43
49
#[ rustc_layout_scalar_valid_range_end( 999_999_999 ) ]
44
50
struct Nanoseconds ( u32 ) ;
45
51
52
+ impl Invariant for Nanoseconds {
53
+ fn is_safe ( & self ) -> bool {
54
+ self . 0 < NANOS_PER_SEC
55
+ }
56
+ }
57
+
46
58
impl Nanoseconds {
47
59
// SAFETY: 0 is within the valid range
48
60
const ZERO : Self = unsafe { Nanoseconds ( 0 ) } ;
@@ -95,6 +107,7 @@ impl Default for Nanoseconds {
95
107
#[ stable( feature = "duration" , since = "1.3.0" ) ]
96
108
#[ derive( Clone , Copy , PartialEq , Eq , PartialOrd , Ord , Hash , Default ) ]
97
109
#[ cfg_attr( not( test) , rustc_diagnostic_item = "Duration" ) ]
110
+ #[ derive( Invariant ) ]
98
111
pub struct Duration {
99
112
secs : u64 ,
100
113
nanos : Nanoseconds , // Always 0 <= nanos < NANOS_PER_SEC
@@ -208,6 +221,7 @@ impl Duration {
208
221
#[ inline]
209
222
#[ must_use]
210
223
#[ rustc_const_stable( feature = "duration_consts_2" , since = "1.58.0" ) ]
224
+ #[ ensures( |duration| duration. is_safe( ) ) ]
211
225
pub const fn new ( secs : u64 , nanos : u32 ) -> Duration {
212
226
if nanos < NANOS_PER_SEC {
213
227
// SAFETY: nanos < NANOS_PER_SEC, therefore nanos is within the valid range
@@ -238,6 +252,8 @@ impl Duration {
238
252
#[ must_use]
239
253
#[ inline]
240
254
#[ rustc_const_stable( feature = "duration_consts" , since = "1.32.0" ) ]
255
+ #[ ensures( |duration| duration. is_safe( ) ) ]
256
+ #[ ensures( |duration| duration. secs == secs) ]
241
257
pub const fn from_secs ( secs : u64 ) -> Duration {
242
258
Duration { secs, nanos : Nanoseconds :: ZERO }
243
259
}
@@ -258,6 +274,7 @@ impl Duration {
258
274
#[ must_use]
259
275
#[ inline]
260
276
#[ rustc_const_stable( feature = "duration_consts" , since = "1.32.0" ) ]
277
+ #[ ensures( |duration| duration. is_safe( ) ) ]
261
278
pub const fn from_millis ( millis : u64 ) -> Duration {
262
279
let secs = millis / MILLIS_PER_SEC ;
263
280
let subsec_millis = ( millis % MILLIS_PER_SEC ) as u32 ;
@@ -284,6 +301,7 @@ impl Duration {
284
301
#[ must_use]
285
302
#[ inline]
286
303
#[ rustc_const_stable( feature = "duration_consts" , since = "1.32.0" ) ]
304
+ #[ ensures( |duration| duration. is_safe( ) ) ]
287
305
pub const fn from_micros ( micros : u64 ) -> Duration {
288
306
let secs = micros / MICROS_PER_SEC ;
289
307
let subsec_micros = ( micros % MICROS_PER_SEC ) as u32 ;
@@ -315,6 +333,7 @@ impl Duration {
315
333
#[ must_use]
316
334
#[ inline]
317
335
#[ rustc_const_stable( feature = "duration_consts" , since = "1.32.0" ) ]
336
+ #[ ensures( |duration| duration. is_safe( ) ) ]
318
337
pub const fn from_nanos ( nanos : u64 ) -> Duration {
319
338
const NANOS_PER_SEC : u64 = self :: NANOS_PER_SEC as u64 ;
320
339
let secs = nanos / NANOS_PER_SEC ;
@@ -485,6 +504,7 @@ impl Duration {
485
504
#[ rustc_const_stable( feature = "duration_consts" , since = "1.32.0" ) ]
486
505
#[ must_use]
487
506
#[ inline]
507
+ #[ ensures( |secs| * secs == self . secs) ]
488
508
pub const fn as_secs ( & self ) -> u64 {
489
509
self . secs
490
510
}
@@ -508,6 +528,7 @@ impl Duration {
508
528
#[ rustc_const_stable( feature = "duration_consts" , since = "1.32.0" ) ]
509
529
#[ must_use]
510
530
#[ inline]
531
+ #[ ensures( |ms| * ms == self . nanos. 0 / NANOS_PER_MILLI ) ]
511
532
pub const fn subsec_millis ( & self ) -> u32 {
512
533
self . nanos . 0 / NANOS_PER_MILLI
513
534
}
@@ -531,6 +552,7 @@ impl Duration {
531
552
#[ rustc_const_stable( feature = "duration_consts" , since = "1.32.0" ) ]
532
553
#[ must_use]
533
554
#[ inline]
555
+ #[ ensures( |ms| * ms == self . nanos. 0 / NANOS_PER_MICRO ) ]
534
556
pub const fn subsec_micros ( & self ) -> u32 {
535
557
self . nanos . 0 / NANOS_PER_MICRO
536
558
}
@@ -554,6 +576,7 @@ impl Duration {
554
576
#[ rustc_const_stable( feature = "duration_consts" , since = "1.32.0" ) ]
555
577
#[ must_use]
556
578
#[ inline]
579
+ #[ ensures( |nanos| * nanos == self . nanos. 0 ) ]
557
580
pub const fn subsec_nanos ( & self ) -> u32 {
558
581
self . nanos . 0
559
582
}
@@ -572,6 +595,7 @@ impl Duration {
572
595
#[ rustc_const_stable( feature = "duration_as_u128" , since = "1.33.0" ) ]
573
596
#[ must_use]
574
597
#[ inline]
598
+ #[ ensures( |ms| * ms == self . secs as u128 * MILLIS_PER_SEC as u128 + ( self . nanos. 0 / NANOS_PER_MILLI ) as u128 ) ]
575
599
pub const fn as_millis ( & self ) -> u128 {
576
600
self . secs as u128 * MILLIS_PER_SEC as u128 + ( self . nanos . 0 / NANOS_PER_MILLI ) as u128
577
601
}
@@ -590,6 +614,7 @@ impl Duration {
590
614
#[ rustc_const_stable( feature = "duration_as_u128" , since = "1.33.0" ) ]
591
615
#[ must_use]
592
616
#[ inline]
617
+ #[ ensures( |ms| * ms == self . secs as u128 * MICROS_PER_SEC as u128 + ( self . nanos. 0 / NANOS_PER_MICRO ) as u128 ) ]
593
618
pub const fn as_micros ( & self ) -> u128 {
594
619
self . secs as u128 * MICROS_PER_SEC as u128 + ( self . nanos . 0 / NANOS_PER_MICRO ) as u128
595
620
}
@@ -647,6 +672,7 @@ impl Duration {
647
672
without modifying the original"]
648
673
#[ inline]
649
674
#[ rustc_const_stable( feature = "duration_consts_2" , since = "1.58.0" ) ]
675
+ #[ ensures( |duration| duration. is_none( ) || duration. unwrap( ) . is_safe( ) ) ]
650
676
pub const fn checked_add ( self , rhs : Duration ) -> Option < Duration > {
651
677
if let Some ( mut secs) = self . secs . checked_add ( rhs. secs ) {
652
678
let mut nanos = self . nanos . 0 + rhs. nanos . 0 ;
@@ -705,6 +731,7 @@ impl Duration {
705
731
without modifying the original"]
706
732
#[ inline]
707
733
#[ rustc_const_stable( feature = "duration_consts_2" , since = "1.58.0" ) ]
734
+ #[ ensures( |duration| duration. is_none( ) || duration. unwrap( ) . is_safe( ) ) ]
708
735
pub const fn checked_sub ( self , rhs : Duration ) -> Option < Duration > {
709
736
if let Some ( mut secs) = self . secs . checked_sub ( rhs. secs ) {
710
737
let nanos = if self . nanos . 0 >= rhs. nanos . 0 {
@@ -761,6 +788,7 @@ impl Duration {
761
788
without modifying the original"]
762
789
#[ inline]
763
790
#[ rustc_const_stable( feature = "duration_consts_2" , since = "1.58.0" ) ]
791
+ #[ ensures( |duration| duration. is_none( ) || duration. unwrap( ) . is_safe( ) ) ]
764
792
pub const fn checked_mul ( self , rhs : u32 ) -> Option < Duration > {
765
793
// Multiply nanoseconds as u64, because it cannot overflow that way.
766
794
let total_nanos = self . nanos . 0 as u64 * rhs as u64 ;
@@ -816,13 +844,15 @@ impl Duration {
816
844
#[ must_use = "this returns the result of the operation, \
817
845
without modifying the original"]
818
846
#[ inline]
847
+ #[ ensures( |duration| rhs == 0 || duration. unwrap( ) . is_safe( ) ) ]
819
848
#[ rustc_const_stable( feature = "duration_consts_2" , since = "1.58.0" ) ]
820
849
pub const fn checked_div ( self , rhs : u32 ) -> Option < Duration > {
821
850
if rhs != 0 {
822
851
let ( secs, extra_secs) = ( self . secs / ( rhs as u64 ) , self . secs % ( rhs as u64 ) ) ;
823
852
let ( mut nanos, extra_nanos) = ( self . nanos . 0 / rhs, self . nanos . 0 % rhs) ;
824
853
nanos +=
825
854
( ( extra_secs * ( NANOS_PER_SEC as u64 ) + extra_nanos as u64 ) / ( rhs as u64 ) ) as u32 ;
855
+ #[ cfg( not( kani) ) ]
826
856
debug_assert ! ( nanos < NANOS_PER_SEC ) ;
827
857
Some ( Duration :: new ( secs, nanos) )
828
858
} else {
@@ -1698,3 +1728,213 @@ impl Duration {
1698
1728
)
1699
1729
}
1700
1730
}
1731
+
1732
+ #[ cfg( kani) ]
1733
+ #[ unstable( feature = "kani" , issue = "none" ) ]
1734
+ pub mod duration_verify {
1735
+ use crate :: kani;
1736
+ use super :: * ;
1737
+
1738
+ impl kani:: Arbitrary for Duration {
1739
+ fn any ( ) -> Duration {
1740
+ let secs = kani:: any :: < u64 > ( ) ;
1741
+ let nanos = kani:: any :: < u32 > ( ) ;
1742
+ Duration :: new ( secs, nanos)
1743
+ }
1744
+ }
1745
+
1746
+ fn safe_duration ( ) -> Duration {
1747
+ let secs = kani:: any :: < u64 > ( ) ;
1748
+ let nanos = kani:: any :: < u32 > ( ) ;
1749
+ kani:: assume ( nanos < NANOS_PER_SEC || secs. checked_add ( ( nanos / NANOS_PER_SEC ) as u64 ) . is_some ( ) ) ;
1750
+ Duration :: new ( secs, nanos)
1751
+ }
1752
+
1753
+ #[ kani:: proof_for_contract( Duration :: new) ]
1754
+ fn duration_new ( ) {
1755
+ let _ = safe_duration ( ) ;
1756
+ }
1757
+
1758
+ #[ kani:: proof_for_contract( Duration :: new) ]
1759
+ #[ kani:: should_panic]
1760
+ fn duration_new_panics ( ) {
1761
+ let secs = kani:: any :: < u64 > ( ) ;
1762
+ let nanos = kani:: any :: < u32 > ( ) ;
1763
+ let _ = Duration :: new ( secs, nanos) ;
1764
+ }
1765
+
1766
+ #[ kani:: proof_for_contract( Duration :: from_secs) ]
1767
+ fn duration_from_secs ( ) {
1768
+ let secs = kani:: any :: < u64 > ( ) ;
1769
+ let _ = Duration :: from_secs ( secs) ;
1770
+ }
1771
+
1772
+ #[ kani:: proof_for_contract( Duration :: from_millis) ]
1773
+ fn duration_from_millis ( ) {
1774
+ let ms = kani:: any :: < u64 > ( ) ;
1775
+ let _ = Duration :: from_millis ( ms) ;
1776
+ }
1777
+
1778
+ #[ kani:: proof_for_contract( Duration :: from_micros) ]
1779
+ fn duration_from_micros ( ) {
1780
+ let micros = kani:: any :: < u64 > ( ) ;
1781
+ let _ = Duration :: from_micros ( micros) ;
1782
+ }
1783
+
1784
+ #[ kani:: proof_for_contract( Duration :: from_nanos) ]
1785
+ fn duration_from_nanos ( ) {
1786
+ let nanos = kani:: any :: < u64 > ( ) ;
1787
+ let _ = Duration :: from_nanos ( nanos) ;
1788
+ }
1789
+
1790
+ #[ kani:: proof_for_contract( Duration :: as_secs) ]
1791
+ fn duration_as_secs ( ) {
1792
+ let dur = safe_duration ( ) ;
1793
+ let _ = dur. as_secs ( ) ;
1794
+ }
1795
+
1796
+ #[ kani:: proof_for_contract( Duration :: as_secs) ]
1797
+ #[ kani:: should_panic]
1798
+ fn duration_as_secs_panics ( ) {
1799
+ let dur = kani:: any :: < Duration > ( ) ;
1800
+ let _ = dur. as_secs ( ) ;
1801
+ }
1802
+
1803
+ #[ kani:: proof_for_contract( Duration :: subsec_millis) ]
1804
+ fn duration_subsec_millis ( ) {
1805
+ let dur = safe_duration ( ) ;
1806
+ let _ = dur. subsec_millis ( ) ;
1807
+ }
1808
+
1809
+ #[ kani:: proof_for_contract( Duration :: subsec_millis) ]
1810
+ #[ kani:: should_panic]
1811
+ fn duration_subsec_millis_panics ( ) {
1812
+ let dur = kani:: any :: < Duration > ( ) ;
1813
+ let _ = dur. subsec_millis ( ) ;
1814
+ }
1815
+
1816
+ #[ kani:: proof_for_contract( Duration :: subsec_micros) ]
1817
+ fn duration_subsec_micros ( ) {
1818
+ let dur = safe_duration ( ) ;
1819
+ let _ = dur. subsec_micros ( ) ;
1820
+ }
1821
+
1822
+ #[ kani:: proof_for_contract( Duration :: subsec_micros) ]
1823
+ #[ kani:: should_panic]
1824
+ fn duration_subsec_micros_panics ( ) {
1825
+ let dur = kani:: any :: < Duration > ( ) ;
1826
+ let _ = dur. subsec_micros ( ) ;
1827
+ }
1828
+
1829
+ #[ kani:: proof_for_contract( Duration :: subsec_nanos) ]
1830
+ fn duration_subsec_nanos ( ) {
1831
+ let dur = safe_duration ( ) ;
1832
+ let _ = dur. subsec_nanos ( ) ;
1833
+ }
1834
+
1835
+ #[ kani:: proof_for_contract( Duration :: subsec_nanos) ]
1836
+ #[ kani:: should_panic]
1837
+ fn duration_subsec_nanos_panics ( ) {
1838
+ let dur = kani:: any :: < Duration > ( ) ;
1839
+ let _ = dur. subsec_nanos ( ) ;
1840
+ }
1841
+
1842
+ #[ kani:: proof_for_contract( Duration :: as_millis) ]
1843
+ fn duration_as_millis ( ) {
1844
+ let dur = safe_duration ( ) ;
1845
+ let _ = dur. as_millis ( ) ;
1846
+ }
1847
+
1848
+ #[ kani:: proof_for_contract( Duration :: as_millis) ]
1849
+ #[ kani:: should_panic]
1850
+ fn duration_as_millis_panics ( ) {
1851
+ let dur = kani:: any :: < Duration > ( ) ;
1852
+ let _ = dur. as_millis ( ) ;
1853
+ }
1854
+
1855
+ #[ kani:: proof_for_contract( Duration :: as_micros) ]
1856
+ fn duration_as_micros ( ) {
1857
+ let dur = safe_duration ( ) ;
1858
+ let _ = dur. as_micros ( ) ;
1859
+ }
1860
+
1861
+ #[ kani:: proof_for_contract( Duration :: as_micros) ]
1862
+ #[ kani:: should_panic]
1863
+ fn duration_as_micros_panics ( ) {
1864
+ let dur = kani:: any :: < Duration > ( ) ;
1865
+ let _ = dur. as_micros ( ) ;
1866
+ }
1867
+
1868
+ #[ kani:: proof]
1869
+ fn duration_as_nanos ( ) {
1870
+ let dur = safe_duration ( ) ;
1871
+ let _ = dur. as_nanos ( ) ;
1872
+ }
1873
+
1874
+ #[ kani:: proof]
1875
+ #[ kani:: should_panic]
1876
+ fn duration_as_nanos_panics ( ) {
1877
+ let dur = kani:: any :: < Duration > ( ) ;
1878
+ let _ = dur. as_nanos ( ) ;
1879
+ }
1880
+
1881
+ #[ kani:: proof_for_contract( Duration :: checked_add) ]
1882
+ fn duration_checked_add ( ) {
1883
+ let d0 = safe_duration ( ) ;
1884
+ let d1 = safe_duration ( ) ;
1885
+ let _ = d0. checked_add ( d1) ;
1886
+ }
1887
+
1888
+ #[ kani:: proof_for_contract( Duration :: checked_add) ]
1889
+ #[ kani:: should_panic]
1890
+ fn duration_checked_add_panics ( ) {
1891
+ let d0 = kani:: any :: < Duration > ( ) ;
1892
+ let d1 = kani:: any :: < Duration > ( ) ;
1893
+ let _ = d0. checked_add ( d1) ;
1894
+ }
1895
+
1896
+ #[ kani:: proof_for_contract( Duration :: checked_sub) ]
1897
+ fn duration_checked_sub ( ) {
1898
+ let d0 = safe_duration ( ) ;
1899
+ let d1 = safe_duration ( ) ;
1900
+ let _ = d0. checked_sub ( d1) ;
1901
+ }
1902
+
1903
+ #[ kani:: proof_for_contract( Duration :: checked_sub) ]
1904
+ #[ kani:: should_panic]
1905
+ fn duration_checked_sub_panics ( ) {
1906
+ let d0 = kani:: any :: < Duration > ( ) ;
1907
+ let d1 = kani:: any :: < Duration > ( ) ;
1908
+ let _ = d0. checked_sub ( d1) ;
1909
+ }
1910
+
1911
+ #[ kani:: proof_for_contract( Duration :: checked_mul) ]
1912
+ fn duration_checked_mul ( ) {
1913
+ let d0 = safe_duration ( ) ;
1914
+ let amt = kani:: any :: < u32 > ( ) ;
1915
+ let _ = d0. checked_mul ( amt) ;
1916
+ }
1917
+
1918
+ #[ kani:: proof_for_contract( Duration :: checked_mul) ]
1919
+ #[ kani:: should_panic]
1920
+ fn duration_checked_mul_panics ( ) {
1921
+ let d0 = kani:: any :: < Duration > ( ) ;
1922
+ let amt = kani:: any :: < u32 > ( ) ;
1923
+ let _ = d0. checked_mul ( amt) ;
1924
+ }
1925
+
1926
+ #[ kani:: proof_for_contract( Duration :: checked_div) ]
1927
+ fn duration_checked_div ( ) {
1928
+ let d0 = safe_duration ( ) ;
1929
+ let amt = kani:: any :: < u32 > ( ) ;
1930
+ let _ = d0. checked_div ( amt) ;
1931
+ }
1932
+
1933
+ #[ kani:: proof_for_contract( Duration :: checked_div) ]
1934
+ #[ kani:: should_panic]
1935
+ fn duration_checked_div_panics ( ) {
1936
+ let d0 = kani:: any :: < Duration > ( ) ;
1937
+ let amt = kani:: any :: < u32 > ( ) ;
1938
+ let _ = d0. checked_div ( amt) ;
1939
+ }
1940
+ }
0 commit comments