@@ -16,6 +16,8 @@ use core::{fmt, i64};
1616#[ cfg( feature = "std" ) ]
1717use std:: error:: Error ;
1818
19+ use crate :: { expect, try_opt} ;
20+
1921#[ cfg( feature = "rkyv" ) ]
2022use rkyv:: { Archive , Deserialize , Serialize } ;
2123
@@ -75,88 +77,88 @@ impl Duration {
7577 /// Panics when the duration is out of bounds.
7678 #[ inline]
7779 #[ must_use]
78- pub fn weeks ( weeks : i64 ) -> Duration {
79- Duration :: try_weeks ( weeks) . expect ( "Duration::weeks out of bounds" )
80+ pub const fn weeks ( weeks : i64 ) -> Duration {
81+ expect ! ( Duration :: try_weeks( weeks) , "Duration::weeks out of bounds" )
8082 }
8183
8284 /// Makes a new `Duration` with given number of weeks.
8385 /// Equivalent to `Duration::seconds(weeks * 7 * 24 * 60 * 60)` with overflow checks.
8486 /// Returns `None` when the duration is out of bounds.
8587 #[ inline]
86- pub fn try_weeks ( weeks : i64 ) -> Option < Duration > {
87- weeks. checked_mul ( SECS_PER_WEEK ) . and_then ( Duration :: try_seconds )
88+ pub const fn try_weeks ( weeks : i64 ) -> Option < Duration > {
89+ Duration :: try_seconds ( try_opt ! ( weeks. checked_mul( SECS_PER_WEEK ) ) )
8890 }
8991
9092 /// Makes a new `Duration` with given number of days.
9193 /// Equivalent to `Duration::seconds(days * 24 * 60 * 60)` with overflow checks.
9294 /// Panics when the duration is out of bounds.
9395 #[ inline]
9496 #[ must_use]
95- pub fn days ( days : i64 ) -> Duration {
96- Duration :: try_days ( days) . expect ( "Duration::days out of bounds" )
97+ pub const fn days ( days : i64 ) -> Duration {
98+ expect ! ( Duration :: try_days( days) , "Duration::days out of bounds" )
9799 }
98100
99101 /// Makes a new `Duration` with given number of days.
100102 /// Equivalent to `Duration::seconds(days * 24 * 60 * 60)` with overflow checks.
101103 /// Returns `None` when the duration is out of bounds.
102104 #[ inline]
103- pub fn try_days ( days : i64 ) -> Option < Duration > {
104- days. checked_mul ( SECS_PER_DAY ) . and_then ( Duration :: try_seconds )
105+ pub const fn try_days ( days : i64 ) -> Option < Duration > {
106+ Duration :: try_seconds ( try_opt ! ( days. checked_mul( SECS_PER_DAY ) ) )
105107 }
106108
107109 /// Makes a new `Duration` with given number of hours.
108110 /// Equivalent to `Duration::seconds(hours * 60 * 60)` with overflow checks.
109111 /// Panics when the duration is out of bounds.
110112 #[ inline]
111113 #[ must_use]
112- pub fn hours ( hours : i64 ) -> Duration {
113- Duration :: try_hours ( hours) . expect ( "Duration::hours ouf of bounds" )
114+ pub const fn hours ( hours : i64 ) -> Duration {
115+ expect ! ( Duration :: try_hours( hours) , "Duration::hours ouf of bounds" )
114116 }
115117
116118 /// Makes a new `Duration` with given number of hours.
117119 /// Equivalent to `Duration::seconds(hours * 60 * 60)` with overflow checks.
118120 /// Returns `None` when the duration is out of bounds.
119121 #[ inline]
120- pub fn try_hours ( hours : i64 ) -> Option < Duration > {
121- hours. checked_mul ( SECS_PER_HOUR ) . and_then ( Duration :: try_seconds )
122+ pub const fn try_hours ( hours : i64 ) -> Option < Duration > {
123+ Duration :: try_seconds ( try_opt ! ( hours. checked_mul( SECS_PER_HOUR ) ) )
122124 }
123125
124126 /// Makes a new `Duration` with given number of minutes.
125127 /// Equivalent to `Duration::seconds(minutes * 60)` with overflow checks.
126128 /// Panics when the duration is out of bounds.
127129 #[ inline]
128130 #[ must_use]
129- pub fn minutes ( minutes : i64 ) -> Duration {
130- Duration :: try_minutes ( minutes) . expect ( "Duration::minutes out of bounds" )
131+ pub const fn minutes ( minutes : i64 ) -> Duration {
132+ expect ! ( Duration :: try_minutes( minutes) , "Duration::minutes out of bounds" )
131133 }
132134
133135 /// Makes a new `Duration` with given number of minutes.
134136 /// Equivalent to `Duration::seconds(minutes * 60)` with overflow checks.
135137 /// Returns `None` when the duration is out of bounds.
136138 #[ inline]
137- pub fn try_minutes ( minutes : i64 ) -> Option < Duration > {
138- minutes. checked_mul ( SECS_PER_MINUTE ) . and_then ( Duration :: try_seconds )
139+ pub const fn try_minutes ( minutes : i64 ) -> Option < Duration > {
140+ Duration :: try_seconds ( try_opt ! ( minutes. checked_mul( SECS_PER_MINUTE ) ) )
139141 }
140142
141143 /// Makes a new `Duration` with given number of seconds.
142144 /// Panics when the duration is more than `i64::MAX` milliseconds
143145 /// or less than `i64::MIN` milliseconds.
144146 #[ inline]
145147 #[ must_use]
146- pub fn seconds ( seconds : i64 ) -> Duration {
147- Duration :: try_seconds ( seconds) . expect ( "Duration::seconds out of bounds" )
148+ pub const fn seconds ( seconds : i64 ) -> Duration {
149+ expect ! ( Duration :: try_seconds( seconds) , "Duration::seconds out of bounds" )
148150 }
149151
150152 /// Makes a new `Duration` with given number of seconds.
151153 /// Returns `None` when the duration is more than `i64::MAX` milliseconds
152154 /// or less than `i64::MIN` milliseconds.
153155 #[ inline]
154- pub fn try_seconds ( seconds : i64 ) -> Option < Duration > {
156+ pub const fn try_seconds ( seconds : i64 ) -> Option < Duration > {
155157 let d = Duration { secs : seconds, nanos : 0 } ;
156- if d < MIN || d > MAX {
157- return None ;
158+ match d. out_of_bounds ( ) {
159+ true => None ,
160+ false => Some ( d) ,
158161 }
159- Some ( d)
160162 }
161163
162164 /// Makes a new `Duration` with given number of milliseconds.
@@ -253,7 +255,7 @@ impl Duration {
253255
254256 /// Add two durations, returning `None` if overflow occurred.
255257 #[ must_use]
256- pub fn checked_add ( & self , rhs : & Duration ) -> Option < Duration > {
258+ pub const fn checked_add ( & self , rhs : & Duration ) -> Option < Duration > {
257259 let mut secs = try_opt ! ( self . secs. checked_add( rhs. secs) ) ;
258260 let mut nanos = self . nanos + rhs. nanos ;
259261 if nanos >= NANOS_PER_SEC {
@@ -263,16 +265,15 @@ impl Duration {
263265 let d = Duration { secs, nanos } ;
264266 // Even if d is within the bounds of i64 seconds,
265267 // it might still overflow i64 milliseconds.
266- if d < MIN || d > MAX {
267- None
268- } else {
269- Some ( d)
268+ match d. out_of_bounds ( ) {
269+ true => None ,
270+ false => Some ( d) ,
270271 }
271272 }
272273
273274 /// Subtract two durations, returning `None` if overflow occurred.
274275 #[ must_use]
275- pub fn checked_sub ( & self , rhs : & Duration ) -> Option < Duration > {
276+ pub const fn checked_sub ( & self , rhs : & Duration ) -> Option < Duration > {
276277 let mut secs = try_opt ! ( self . secs. checked_sub( rhs. secs) ) ;
277278 let mut nanos = self . nanos - rhs. nanos ;
278279 if nanos < 0 {
@@ -282,10 +283,9 @@ impl Duration {
282283 let d = Duration { secs, nanos } ;
283284 // Even if d is within the bounds of i64 seconds,
284285 // it might still overflow i64 milliseconds.
285- if d < MIN || d > MAX {
286- None
287- } else {
288- Some ( d)
286+ match d. out_of_bounds ( ) {
287+ true => None ,
288+ false => Some ( d) ,
289289 }
290290 }
291291
@@ -327,13 +327,13 @@ impl Duration {
327327 ///
328328 /// This function errors when original duration is larger than the maximum
329329 /// value supported for this type.
330- pub fn from_std ( duration : StdDuration ) -> Result < Duration , OutOfRangeError > {
330+ pub const fn from_std ( duration : StdDuration ) -> Result < Duration , OutOfRangeError > {
331331 // We need to check secs as u64 before coercing to i64
332332 if duration. as_secs ( ) > MAX . secs as u64 {
333333 return Err ( OutOfRangeError ( ( ) ) ) ;
334334 }
335335 let d = Duration { secs : duration. as_secs ( ) as i64 , nanos : duration. subsec_nanos ( ) as i32 } ;
336- if d > MAX {
336+ if d. out_of_bounds ( ) {
337337 return Err ( OutOfRangeError ( ( ) ) ) ;
338338 }
339339 Ok ( d)
@@ -343,12 +343,21 @@ impl Duration {
343343 ///
344344 /// This function errors when duration is less than zero. As standard
345345 /// library implementation is limited to non-negative values.
346+ // TODO: make this method const once our MSRV is 1.58+
346347 pub fn to_std ( & self ) -> Result < StdDuration , OutOfRangeError > {
347348 if self . secs < 0 {
348349 return Err ( OutOfRangeError ( ( ) ) ) ;
349350 }
350351 Ok ( StdDuration :: new ( self . secs as u64 , self . nanos as u32 ) )
351352 }
353+
354+ /// Returns `true` if d < MIN || d > MAX
355+ const fn out_of_bounds ( & self ) -> bool {
356+ self . secs < MIN . secs
357+ || self . secs > MAX . secs
358+ || ( self . secs == MAX . secs && self . nanos > MAX . nanos )
359+ || ( self . secs == MIN . secs && self . nanos < MIN . nanos )
360+ }
352361}
353362
354363impl Neg for Duration {
0 commit comments