Skip to content

Commit 59c9803

Browse files
authored
Rollup merge of rust-lang#76114 - marmeladema:duration-saturating-ops, r=shepmaster
Add saturating methods for `Duration` In some project, I needed a `saturating_add` method for `Duration`. I implemented it myself but i thought it would be a nice addition to the standard library as it matches closely with the integers types. 3 new methods have been introduced and are gated by the new `duration_saturating_ops` unstable feature: * `Duration::saturating_add` * `Duration::saturating_sub` * `Duration::saturating_mul` If have left the tracking issue to `none` for now as I want first to understand if those methods would be acceptable at all. If agreed, I'll update the PR with the tracking issue. Further more, to match the behavior of integers types, I introduced 2 associated constants: * `Duration::MIN`: this one is somehow a duplicate from `Duration::zero()` method, but at the time this method was added, `MIN` was rejected as it was considered a different semantic (see rust-lang#72790 (comment)). * `Duration::MAX` Both have been gated by the already existing unstable feature `duration_constants`, I can introduce a new unstable feature if needed or just re-use the `duration_saturating_ops`. We might have to decide whether: * `MIN` should be replaced by `ZERO`? * associated constants over methods?
2 parents ed67c2d + d4b35f7 commit 59c9803

File tree

4 files changed

+130
-0
lines changed

4 files changed

+130
-0
lines changed

core/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
#![feature(doc_cfg)]
101101
#![feature(doc_spotlight)]
102102
#![feature(duration_consts_2)]
103+
#![feature(duration_saturating_ops)]
103104
#![feature(extern_types)]
104105
#![feature(fundamental)]
105106
#![feature(intrinsics)]

core/src/time.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,34 @@ impl Duration {
108108
#[unstable(feature = "duration_constants", issue = "57391")]
109109
pub const NANOSECOND: Duration = Duration::from_nanos(1);
110110

111+
/// The minimum duration.
112+
///
113+
/// # Examples
114+
///
115+
/// ```
116+
/// #![feature(duration_constants)]
117+
/// use std::time::Duration;
118+
///
119+
/// assert_eq!(Duration::MIN, Duration::new(0, 0));
120+
/// ```
121+
#[unstable(feature = "duration_constants", issue = "57391")]
122+
pub const MIN: Duration = Duration::from_nanos(0);
123+
124+
/// The maximum duration.
125+
///
126+
/// It is roughly equal to a duration of 584,942,417,355 years.
127+
///
128+
/// # Examples
129+
///
130+
/// ```
131+
/// #![feature(duration_constants)]
132+
/// use std::time::Duration;
133+
///
134+
/// assert_eq!(Duration::MAX, Duration::new(u64::MAX, 1_000_000_000 - 1));
135+
/// ```
136+
#[unstable(feature = "duration_constants", issue = "57391")]
137+
pub const MAX: Duration = Duration::new(u64::MAX, NANOS_PER_SEC - 1);
138+
111139
/// Creates a new `Duration` from the specified number of whole seconds and
112140
/// additional nanoseconds.
113141
///
@@ -450,6 +478,29 @@ impl Duration {
450478
}
451479
}
452480

481+
/// Saturating `Duration` addition. Computes `self + other`, returning [`Duration::MAX`]
482+
/// if overflow occurred.
483+
///
484+
/// # Examples
485+
///
486+
/// ```
487+
/// #![feature(duration_saturating_ops)]
488+
/// #![feature(duration_constants)]
489+
/// use std::time::Duration;
490+
///
491+
/// assert_eq!(Duration::new(0, 0).saturating_add(Duration::new(0, 1)), Duration::new(0, 1));
492+
/// assert_eq!(Duration::new(1, 0).saturating_add(Duration::new(u64::MAX, 0)), Duration::MAX);
493+
/// ```
494+
#[unstable(feature = "duration_saturating_ops", issue = "76416")]
495+
#[inline]
496+
#[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
497+
pub const fn saturating_add(self, rhs: Duration) -> Duration {
498+
match self.checked_add(rhs) {
499+
Some(res) => res,
500+
None => Duration::MAX,
501+
}
502+
}
503+
453504
/// Checked `Duration` subtraction. Computes `self - other`, returning [`None`]
454505
/// if the result would be negative or if overflow occurred.
455506
///
@@ -485,6 +536,29 @@ impl Duration {
485536
}
486537
}
487538

