Skip to content

Commit

Permalink
Add saturating methods for Duration
Browse files Browse the repository at this point in the history
  • Loading branch information
marmeladema committed Sep 7, 2020
1 parent 9fe551a commit b869aa5
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 16 deletions.
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
#![feature(doc_cfg)]
#![feature(doc_spotlight)]
#![feature(duration_consts_2)]
#![feature(duration_saturating_ops)]
#![feature(extern_types)]
#![feature(fundamental)]
#![feature(intrinsics)]
Expand Down
97 changes: 97 additions & 0 deletions library/core/src/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,34 @@ impl Duration {
#[unstable(feature = "duration_constants", issue = "57391")]
pub const NANOSECOND: Duration = Duration::from_nanos(1);

/// The minimum duration.
///
/// # Examples
///
/// ```
/// #![feature(duration_constants)]
/// use std::time::Duration;
///
/// assert_eq!(Duration::MIN, Duration::new(0, 0));
/// ```
#[unstable(feature = "duration_constants", issue = "57391")]
pub const MIN: Duration = Duration::from_nanos(0);

/// The maximum duration.
///
/// It is roughly equal to a duration of 584,942,417,355 years.
///
/// # Examples
///
/// ```
/// #![feature(duration_constants)]
/// use std::time::Duration;
///
/// assert_eq!(Duration::MAX, Duration::new(u64::MAX, 1_000_000_000 - 1));
/// ```
#[unstable(feature = "duration_constants", issue = "57391")]
pub const MAX: Duration = Duration::new(u64::MAX, NANOS_PER_SEC - 1);

/// Creates a new `Duration` from the specified number of whole seconds and
/// additional nanoseconds.
///
Expand Down Expand Up @@ -450,6 +478,29 @@ impl Duration {
}
}

/// Saturating `Duration` addition. Computes `self + other`, returning [`Duration::MAX`]
/// if overflow occurred.
///
/// # Examples
///
/// ```
/// #![feature(duration_saturating_ops)]
/// #![feature(duration_constants)]
/// use std::time::Duration;
///
/// assert_eq!(Duration::new(0, 0).saturating_add(Duration::new(0, 1)), Duration::new(0, 1));
/// assert_eq!(Duration::new(1, 0).saturating_add(Duration::new(u64::MAX, 0)), Duration::MAX);
/// ```
#[unstable(feature = "duration_saturating_ops", issue = "76416")]
#[inline]
#[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
pub const fn saturating_add(self, rhs: Duration) -> Duration {
match self.checked_add(rhs) {
Some(res) => res,
None => Duration::MAX,
}
}

/// Checked `Duration` subtraction. Computes `self - other`, returning [`None`]
/// if the result would be negative or if overflow occurred.
///
Expand Down Expand Up @@ -485,6 +536,29 @@ impl Duration {
}
}

/// Saturating `Duration` subtraction. Computes `self - other`, returning [`Duration::MIN`]
/// if the result would be negative or if overflow occurred.
///
/// # Examples
///
/// ```
/// #![feature(duration_saturating_ops)]
/// #![feature(duration_constants)]
/// use std::time::Duration;
///
/// assert_eq!(Duration::new(0, 1).saturating_sub(Duration::new(0, 0)), Duration::new(0, 1));
/// assert_eq!(Duration::new(0, 0).saturating_sub(Duration::new(0, 1)), Duration::MIN);
/// ```
#[unstable(feature = "duration_saturating_ops", issue = "76416")]
#[inline]
#[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
pub const fn saturating_sub(self, rhs: Duration) -> Duration {
match self.checked_sub(rhs) {
Some(res) => res,
None => Duration::MIN,
}
}

/// Checked `Duration` multiplication. Computes `self * other`, returning
/// [`None`] if overflow occurred.
///
Expand Down Expand Up @@ -515,6 +589,29 @@ impl Duration {
None
}

/// Saturating `Duration` multiplication. Computes `self * other`, returning
/// [`Duration::MAX`] if overflow occurred.
///
/// # Examples
///
/// ```
/// #![feature(duration_saturating_ops)]
/// #![feature(duration_constants)]
/// use std::time::Duration;
///
/// assert_eq!(Duration::new(0, 500_000_001).saturating_mul(2), Duration::new(1, 2));
/// assert_eq!(Duration::new(u64::MAX - 1, 0).saturating_mul(2), Duration::MAX);
/// ```
#[unstable(feature = "duration_saturating_ops", issue = "76416")]
#[inline]
#[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
pub const fn saturating_mul(self, rhs: u32) -> Duration {
match self.checked_mul(rhs) {
Some(res) => res,
None => Duration::MAX,
}
}

/// Checked `Duration` division. Computes `self / other`, returning [`None`]
/// if `other == 0`.
///
Expand Down
2 changes: 2 additions & 0 deletions library/core/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#![feature(core_private_diy_float)]
#![feature(debug_non_exhaustive)]
#![feature(dec2flt)]
#![feature(duration_constants)]
#![feature(duration_saturating_ops)]
#![feature(exact_size_is_empty)]
#![feature(fixed_size_array)]
#![feature(flt2dec)]
Expand Down
30 changes: 30 additions & 0 deletions library/core/tests/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,16 @@ fn checked_add() {
assert_eq!(Duration::new(1, 0).checked_add(Duration::new(u64::MAX, 0)), None);
}

#[test]
fn saturating_add() {
assert_eq!(Duration::new(0, 0).saturating_add(Duration::new(0, 1)), Duration::new(0, 1));
assert_eq!(
Duration::new(0, 500_000_000).saturating_add(Duration::new(0, 500_000_001)),
Duration::new(1, 1)
);
assert_eq!(Duration::new(1, 0).saturating_add(Duration::new(u64::MAX, 0)), Duration::MAX);
}

