Skip to content

Commit 0995d40

Browse files
committed
Make all methods on Duration const
1 parent e5d3724 commit 0995d40

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
@@ -16,6 +16,8 @@ use core::{fmt, i64};
1616
#[cfg(feature = "std")]
1717
use std::error::Error;
1818

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

354363
impl Neg for Duration {

0 commit comments

Comments
 (0)