539+
/// Saturating `Duration` subtraction. Computes `self - other`, returning [`Duration::MIN`]
540+
/// if the result would be negative or if overflow occurred.
541+
///
542+
/// # Examples
543+
///
544+
/// ```
545+
/// #![feature(duration_saturating_ops)]
546+
/// #![feature(duration_constants)]
547+
/// use std::time::Duration;
548+
///
549+
/// assert_eq!(Duration::new(0, 1).saturating_sub(Duration::new(0, 0)), Duration::new(0, 1));
550+
/// assert_eq!(Duration::new(0, 0).saturating_sub(Duration::new(0, 1)), Duration::MIN);
551+
/// ```
552+
#[unstable(feature = "duration_saturating_ops", issue = "76416")]
553+
#[inline]
554+
#[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
555+
pub const fn saturating_sub(self, rhs: Duration) -> Duration {
556+
match self.checked_sub(rhs) {
557+
Some(res) => res,
558+
None => Duration::MIN,
559+
}
560+
}
561+
488562
/// Checked `Duration` multiplication. Computes `self * other`, returning
489563
/// [`None`] if overflow occurred.
490564
///
@@ -515,6 +589,29 @@ impl Duration {
515589
None
516590
}
517591

592+
/// Saturating `Duration` multiplication. Computes `self * other`, returning
593+
/// [`Duration::MAX`] if overflow occurred.
594+
///
595+
/// # Examples
596+
///
597+
/// ```
598+
/// #![feature(duration_saturating_ops)]
599+
/// #![feature(duration_constants)]
600+
/// use std::time::Duration;
601+
///
602+
/// assert_eq!(Duration::new(0, 500_000_001).saturating_mul(2), Duration::new(1, 2));
603+
/// assert_eq!(Duration::new(u64::MAX - 1, 0).saturating_mul(2), Duration::MAX);
604+
/// ```
605+
#[unstable(feature = "duration_saturating_ops", issue = "76416")]
606+
#[inline]
607+
#[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
608+
pub const fn saturating_mul(self, rhs: u32) -> Duration {
609+
match self.checked_mul(rhs) {
610+
Some(res) => res,
611+
None => Duration::MAX,
612+
}
613+
}
614+
518615
/// Checked `Duration` division. Computes `self / other`, returning [`None`]
519616
/// if `other == 0`.
520617
///

core/tests/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#![feature(core_private_diy_float)]
1111
#![feature(debug_non_exhaustive)]
1212
#![feature(dec2flt)]
13+
#![feature(duration_constants)]
14+
#![feature(duration_saturating_ops)]
1315
#![feature(exact_size_is_empty)]
1416
#![feature(fixed_size_array)]
1517
#![feature(flt2dec)]

core/tests/time.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,16 @@ fn checked_add() {
8989
assert_eq!(Duration::new(1, 0).checked_add(Duration::new(u64::MAX, 0)), None);
9090
}
9191

92+
#[test]
93+
fn saturating_add() {
94+
assert_eq!(Duration::new(0, 0).saturating_add(Duration::new(0, 1)), Duration::new(0, 1));
95+
assert_eq!(
96+
Duration::new(0, 500_000_000).saturating_add(Duration::new(0, 500_000_001)),
97+
Duration::new(1, 1)
98+
);
99+
assert_eq!(Duration::new(1, 0).saturating_add(Duration::new(u64::MAX, 0)), Duration::MAX);
100+
}
101+
92102
#[test]
93103
fn sub() {
94104
assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), Duration::new(0, 1));
@@ -107,6 +117,17 @@ fn checked_sub() {
107117
assert_eq!(zero.checked_sub(one_sec), None);
108118
}
109119

120+
#[test]
121+
fn saturating_sub() {
122+
let zero = Duration::new(0, 0);
123+
let one_nano = Duration::new(0, 1);
124+
let one_sec = Duration::new(1, 0);
125+
assert_eq!(one_nano.saturating_sub(zero), Duration::new(0, 1));
126+
assert_eq!(one_sec.saturating_sub(one_nano), Duration::new(0, 999_999_999));
127+
assert_eq!(zero.saturating_sub(one_nano), Duration::MIN);
128+
assert_eq!(zero.saturating_sub(one_sec), Duration::MIN);
129+
}
130+
110131
#[test]
111132
#[should_panic]
112133
fn sub_bad1() {
@@ -136,6 +157,15 @@ fn checked_mul() {
136157
assert_eq!(Duration::new(u64::MAX - 1, 0).checked_mul(2), None);
137158
}
138159

160+
#[test]
161+
fn saturating_mul() {
162+
assert_eq!(Duration::new(0, 1).saturating_mul(2), Duration::new(0, 2));
163+
assert_eq!(Duration::new(1, 1).saturating_mul(3), Duration::new(3, 3));
164+
assert_eq!(Duration::new(0, 500_000_001).saturating_mul(4), Duration::new(2, 4));
165+
assert_eq!(Duration::new(0, 500_000_001).saturating_mul(4000), Duration::new(2000, 4000));
166+
assert_eq!(Duration::new(u64::MAX - 1, 0).saturating_mul(2), Duration::MAX);
167+
}
168+
139169
#[test]
140170
fn div() {
141171
assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0));

0 commit comments

Comments
 (0)