1919//! assert_eq!(total, Duration::new(10, 7));
2020//! ```
2121
22+ use safety:: { ensures, Invariant } ;
2223use crate :: fmt;
2324use crate :: iter:: Sum ;
2425use crate :: ops:: { Add , AddAssign , Div , DivAssign , Mul , MulAssign , Sub , SubAssign } ;
2526
27+ #[ cfg( kani) ]
28+ use crate :: kani;
29+
30+ use crate :: ub_checks:: Invariant ;
31+
2632const NANOS_PER_SEC : u32 = 1_000_000_000 ;
2733const NANOS_PER_MILLI : u32 = 1_000_000 ;
2834const NANOS_PER_MICRO : u32 = 1_000 ;
@@ -43,6 +49,12 @@ const DAYS_PER_WEEK: u64 = 7;
4349#[ rustc_layout_scalar_valid_range_end( 999_999_999 ) ]
4450struct Nanoseconds ( u32 ) ;
4551
52+ impl Invariant for Nanoseconds {
53+ fn is_safe ( & self ) -> bool {
54+ self . 0 < NANOS_PER_SEC
55+ }
56+ }
57+
4658impl Nanoseconds {
4759 // SAFETY: 0 is within the valid range
4860 const ZERO : Self = unsafe { Nanoseconds ( 0 ) } ;
@@ -95,6 +107,7 @@ impl Default for Nanoseconds {
95107#[ stable( feature = "duration" , since = "1.3.0" ) ]
96108#[ derive( Clone , Copy , PartialEq , Eq , PartialOrd , Ord , Hash , Default ) ]
97109#[ cfg_attr( not( test) , rustc_diagnostic_item = "Duration" ) ]
110+ #[ derive( Invariant ) ]
98111pub struct Duration {
99112 secs : u64 ,
100113 nanos : Nanoseconds , // Always 0 <= nanos < NANOS_PER_SEC
@@ -208,6 +221,7 @@ impl Duration {
208221 #[ inline]
209222 #[ must_use]
210223 #[ rustc_const_stable( feature = "duration_consts_2" , since = "1.58.0" ) ]
224+ #[ ensures( |duration| duration. is_safe( ) ) ]
211225 pub const fn new ( secs : u64 , nanos : u32 ) -> Duration {
212226 if nanos < NANOS_PER_SEC {
213227 // SAFETY: nanos < NANOS_PER_SEC, therefore nanos is within the valid range
@@ -238,6 +252,8 @@ impl Duration {
238252 #[ must_use]
239253 #[ inline]
240254 #[ rustc_const_stable( feature = "duration_consts" , since = "1.32.0" ) ]
255+ #[ ensures( |duration| duration. is_safe( ) ) ]
256+ #[ ensures( |duration| duration. secs == secs) ]
241257 pub const fn from_secs ( secs : u64 ) -> Duration {
242258 Duration { secs, nanos : Nanoseconds :: ZERO }
243259 }
@@ -258,6 +274,7 @@ impl Duration {
258274 #[ must_use]
259275 #[ inline]
260276 #[ rustc_const_stable( feature = "duration_consts" , since = "1.32.0" ) ]
277+ #[ ensures( |duration| duration. is_safe( ) ) ]
261278 pub const fn from_millis ( millis : u64 ) -> Duration {
262279 let secs = millis / MILLIS_PER_SEC ;
263280 let subsec_millis = ( millis % MILLIS_PER_SEC ) as u32 ;
@@ -284,6 +301,7 @@ impl Duration {
284301 #[ must_use]
285302 #[ inline]
286303 #[ rustc_const_stable( feature = "duration_consts" , since = "1.32.0" ) ]
304+ #[ ensures( |duration| duration. is_safe( ) ) ]
287305 pub const fn from_micros ( micros : u64 ) -> Duration {
288306 let secs = micros / MICROS_PER_SEC ;
289307 let subsec_micros = ( micros % MICROS_PER_SEC ) as u32 ;
@@ -315,6 +333,7 @@ impl Duration {
315333 #[ must_use]
316334 #[ inline]
317335 #[ rustc_const_stable( feature = "duration_consts" , since = "1.32.0" ) ]
336+ #[ ensures( |duration| duration. is_safe( ) ) ]
318337 pub const fn from_nanos ( nanos : u64 ) -> Duration {
319338 const NANOS_PER_SEC : u64 = self :: NANOS_PER_SEC as u64 ;
320339 let secs = nanos / NANOS_PER_SEC ;
@@ -485,6 +504,7 @@ impl Duration {
485504 #[ rustc_const_stable( feature = "duration_consts" , since = "1.32.0" ) ]
486505 #[ must_use]
487506 #[ inline]
507+ #[ ensures( |secs| * secs == self . secs) ]
488508 pub const fn as_secs ( & self ) -> u64 {
489509 self . secs
490510 }
@@ -508,6 +528,7 @@ impl Duration {
508528 #[ rustc_const_stable( feature = "duration_consts" , since = "1.32.0" ) ]
509529 #[ must_use]
510530 #[ inline]
531+ #[ ensures( |ms| * ms == self . nanos. 0 / NANOS_PER_MILLI ) ]
511532 pub const fn subsec_millis ( & self ) -> u32 {
512533 self . nanos . 0 / NANOS_PER_MILLI
513534 }
@@ -531,6 +552,7 @@ impl Duration {
531552 #[ rustc_const_stable( feature = "duration_consts" , since = "1.32.0" ) ]
532553 #[ must_use]
533554 #[ inline]
555+ #[ ensures( |ms| * ms == self . nanos. 0 / NANOS_PER_MICRO ) ]
534556 pub const fn subsec_micros ( & self ) -> u32 {
535557 self . nanos . 0 / NANOS_PER_MICRO
536558 }
@@ -554,6 +576,7 @@ impl Duration {
554576 #[ rustc_const_stable( feature = "duration_consts" , since = "1.32.0" ) ]
555577 #[ must_use]
556578 #[ inline]
579+ #[ ensures( |nanos| * nanos == self . nanos. 0 ) ]
557580 pub const fn subsec_nanos ( & self ) -> u32 {
558581 self . nanos . 0
559582 }
@@ -572,6 +595,7 @@ impl Duration {
572595 #[ rustc_const_stable( feature = "duration_as_u128" , since = "1.33.0" ) ]
573596 #[ must_use]
574597 #[ inline]
598+ #[ ensures( |ms| * ms == self . secs as u128 * MILLIS_PER_SEC as u128 + ( self . nanos. 0 / NANOS_PER_MILLI ) as u128 ) ]
575599 pub const fn as_millis ( & self ) -> u128 {
576600 self . secs as u128 * MILLIS_PER_SEC as u128 + ( self . nanos . 0 / NANOS_PER_MILLI ) as u128
577601 }
@@ -590,6 +614,7 @@ impl Duration {
590614 #[ rustc_const_stable( feature = "duration_as_u128" , since = "1.33.0" ) ]
591615 #[ must_use]
592616 #[ inline]
617+ #[ ensures( |ms| * ms == self . secs as u128 * MICROS_PER_SEC as u128 + ( self . nanos. 0 / NANOS_PER_MICRO ) as u128 ) ]
593618 pub const fn as_micros ( & self ) -> u128 {
594619 self . secs as u128 * MICROS_PER_SEC as u128 + ( self . nanos . 0 / NANOS_PER_MICRO ) as u128
595620 }
@@ -647,6 +672,7 @@ impl Duration {
647672 without modifying the original"]
648673 #[ inline]
649674 #[ rustc_const_stable( feature = "duration_consts_2" , since = "1.58.0" ) ]
675+ #[ ensures( |duration| duration. is_none( ) || duration. unwrap( ) . is_safe( ) ) ]
650676 pub const fn checked_add ( self , rhs : Duration ) -> Option < Duration > {
651677 if let Some ( mut secs) = self . secs . checked_add ( rhs. secs ) {
652678 let mut nanos = self . nanos . 0 + rhs. nanos . 0 ;
@@ -705,6 +731,7 @@ impl Duration {
705731 without modifying the original"]
706732 #[ inline]
707733 #[ rustc_const_stable( feature = "duration_consts_2" , since = "1.58.0" ) ]
734+ #[ ensures( |duration| duration. is_none( ) || duration. unwrap( ) . is_safe( ) ) ]
708735 pub const fn checked_sub ( self , rhs : Duration ) -> Option < Duration > {
709736 if let Some ( mut secs) = self . secs . checked_sub ( rhs. secs ) {
710737 let nanos = if self . nanos . 0 >= rhs. nanos . 0 {
@@ -761,6 +788,7 @@ impl Duration {
761788 without modifying the original"]
762789 #[ inline]
763790 #[ rustc_const_stable( feature = "duration_consts_2" , since = "1.58.0" ) ]
791+ #[ ensures( |duration| duration. is_none( ) || duration. unwrap( ) . is_safe( ) ) ]
764792 pub const fn checked_mul ( self , rhs : u32 ) -> Option < Duration > {
765793 // Multiply nanoseconds as u64, because it cannot overflow that way.
766794 let total_nanos = self . nanos . 0 as u64 * rhs as u64 ;
@@ -816,13 +844,15 @@ impl Duration {
816844 #[ must_use = "this returns the result of the operation, \
817845 without modifying the original"]
818846 #[ inline]
847+ #[ ensures( |duration| rhs == 0 || duration. unwrap( ) . is_safe( ) ) ]
819848 #[ rustc_const_stable( feature = "duration_consts_2" , since = "1.58.0" ) ]
820849 pub const fn checked_div ( self , rhs : u32 ) -> Option < Duration > {
821850 if rhs != 0 {
822851 let ( secs, extra_secs) = ( self . secs / ( rhs as u64 ) , self . secs % ( rhs as u64 ) ) ;
823852 let ( mut nanos, extra_nanos) = ( self . nanos . 0 / rhs, self . nanos . 0 % rhs) ;
824853 nanos +=
825854 ( ( extra_secs * ( NANOS_PER_SEC as u64 ) + extra_nanos as u64 ) / ( rhs as u64 ) ) as u32 ;
855+ #[ cfg( not( kani) ) ]
826856 debug_assert ! ( nanos < NANOS_PER_SEC ) ;
827857 Some ( Duration :: new ( secs, nanos) )
828858 } else {
@@ -1698,3 +1728,213 @@ impl Duration {
16981728 )
16991729 }
17001730}
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