#[test]
fn sub() {
assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), Duration::new(0, 1));
Expand All @@ -107,6 +117,17 @@ fn checked_sub() {
assert_eq!(zero.checked_sub(one_sec), None);
}

#[test]
fn saturating_sub() {
let zero = Duration::new(0, 0);
let one_nano = Duration::new(0, 1);
let one_sec = Duration::new(1, 0);
assert_eq!(one_nano.saturating_sub(zero), Duration::new(0, 1));
assert_eq!(one_sec.saturating_sub(one_nano), Duration::new(0, 999_999_999));
assert_eq!(zero.saturating_sub(one_nano), Duration::MIN);
assert_eq!(zero.saturating_sub(one_sec), Duration::MIN);
}

#[test]
#[should_panic]
fn sub_bad1() {
Expand Down Expand Up @@ -136,6 +157,15 @@ fn checked_mul() {
assert_eq!(Duration::new(u64::MAX - 1, 0).checked_mul(2), None);
}

#[test]
fn saturating_mul() {
assert_eq!(Duration::new(0, 1).saturating_mul(2), Duration::new(0, 2));
assert_eq!(Duration::new(1, 1).saturating_mul(3), Duration::new(3, 3));
assert_eq!(Duration::new(0, 500_000_001).saturating_mul(4), Duration::new(2, 4));
assert_eq!(Duration::new(0, 500_000_001).saturating_mul(4000), Duration::new(2000, 4000));
assert_eq!(Duration::new(u64::MAX - 1, 0).saturating_mul(2), Duration::MAX);
}

#[test]
fn div() {
assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0));
Expand Down
42 changes: 26 additions & 16 deletions src/test/ui/consts/duration-consts-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#![feature(const_panic)]
#![feature(duration_consts_2)]
#![feature(div_duration)]
#![feature(duration_saturating_ops)]

use std::time::Duration;

Expand All @@ -15,29 +16,29 @@ fn duration() {

const MAX : Duration = Duration::new(u64::MAX, 1_000_000_000 - 1);

const MAX_ADD_ZERO : Option<Duration> = MAX.checked_add(ZERO);
assert_eq!(MAX_ADD_ZERO, Some(MAX));
const MAX_CHECKED_ADD_ZERO : Option<Duration> = MAX.checked_add(ZERO);
assert_eq!(MAX_CHECKED_ADD_ZERO, Some(MAX));

const MAX_ADD_ONE : Option<Duration> = MAX.checked_add(ONE);
assert_eq!(MAX_ADD_ONE, None);
const MAX_CHECKED_ADD_ONE : Option<Duration> = MAX.checked_add(ONE);
assert_eq!(MAX_CHECKED_ADD_ONE, None);

const ONE_SUB_ONE : Option<Duration> = ONE.checked_sub(ONE);
assert_eq!(ONE_SUB_ONE, Some(ZERO));
const ONE_CHECKED_SUB_ONE : Option<Duration> = ONE.checked_sub(ONE);
assert_eq!(ONE_CHECKED_SUB_ONE, Some(ZERO));

const ZERO_SUB_ONE : Option<Duration> = ZERO.checked_sub(ONE);
assert_eq!(ZERO_SUB_ONE, None);
const ZERO_CHECKED_SUB_ONE : Option<Duration> = ZERO.checked_sub(ONE);
assert_eq!(ZERO_CHECKED_SUB_ONE, None);

const ONE_MUL_ONE : Option<Duration> = ONE.checked_mul(1);
assert_eq!(ONE_MUL_ONE, Some(ONE));
const ONE_CHECKED_MUL_ONE : Option<Duration> = ONE.checked_mul(1);
assert_eq!(ONE_CHECKED_MUL_ONE, Some(ONE));

const MAX_MUL_TWO : Option<Duration> = MAX.checked_mul(2);
assert_eq!(MAX_MUL_TWO, None);
const MAX_CHECKED_MUL_TWO : Option<Duration> = MAX.checked_mul(2);
assert_eq!(MAX_CHECKED_MUL_TWO, None);

const ONE_DIV_ONE : Option<Duration> = ONE.checked_div(1);
assert_eq!(ONE_DIV_ONE, Some(ONE));
const ONE_CHECKED_DIV_ONE : Option<Duration> = ONE.checked_div(1);
assert_eq!(ONE_CHECKED_DIV_ONE, Some(ONE));

const ONE_DIV_ZERO : Option<Duration> = ONE.checked_div(0);
assert_eq!(ONE_DIV_ZERO, None);
const ONE_CHECKED_DIV_ZERO : Option<Duration> = ONE.checked_div(0);
assert_eq!(ONE_CHECKED_DIV_ZERO, None);

const MAX_AS_F32 : f32 = MAX.as_secs_f32();
assert_eq!(MAX_AS_F32, 18446744000000000000.0_f32);
Expand All @@ -50,6 +51,15 @@ fn duration() {

const ONE_AS_F64 : f64 = ONE.div_duration_f64(ONE);
assert_eq!(ONE_AS_F64, 1.0_f64);

const MAX_SATURATING_ADD_ONE : Duration = MAX.saturating_add(ONE);
assert_eq!(MAX_SATURATING_ADD_ONE, MAX);

const ZERO_SATURATING_SUB_ONE : Duration = ZERO.saturating_sub(ONE);
assert_eq!(ZERO_SATURATING_SUB_ONE, ZERO);

const MAX_SATURATING_MUL_TWO : Duration = MAX.saturating_mul(2);
assert_eq!(MAX_SATURATING_MUL_TWO, MAX);
}

fn main() {
Expand Down

0 comments on commit b869aa5

Please sign in to comment.