Skip to content

Commit c76e4bb

Browse files
committed
Make all methods on Duration const
1 parent cadd184 commit c76e4bb

File tree

1 file changed

+43
-34
lines changed

1 file changed

+43
-34
lines changed

src/duration.rs

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ use core::{fmt, i64};
1717
#[cfg(feature = "std")]
1818
use std::error::Error;
1919

20+
use crate::{expect, try_opt};
21+
2022
#[cfg(feature = "rkyv")]
2123
use 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

357366
impl Neg for Duration {

0 commit comments

Comments
 (0)