@@ -17,6 +17,8 @@ use core::{fmt, i64};
1717#[ cfg( feature = "std" ) ]
1818use std:: error:: Error ;
1919
20+ use crate :: { expect, try_opt} ;
21+
2022#[ cfg( feature = "rkyv" ) ]
2123use rkyv:: { Archive , Deserialize , Serialize } ;
2224
@@ -76,88 +78,88 @@ impl Duration {
7678 /// Panics when the duration is out of bounds.
7779 #[ inline]
7880 #[ must_use]
79- pub fn weeks ( weeks : i64 ) -> Duration {
80- Duration :: try_weeks ( weeks) . expect ( "Duration::weeks out of bounds" )
81+ pub const fn weeks ( weeks : i64 ) -> Duration {
82+ expect ! ( Duration :: try_weeks( weeks) , "Duration::weeks out of bounds" )
8183 }
8284
8385 /// Makes a new `Duration` with given number of weeks.
8486 /// Equivalent to `Duration::seconds(weeks * 7 * 24 * 60 * 60)` with overflow checks.
8587 /// Returns `None` when the duration is out of bounds.
8688 #[ inline]
87- pub fn try_weeks ( weeks : i64 ) -> Option < Duration > {
88- weeks. checked_mul ( SECS_PER_WEEK ) . and_then ( Duration :: try_seconds )
89+ pub const fn try_weeks ( weeks : i64 ) -> Option < Duration > {
90+ Duration :: try_seconds ( try_opt ! ( weeks. checked_mul( SECS_PER_WEEK ) ) )
8991 }
9092
9193 /// Makes a new `Duration` with given number of days.
9294 /// Equivalent to `Duration::seconds(days * 24 * 60 * 60)` with overflow checks.
9395 /// Panics when the duration is out of bounds.
9496 #[ inline]
9597 #[ must_use]
96- pub fn days ( days : i64 ) -> Duration {
97- Duration :: try_days ( days) . expect ( "Duration::days out of bounds" )
98+ pub const fn days ( days : i64 ) -> Duration {
99+ expect ! ( Duration :: try_days( days) , "Duration::days out of bounds" )
98100 }
99101
100102 /// Makes a new `Duration` with given number of days.
101103 /// Equivalent to `Duration::seconds(days * 24 * 60 * 60)` with overflow checks.
102104 /// Returns `None` when the duration is out of bounds.
103105 #[ inline]
104- pub fn try_days ( days : i64 ) -> Option < Duration > {
105- days. checked_mul ( SECS_PER_DAY ) . and_then ( Duration :: try_seconds )
106+ pub const fn try_days ( days : i64 ) -> Option < Duration > {
107+ Duration :: try_seconds ( try_opt ! ( days. checked_mul( SECS_PER_DAY ) ) )
106108 }
107109
108110 /// Makes a new `Duration` with given number of hours.
109111 /// Equivalent to `Duration::seconds(hours * 60 * 60)` with overflow checks.
110112 /// Panics when the duration is out of bounds.
111113 #[ inline]
112114 #[ must_use]
113- pub fn hours ( hours : i64 ) -> Duration {
114- Duration :: try_hours ( hours) . expect ( "Duration::hours ouf of bounds" )
115+ pub const fn hours ( hours : i64 ) -> Duration {
116+ expect ! ( Duration :: try_hours( hours) , "Duration::hours ouf of bounds" )
115117 }
116118
117119 /// Makes a new `Duration` with given number of hours.
118120 /// Equivalent to `Duration::seconds(hours * 60 * 60)` with overflow checks.
119121 /// Returns `None` when the duration is out of bounds.
120122 #[ inline]
121- pub fn try_hours ( hours : i64 ) -> Option < Duration > {
122- hours. checked_mul ( SECS_PER_HOUR ) . and_then ( Duration :: try_seconds )
123+ pub const fn try_hours ( hours : i64 ) -> Option < Duration > {
124+ Duration :: try_seconds ( try_opt ! ( hours. checked_mul( SECS_PER_HOUR ) ) )
123125 }
124126
125127 /// Makes a new `Duration` with given number of minutes.
126128 /// Equivalent to `Duration::seconds(minutes * 60)` with overflow checks.
127129 /// Panics when the duration is out of bounds.
128130 #[ inline]
129131 #[ must_use]
130- pub fn minutes ( minutes : i64 ) -> Duration {
131- Duration :: try_minutes ( minutes) . expect ( "Duration::minutes out of bounds" )
132+ pub const fn minutes ( minutes : i64 ) -> Duration {
133+ expect ! ( Duration :: try_minutes( minutes) , "Duration::minutes out of bounds" )
132134 }
133135
134136 /// Makes a new `Duration` with given number of minutes.
135137 /// Equivalent to `Duration::seconds(minutes * 60)` with overflow checks.
136138 /// Returns `None` when the duration is out of bounds.
137139 #[ inline]
138- pub fn try_minutes ( minutes : i64 ) -> Option < Duration > {
139- minutes. checked_mul ( SECS_PER_MINUTE ) . and_then ( Duration :: try_seconds )
140+ pub const fn try_minutes ( minutes : i64 ) -> Option < Duration > {
141+ Duration :: try_seconds ( try_opt ! ( minutes. checked_mul( SECS_PER_MINUTE ) ) )
140142 }
141143
142144 /// Makes a new `Duration` with given number of seconds.
143145 /// Panics when the duration is more than `i64::MAX` seconds
144146 /// or less than `i64::MIN` seconds.
145147 #[ inline]
146148 #[ must_use]
147- pub fn seconds ( seconds : i64 ) -> Duration {
148- Duration :: try_seconds ( seconds) . expect ( "Duration::seconds out of bounds" )
149+ pub const fn seconds ( seconds : i64 ) -> Duration {
150+ expect ! ( Duration :: try_seconds( seconds) , "Duration::seconds out of bounds" )
149151 }
150152
151153 /// Makes a new `Duration` with given number of seconds.
152154 /// Returns `None` when the duration is more than `i64::MAX` milliseconds
153155 /// or less than `i64::MIN` milliseconds.
154156 #[ inline]
155- pub fn try_seconds ( seconds : i64 ) -> Option < Duration > {
157+ pub const fn try_seconds ( seconds : i64 ) -> Option < Duration > {
156158 let d = Duration { secs : seconds, nanos : 0 } ;
157- if d < MIN || d > MAX {
158- return None ;
159+ match d. out_of_bounds ( ) {
160+ true => None ,
161+ false => Some ( d) ,
159162 }
160- Some ( d)
161163 }
162164
163165 /// Makes a new `Duration` with given number of milliseconds.
@@ -254,7 +256,7 @@ impl Duration {
254256
255257 /// Add two durations, returning `None` if overflow occurred.
256258 #[ must_use]
257- pub fn checked_add ( & self , rhs : & Duration ) -> Option < Duration > {
259+ pub const fn checked_add ( & self , rhs : & Duration ) -> Option < Duration > {
258260 let mut secs = try_opt ! ( self . secs. checked_add( rhs. secs) ) ;
259261 let mut nanos = self . nanos + rhs. nanos ;
260262 if nanos >= NANOS_PER_SEC {
@@ -264,16 +266,15 @@ impl Duration {
264266 let d = Duration { secs, nanos } ;
265267 // Even if d is within the bounds of i64 seconds,
266268 // it might still overflow i64 milliseconds.
267- if d < MIN || d > MAX {
268- None
269- } else {
270- Some ( d)
269+ match d. out_of_bounds ( ) {
270+ true => None ,
271+ false => Some ( d) ,
271272 }
272273 }
273274
274275 /// Subtract two durations, returning `None` if overflow occurred.
275276 #[ must_use]
276- pub fn checked_sub ( & self , rhs : & Duration ) -> Option < Duration > {
277+ pub const fn checked_sub ( & self , rhs : & Duration ) -> Option < Duration > {
277278 let mut secs = try_opt ! ( self . secs. checked_sub( rhs. secs) ) ;
278279 let mut nanos = self . nanos - rhs. nanos ;
279280 if nanos < 0 {
@@ -283,10 +284,9 @@ impl Duration {
283284 let d = Duration { secs, nanos } ;
284285 // Even if d is within the bounds of i64 seconds,
285286 // it might still overflow i64 milliseconds.
286- if d < MIN || d > MAX {
287- None
288- } else {
289- Some ( d)
287+ match d. out_of_bounds ( ) {
288+ true => None ,
289+ false => Some ( d) ,
290290 }
291291 }
292292
@@ -329,13 +329,13 @@ impl Duration {
329329 /// This function errors when original duration is larger than the maximum
330330 /// value supported for this type.
331331 #[ cfg( feature = "std" ) ]
332- pub fn from_std ( duration : StdDuration ) -> Result < Duration , OutOfRangeError > {
332+ pub const fn from_std ( duration : StdDuration ) -> Result < Duration , OutOfRangeError > {
333333 // We need to check secs as u64 before coercing to i64
334334 if duration. as_secs ( ) > MAX . secs as u64 {
335335 return Err ( OutOfRangeError ( ( ) ) ) ;
336336 }
337337 let d = Duration { secs : duration. as_secs ( ) as i64 , nanos : duration. subsec_nanos ( ) as i32 } ;
338- if d > MAX {
338+ if d. out_of_bounds ( ) {
339339 return Err ( OutOfRangeError ( ( ) ) ) ;
340340 }
341341 Ok ( d)
@@ -345,13 +345,22 @@ impl Duration {
345345 ///
346346 /// This function errors when duration is less than zero. As standard
347347 /// library implementation is limited to non-negative values.
348+ // TODO: make this method const once our MSRV is 1.58+
348349 #[ cfg( feature = "std" ) ]
349350 pub fn to_std ( & self ) -> Result < StdDuration , OutOfRangeError > {
350351 if self . secs < 0 {
351352 return Err ( OutOfRangeError ( ( ) ) ) ;
352353 }
353354 Ok ( StdDuration :: new ( self . secs as u64 , self . nanos as u32 ) )
354355 }
356+
357+ /// Returns `true` if d < MIN || d > MAX
358+ const fn out_of_bounds ( & self ) -> bool {
359+ self . secs < MIN . secs
360+ || self . secs > MAX . secs
361+ || ( self . secs == MAX . secs && self . nanos > MAX . nanos )
362+ || ( self . secs == MIN . secs && self . nanos < MIN . nanos )
363+ }
355364}
356365
357366impl Neg for Duration {
0 commit comments