Add checked_sub for Instant and SystemTime
This commit is contained in:
parent
13f0463a19
commit
f5a99c321b
6 changed files with 83 additions and 87 deletions
|
@ -25,11 +25,6 @@ fn checked_dur2intervals(dur: &Duration) -> Option<abi::timestamp> {
|
||||||
.checked_add(dur.subsec_nanos() as abi::timestamp)
|
.checked_add(dur.subsec_nanos() as abi::timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dur2intervals(dur: &Duration) -> abi::timestamp {
|
|
||||||
checked_dur2intervals(dur)
|
|
||||||
.expect("overflow converting duration to nanoseconds")
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Instant {
|
impl Instant {
|
||||||
pub fn now() -> Instant {
|
pub fn now() -> Instant {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -48,17 +43,15 @@ impl Instant {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
||||||
checked_dur2intervals(other)?
|
Some(Instant {
|
||||||
.checked_add(self.t)
|
t: self.t.checked_add(checked_dur2intervals(other)?)?,
|
||||||
.map(|t| Instant {t})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sub_duration(&self, other: &Duration) -> Instant {
|
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
|
||||||
Instant {
|
Some(Instant {
|
||||||
t: self.t
|
t: self.t.checked_sub(checked_dur2intervals(other)?)?,
|
||||||
.checked_sub(dur2intervals(other))
|
})
|
||||||
.expect("overflow when subtracting duration from instant"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,17 +87,15 @@ impl SystemTime {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
|
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||||
checked_dur2intervals(other)
|
Some(SystemTime {
|
||||||
.and_then(|d| self.t.checked_add(d))
|
t: self.t.checked_add(checked_dur2intervals(other)?)?,
|
||||||
.map(|t| SystemTime {t})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sub_duration(&self, other: &Duration) -> SystemTime {
|
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||||
SystemTime {
|
Some(SystemTime {
|
||||||
t: self.t
|
t: self.t.checked_sub(checked_dur2intervals(other)?)?,
|
||||||
.checked_sub(dur2intervals(other))
|
})
|
||||||
.expect("overflow when subtracting duration from instant"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,27 +63,25 @@ impl Timespec {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sub_duration(&self, other: &Duration) -> Timespec {
|
fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
|
||||||
let mut secs = other
|
let mut secs = other
|
||||||
.as_secs()
|
.as_secs()
|
||||||
.try_into() // <- target type would be `i64`
|
.try_into() // <- target type would be `i64`
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|secs| self.t.tv_sec.checked_sub(secs))
|
.and_then(|secs| self.t.tv_sec.checked_sub(secs))?;
|
||||||
.expect("overflow when subtracting duration from time");
|
|
||||||
|
|
||||||
// Similar to above, nanos can't overflow.
|
// Similar to above, nanos can't overflow.
|
||||||
let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
|
let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
|
||||||
if nsec < 0 {
|
if nsec < 0 {
|
||||||
nsec += NSEC_PER_SEC as i32;
|
nsec += NSEC_PER_SEC as i32;
|
||||||
secs = secs.checked_sub(1).expect("overflow when subtracting \
|
secs = secs.checked_sub(1)?;
|
||||||
duration from time");
|
|
||||||
}
|
}
|
||||||
Timespec {
|
Some(Timespec {
|
||||||
t: syscall::TimeSpec {
|
t: syscall::TimeSpec {
|
||||||
tv_sec: secs,
|
tv_sec: secs,
|
||||||
tv_nsec: nsec as i32,
|
tv_nsec: nsec as i32,
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,11 +145,11 @@ impl Instant {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
||||||
self.t.checked_add_duration(other).map(|t| Instant { t })
|
Some(Instant { t: self.t.checked_add_duration(other)? })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sub_duration(&self, other: &Duration) -> Instant {
|
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
|
||||||
Instant { t: self.t.sub_duration(other) }
|
Some(Instant { t: self.t.checked_sub_duration(other)? })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,11 +173,11 @@ impl SystemTime {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
|
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||||
self.t.checked_add_duration(other).map(|t| SystemTime { t })
|
Some(SystemTime { t: self.t.checked_add_duration(other)? })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sub_duration(&self, other: &Duration) -> SystemTime {
|
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||||
SystemTime { t: self.t.sub_duration(other) }
|
Some(SystemTime { t: self.t.checked_sub_duration(other)? })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,27 +64,25 @@ impl Timespec {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sub_duration(&self, other: &Duration) -> Timespec {
|
fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
|
||||||
let mut secs = other
|
let mut secs = other
|
||||||
.as_secs()
|
.as_secs()
|
||||||
.try_into() // <- target type would be `libc::time_t`
|
.try_into() // <- target type would be `libc::time_t`
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|secs| self.t.tv_sec.checked_sub(secs))
|
.and_then(|secs| self.t.tv_sec.checked_sub(secs))?;
|
||||||
.expect("overflow when subtracting duration from time");
|
|
||||||
|
|
||||||
// Similar to above, nanos can't overflow.
|
// Similar to above, nanos can't overflow.
|
||||||
let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
|
let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
|
||||||
if nsec < 0 {
|
if nsec < 0 {
|
||||||
nsec += NSEC_PER_SEC as i32;
|
nsec += NSEC_PER_SEC as i32;
|
||||||
secs = secs.checked_sub(1).expect("overflow when subtracting \
|
secs = secs.checked_sub(1)?;
|
||||||
duration from time");
|
|
||||||
}
|
}
|
||||||
Timespec {
|
Some(Timespec {
|
||||||
t: libc::timespec {
|
t: libc::timespec {
|
||||||
tv_sec: secs,
|
tv_sec: secs,
|
||||||
tv_nsec: nsec as _,
|
tv_nsec: nsec as _,
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,14 +160,15 @@ mod inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
||||||
checked_dur2intervals(other)?.checked_add(self.t).map(|t| Instant {t})
|
Some(Instant {
|
||||||
|
t: self.t.checked_add(checked_dur2intervals(other)?)?,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sub_duration(&self, other: &Duration) -> Instant {
|
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
|
||||||
Instant {
|
Some(Instant {
|
||||||
t: self.t.checked_sub(dur2intervals(other))
|
t: self.t.checked_sub(checked_dur2intervals(other)?)?,
|
||||||
.expect("overflow when subtracting duration from instant"),
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,11 +192,11 @@ mod inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
|
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||||
self.t.checked_add_duration(other).map(|t| SystemTime { t })
|
Some(SystemTime { t: self.t.checked_add_duration(other)? })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sub_duration(&self, other: &Duration) -> SystemTime {
|
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||||
SystemTime { t: self.t.sub_duration(other) }
|
Some(SystemTime { t: self.t.checked_sub_duration(other)? })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,11 +224,6 @@ mod inner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dur2intervals(dur: &Duration) -> u64 {
|
|
||||||
checked_dur2intervals(dur)
|
|
||||||
.expect("overflow converting duration to nanoseconds")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn checked_dur2intervals(dur: &Duration) -> Option<u64> {
|
fn checked_dur2intervals(dur: &Duration) -> Option<u64> {
|
||||||
let nanos = dur.as_secs()
|
let nanos = dur.as_secs()
|
||||||
.checked_mul(NSEC_PER_SEC)?
|
.checked_mul(NSEC_PER_SEC)?
|
||||||
|
@ -294,11 +288,11 @@ mod inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
||||||
self.t.checked_add_duration(other).map(|t| Instant { t })
|
Some(Instant { t: self.t.checked_add_duration(other)? })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sub_duration(&self, other: &Duration) -> Instant {
|
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
|
||||||
Instant { t: self.t.sub_duration(other) }
|
Some(Instant { t: self.t.checked_sub_duration(other)? })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,11 +316,11 @@ mod inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
|
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||||
self.t.checked_add_duration(other).map(|t| SystemTime { t })
|
Some(SystemTime { t: self.t.checked_add_duration(other)? })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sub_duration(&self, other: &Duration) -> SystemTime {
|
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||||
SystemTime { t: self.t.sub_duration(other) }
|
Some(SystemTime { t: self.t.checked_sub_duration(other)? })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,11 +29,11 @@ impl Instant {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
||||||
self.0.checked_add(*other).map(|d| Instant(d))
|
Some(Instant(self.0.checked_add(*other)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sub_duration(&self, other: &Duration) -> Instant {
|
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
|
||||||
Instant(self.0 - *other)
|
Some(Instant(self.0.checked_sub(*other)?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,10 +48,10 @@ impl SystemTime {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
|
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||||
self.0.checked_add(*other).map(|d| SystemTime(d))
|
Some(SystemTime(self.0.checked_add(*other)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sub_duration(&self, other: &Duration) -> SystemTime {
|
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||||
SystemTime(self.0 - *other)
|
Some(SystemTime(self.0.checked_sub(*other)?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,16 +79,16 @@ impl Instant {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sub_duration(&self, other: &Duration) -> Instant {
|
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
|
||||||
let freq = frequency() as u64;
|
let freq = frequency() as u64;
|
||||||
let t = other.as_secs().checked_mul(freq).and_then(|i| {
|
let t = other.as_secs().checked_mul(freq).and_then(|i| {
|
||||||
(self.t as u64).checked_sub(i)
|
(self.t as u64).checked_sub(i)
|
||||||
}).and_then(|i| {
|
}).and_then(|i| {
|
||||||
i.checked_sub(mul_div_u64(other.subsec_nanos() as u64, freq, NANOS_PER_SEC))
|
i.checked_sub(mul_div_u64(other.subsec_nanos() as u64, freq, NANOS_PER_SEC))
|
||||||
}).expect("overflow when subtracting duration from time");
|
})?;
|
||||||
Instant {
|
Some(Instant {
|
||||||
t: t as c::LARGE_INTEGER,
|
t: t as c::LARGE_INTEGER,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,15 +125,13 @@ impl SystemTime {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
|
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||||
checked_dur2intervals(other)
|
let intervals = self.intervals().checked_add(checked_dur2intervals(other)?)?;
|
||||||
.and_then(|d| self.intervals().checked_add(d))
|
Some(SystemTime::from_intervals(intervals))
|
||||||
.map(|i| SystemTime::from_intervals(i))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sub_duration(&self, other: &Duration) -> SystemTime {
|
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||||
let intervals = self.intervals().checked_sub(dur2intervals(other))
|
let intervals = self.intervals().checked_sub(checked_dur2intervals(other)?)?;
|
||||||
.expect("overflow when subtracting from time");
|
Some(SystemTime::from_intervals(intervals))
|
||||||
SystemTime::from_intervals(intervals)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,11 +183,6 @@ fn checked_dur2intervals(dur: &Duration) -> Option<i64> {
|
||||||
.ok()
|
.ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dur2intervals(d: &Duration) -> i64 {
|
|
||||||
checked_dur2intervals(d)
|
|
||||||
.expect("overflow when converting duration to intervals")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn intervals2dur(intervals: u64) -> Duration {
|
fn intervals2dur(intervals: u64) -> Duration {
|
||||||
Duration::new(intervals / INTERVALS_PER_SEC,
|
Duration::new(intervals / INTERVALS_PER_SEC,
|
||||||
((intervals % INTERVALS_PER_SEC) * 100) as u32)
|
((intervals % INTERVALS_PER_SEC) * 100) as u32)
|
||||||
|
|
|
@ -216,6 +216,14 @@ impl Instant {
|
||||||
pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
|
pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
|
||||||
self.0.checked_add_duration(&duration).map(|t| Instant(t))
|
self.0.checked_add_duration(&duration).map(|t| Instant(t))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as
|
||||||
|
/// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
|
||||||
|
/// otherwise.
|
||||||
|
#[unstable(feature = "time_checked_add", issue = "55940")]
|
||||||
|
pub fn checked_sub(&self, duration: Duration) -> Option<Instant> {
|
||||||
|
self.0.checked_sub_duration(&duration).map(|t| Instant(t))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "time2", since = "1.8.0")]
|
#[stable(feature = "time2", since = "1.8.0")]
|
||||||
|
@ -240,7 +248,8 @@ impl Sub<Duration> for Instant {
|
||||||
type Output = Instant;
|
type Output = Instant;
|
||||||
|
|
||||||
fn sub(self, other: Duration) -> Instant {
|
fn sub(self, other: Duration) -> Instant {
|
||||||
Instant(self.0.sub_duration(&other))
|
self.checked_sub(other)
|
||||||
|
.expect("overflow when subtracting duration from instant")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,6 +383,14 @@ impl SystemTime {
|
||||||
pub fn checked_add(&self, duration: Duration) -> Option<SystemTime> {
|
pub fn checked_add(&self, duration: Duration) -> Option<SystemTime> {
|
||||||
self.0.checked_add_duration(&duration).map(|t| SystemTime(t))
|
self.0.checked_add_duration(&duration).map(|t| SystemTime(t))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as
|
||||||
|
/// `SystemTime` (which means it's inside the bounds of the underlying data structure), `None`
|
||||||
|
/// otherwise.
|
||||||
|
#[unstable(feature = "time_checked_add", issue = "55940")]
|
||||||
|
pub fn checked_sub(&self, duration: Duration) -> Option<SystemTime> {
|
||||||
|
self.0.checked_sub_duration(&duration).map(|t| SystemTime(t))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "time2", since = "1.8.0")]
|
#[stable(feature = "time2", since = "1.8.0")]
|
||||||
|
@ -398,7 +415,8 @@ impl Sub<Duration> for SystemTime {
|
||||||
type Output = SystemTime;
|
type Output = SystemTime;
|
||||||
|
|
||||||
fn sub(self, dur: Duration) -> SystemTime {
|
fn sub(self, dur: Duration) -> SystemTime {
|
||||||
SystemTime(self.0.sub_duration(&dur))
|
self.checked_sub(dur)
|
||||||
|
.expect("overflow when subtracting duration from instant")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,6 +549,7 @@ mod tests {
|
||||||
|
|
||||||
let second = Duration::new(1, 0);
|
let second = Duration::new(1, 0);
|
||||||
assert_almost_eq!(a - second + second, a);
|
assert_almost_eq!(a - second + second, a);
|
||||||
|
assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a);
|
||||||
|
|
||||||
// checked_add_duration will not panic on overflow
|
// checked_add_duration will not panic on overflow
|
||||||
let mut maybe_t = Some(Instant::now());
|
let mut maybe_t = Some(Instant::now());
|
||||||
|
@ -580,6 +599,7 @@ mod tests {
|
||||||
.duration(), second);
|
.duration(), second);
|
||||||
|
|
||||||
assert_almost_eq!(a - second + second, a);
|
assert_almost_eq!(a - second + second, a);
|
||||||
|
assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a);
|
||||||
|
|
||||||
// A difference of 80 and 800 years cannot fit inside a 32-bit time_t
|
// A difference of 80 and 800 years cannot fit inside a 32-bit time_t
|
||||||
if !(cfg!(unix) && ::mem::size_of::<::libc::time_t>() <= 4) {
|
if !(cfg!(unix) && ::mem::size_of::<::libc::time_t>() <= 4) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue