diff --git a/src/libstd/sys/cloudabi/condvar.rs b/src/libstd/sys/cloudabi/condvar.rs index ccf848a9be420..3229d98624e17 100644 --- a/src/libstd/sys/cloudabi/condvar.rs +++ b/src/libstd/sys/cloudabi/condvar.rs @@ -13,7 +13,7 @@ use mem; use sync::atomic::{AtomicU32, Ordering}; use sys::cloudabi::abi; use sys::mutex::{self, Mutex}; -use sys::time::dur2intervals; +use sys::time::checked_dur2intervals; use time::Duration; extern "C" { @@ -114,6 +114,8 @@ impl Condvar { // Call into the kernel to wait on the condition variable. let condvar = self.condvar.get(); + let timeout = checked_dur2intervals(&dur) + .expect("overflow converting duration to nanoseconds"); let subscriptions = [ abi::subscription { type_: abi::eventtype::CONDVAR, @@ -132,7 +134,7 @@ impl Condvar { union: abi::subscription_union { clock: abi::subscription_clock { clock_id: abi::clockid::MONOTONIC, - timeout: dur2intervals(&dur), + timeout, ..mem::zeroed() }, }, diff --git a/src/libstd/sys/cloudabi/thread.rs b/src/libstd/sys/cloudabi/thread.rs index a76e1fa3345cd..177321439d83c 100644 --- a/src/libstd/sys/cloudabi/thread.rs +++ b/src/libstd/sys/cloudabi/thread.rs @@ -16,7 +16,7 @@ use libc; use mem; use ptr; use sys::cloudabi::abi; -use sys::time::dur2intervals; +use sys::time::checked_dur2intervals; use sys_common::thread::*; use time::Duration; @@ -70,13 +70,15 @@ impl Thread { } pub fn sleep(dur: Duration) { + let timeout = checked_dur2intervals(&dur) + .expect("overflow converting duration to nanoseconds"); unsafe { let subscription = abi::subscription { type_: abi::eventtype::CLOCK, union: abi::subscription_union { clock: abi::subscription_clock { clock_id: abi::clockid::MONOTONIC, - timeout: dur2intervals(&dur), + timeout, ..mem::zeroed() }, }, diff --git a/src/libstd/sys/cloudabi/time.rs b/src/libstd/sys/cloudabi/time.rs index a442d1e4ad7b7..c9fea18fda6ec 100644 --- a/src/libstd/sys/cloudabi/time.rs +++ b/src/libstd/sys/cloudabi/time.rs @@ -19,15 +19,10 @@ pub struct Instant { t: abi::timestamp, } -fn checked_dur2intervals(dur: &Duration) -> Option { +pub fn checked_dur2intervals(dur: &Duration) -> Option { dur.as_secs() - .checked_mul(NSEC_PER_SEC) - .and_then(|nanos| nanos.checked_add(dur.subsec_nanos() as abi::timestamp)) -} - -pub fn dur2intervals(dur: &Duration) -> abi::timestamp { - checked_dur2intervals(dur) - .expect("overflow converting duration to nanoseconds") + .checked_mul(NSEC_PER_SEC)? + .checked_add(dur.subsec_nanos() as abi::timestamp) } impl Instant { @@ -47,20 +42,16 @@ impl Instant { Duration::new(diff / NSEC_PER_SEC, (diff % NSEC_PER_SEC) as u32) } - pub fn add_duration(&self, other: &Duration) -> Instant { - Instant { - t: self.t - .checked_add(dur2intervals(other)) - .expect("overflow when adding duration to instant"), - } + pub fn checked_add_duration(&self, other: &Duration) -> Option { + Some(Instant { + t: self.t.checked_add(checked_dur2intervals(other)?)?, + }) } - pub fn sub_duration(&self, other: &Duration) -> Instant { - Instant { - t: self.t - .checked_sub(dur2intervals(other)) - .expect("overflow when subtracting duration from instant"), - } + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(Instant { + t: self.t.checked_sub(checked_dur2intervals(other)?)?, + }) } } @@ -95,23 +86,16 @@ impl SystemTime { } } - pub fn add_duration(&self, other: &Duration) -> SystemTime { - self.checked_add_duration(other) - .expect("overflow when adding duration to instant") - } - pub fn checked_add_duration(&self, other: &Duration) -> Option { - checked_dur2intervals(other) - .and_then(|d| self.t.checked_add(d)) - .map(|t| SystemTime {t}) + Some(SystemTime { + t: self.t.checked_add(checked_dur2intervals(other)?)?, + }) } - pub fn sub_duration(&self, other: &Duration) -> SystemTime { - SystemTime { - t: self.t - .checked_sub(dur2intervals(other)) - .expect("overflow when subtracting duration from instant"), - } + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(SystemTime { + t: self.t.checked_sub(checked_dur2intervals(other)?)?, + }) } } diff --git a/src/libstd/sys/redox/time.rs b/src/libstd/sys/redox/time.rs index beff8d287e7c4..cb2eab5221181 100644 --- a/src/libstd/sys/redox/time.rs +++ b/src/libstd/sys/redox/time.rs @@ -41,10 +41,6 @@ impl Timespec { } } - fn add_duration(&self, other: &Duration) -> Timespec { - self.checked_add_duration(other).expect("overflow when adding duration to time") - } - fn checked_add_duration(&self, other: &Duration) -> Option { let mut secs = other .as_secs() @@ -67,27 +63,25 @@ impl Timespec { }) } - fn sub_duration(&self, other: &Duration) -> Timespec { + fn checked_sub_duration(&self, other: &Duration) -> Option { let mut secs = other .as_secs() .try_into() // <- target type would be `i64` .ok() - .and_then(|secs| self.t.tv_sec.checked_sub(secs)) - .expect("overflow when subtracting duration from time"); + .and_then(|secs| self.t.tv_sec.checked_sub(secs))?; // Similar to above, nanos can't overflow. let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32; if nsec < 0 { nsec += NSEC_PER_SEC as i32; - secs = secs.checked_sub(1).expect("overflow when subtracting \ - duration from time"); + secs = secs.checked_sub(1)?; } - Timespec { + Some(Timespec { t: syscall::TimeSpec { tv_sec: secs, tv_nsec: nsec as i32, }, - } + }) } } @@ -150,12 +144,12 @@ impl Instant { }) } - pub fn add_duration(&self, other: &Duration) -> Instant { - Instant { t: self.t.add_duration(other) } + pub fn checked_add_duration(&self, other: &Duration) -> Option { + Some(Instant { t: self.t.checked_add_duration(other)? }) } - pub fn sub_duration(&self, other: &Duration) -> Instant { - Instant { t: self.t.sub_duration(other) } + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(Instant { t: self.t.checked_sub_duration(other)? }) } } @@ -178,16 +172,12 @@ impl SystemTime { self.t.sub_timespec(&other.t) } - pub fn add_duration(&self, other: &Duration) -> SystemTime { - SystemTime { t: self.t.add_duration(other) } - } - pub fn checked_add_duration(&self, other: &Duration) -> Option { - 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 { - SystemTime { t: self.t.sub_duration(other) } + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(SystemTime { t: self.t.checked_sub_duration(other)? }) } } diff --git a/src/libstd/sys/sgx/time.rs b/src/libstd/sys/sgx/time.rs index b01c992768e71..196e1a97fc44f 100644 --- a/src/libstd/sys/sgx/time.rs +++ b/src/libstd/sys/sgx/time.rs @@ -28,12 +28,12 @@ impl Instant { self.0 - other.0 } - pub fn add_duration(&self, other: &Duration) -> Instant { - Instant(self.0 + *other) + pub fn checked_add_duration(&self, other: &Duration) -> Option { + Some(Instant(self.0.checked_add(*other)?)) } - pub fn sub_duration(&self, other: &Duration) -> Instant { - Instant(self.0 - *other) + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(Instant(self.0.checked_sub(*other)?)) } } @@ -47,15 +47,11 @@ impl SystemTime { self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) } - pub fn add_duration(&self, other: &Duration) -> SystemTime { - SystemTime(self.0 + *other) - } - pub fn checked_add_duration(&self, other: &Duration) -> Option { - self.0.checked_add(*other).map(|d| SystemTime(d)) + Some(SystemTime(self.0.checked_add(*other)?)) } - pub fn sub_duration(&self, other: &Duration) -> SystemTime { - SystemTime(self.0 - *other) + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(SystemTime(self.0.checked_sub(*other)?)) } } diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs index 1f9539c36e02e..8f8aaa88b2265 100644 --- a/src/libstd/sys/unix/time.rs +++ b/src/libstd/sys/unix/time.rs @@ -42,10 +42,6 @@ impl Timespec { } } - fn add_duration(&self, other: &Duration) -> Timespec { - self.checked_add_duration(other).expect("overflow when adding duration to time") - } - fn checked_add_duration(&self, other: &Duration) -> Option { let mut secs = other .as_secs() @@ -68,27 +64,25 @@ impl Timespec { }) } - fn sub_duration(&self, other: &Duration) -> Timespec { + fn checked_sub_duration(&self, other: &Duration) -> Option { let mut secs = other .as_secs() .try_into() // <- target type would be `libc::time_t` .ok() - .and_then(|secs| self.t.tv_sec.checked_sub(secs)) - .expect("overflow when subtracting duration from time"); + .and_then(|secs| self.t.tv_sec.checked_sub(secs))?; // Similar to above, nanos can't overflow. let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32; if nsec < 0 { nsec += NSEC_PER_SEC as i32; - secs = secs.checked_sub(1).expect("overflow when subtracting \ - duration from time"); + secs = secs.checked_sub(1)?; } - Timespec { + Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _, }, - } + }) } } @@ -165,18 +159,16 @@ mod inner { Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32) } - pub fn add_duration(&self, other: &Duration) -> Instant { - Instant { - t: self.t.checked_add(dur2intervals(other)) - .expect("overflow when adding duration to instant"), - } + pub fn checked_add_duration(&self, other: &Duration) -> Option { + Some(Instant { + t: self.t.checked_add(checked_dur2intervals(other)?)?, + }) } - pub fn sub_duration(&self, other: &Duration) -> Instant { - Instant { - t: self.t.checked_sub(dur2intervals(other)) - .expect("overflow when subtracting duration from instant"), - } + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(Instant { + t: self.t.checked_sub(checked_dur2intervals(other)?)?, + }) } } @@ -199,16 +191,12 @@ mod inner { self.t.sub_timespec(&other.t) } - pub fn add_duration(&self, other: &Duration) -> SystemTime { - SystemTime { t: self.t.add_duration(other) } - } - pub fn checked_add_duration(&self, other: &Duration) -> Option { - 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 { - SystemTime { t: self.t.sub_duration(other) } + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(SystemTime { t: self.t.checked_sub_duration(other)? }) } } @@ -236,12 +224,12 @@ mod inner { } } - fn dur2intervals(dur: &Duration) -> u64 { + fn checked_dur2intervals(dur: &Duration) -> Option { + let nanos = dur.as_secs() + .checked_mul(NSEC_PER_SEC)? + .checked_add(dur.subsec_nanos() as u64)?; let info = info(); - let nanos = dur.as_secs().checked_mul(NSEC_PER_SEC).and_then(|nanos| { - nanos.checked_add(dur.subsec_nanos() as u64) - }).expect("overflow converting duration to nanoseconds"); - mul_div_u64(nanos, info.denom as u64, info.numer as u64) + Some(mul_div_u64(nanos, info.denom as u64, info.numer as u64)) } fn info() -> &'static libc::mach_timebase_info { @@ -299,12 +287,12 @@ mod inner { }) } - pub fn add_duration(&self, other: &Duration) -> Instant { - Instant { t: self.t.add_duration(other) } + pub fn checked_add_duration(&self, other: &Duration) -> Option { + Some(Instant { t: self.t.checked_add_duration(other)? }) } - pub fn sub_duration(&self, other: &Duration) -> Instant { - Instant { t: self.t.sub_duration(other) } + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(Instant { t: self.t.checked_sub_duration(other)? }) } } @@ -327,16 +315,12 @@ mod inner { self.t.sub_timespec(&other.t) } - pub fn add_duration(&self, other: &Duration) -> SystemTime { - SystemTime { t: self.t.add_duration(other) } - } - pub fn checked_add_duration(&self, other: &Duration) -> Option { - 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 { - SystemTime { t: self.t.sub_duration(other) } + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(SystemTime { t: self.t.checked_sub_duration(other)? }) } } diff --git a/src/libstd/sys/wasm/time.rs b/src/libstd/sys/wasm/time.rs index 991e8176edf6d..cc56773e0ea8e 100644 --- a/src/libstd/sys/wasm/time.rs +++ b/src/libstd/sys/wasm/time.rs @@ -28,12 +28,12 @@ impl Instant { self.0 - other.0 } - pub fn add_duration(&self, other: &Duration) -> Instant { - Instant(self.0 + *other) + pub fn checked_add_duration(&self, other: &Duration) -> Option { + Some(Instant(self.0.checked_add(*other)?)) } - pub fn sub_duration(&self, other: &Duration) -> Instant { - Instant(self.0 - *other) + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(Instant(self.0.checked_sub(*other)?)) } } @@ -47,15 +47,11 @@ impl SystemTime { self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) } - pub fn add_duration(&self, other: &Duration) -> SystemTime { - SystemTime(self.0 + *other) - } - pub fn checked_add_duration(&self, other: &Duration) -> Option { - self.0.checked_add(*other).map(|d| SystemTime(d)) + Some(SystemTime(self.0.checked_add(*other)?)) } - pub fn sub_duration(&self, other: &Duration) -> SystemTime { - SystemTime(self.0 - *other) + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(SystemTime(self.0.checked_sub(*other)?)) } } diff --git a/src/libstd/sys/windows/time.rs b/src/libstd/sys/windows/time.rs index c809a0b98ac94..bb2c97ea149d2 100644 --- a/src/libstd/sys/windows/time.rs +++ b/src/libstd/sys/windows/time.rs @@ -68,30 +68,27 @@ impl Instant { Duration::new(nanos / NANOS_PER_SEC, (nanos % NANOS_PER_SEC) as u32) } - pub fn add_duration(&self, other: &Duration) -> Instant { + pub fn checked_add_duration(&self, other: &Duration) -> Option { let freq = frequency() as u64; - let t = other.as_secs().checked_mul(freq).and_then(|i| { - (self.t as u64).checked_add(i) - }).and_then(|i| { - i.checked_add(mul_div_u64(other.subsec_nanos() as u64, freq, - NANOS_PER_SEC)) - }).expect("overflow when adding duration to time"); - Instant { + let t = other.as_secs() + .checked_mul(freq)? + .checked_add(mul_div_u64(other.subsec_nanos() as u64, freq, NANOS_PER_SEC))? + .checked_add(self.t as u64)?; + Some(Instant { t: t as c::LARGE_INTEGER, - } + }) } - pub fn sub_duration(&self, other: &Duration) -> Instant { + pub fn checked_sub_duration(&self, other: &Duration) -> Option { let freq = frequency() as u64; let t = other.as_secs().checked_mul(freq).and_then(|i| { (self.t as u64).checked_sub(i) }).and_then(|i| { - i.checked_sub(mul_div_u64(other.subsec_nanos() as u64, freq, - NANOS_PER_SEC)) - }).expect("overflow when subtracting duration from time"); - Instant { + i.checked_sub(mul_div_u64(other.subsec_nanos() as u64, freq, NANOS_PER_SEC)) + })?; + Some(Instant { t: t as c::LARGE_INTEGER, - } + }) } } @@ -127,20 +124,14 @@ impl SystemTime { } } - pub fn add_duration(&self, other: &Duration) -> SystemTime { - self.checked_add_duration(other).expect("overflow when adding duration to time") - } - pub fn checked_add_duration(&self, other: &Duration) -> Option { - checked_dur2intervals(other) - .and_then(|d| self.intervals().checked_add(d)) - .map(|i| SystemTime::from_intervals(i)) + let intervals = self.intervals().checked_add(checked_dur2intervals(other)?)?; + Some(SystemTime::from_intervals(intervals)) } - pub fn sub_duration(&self, other: &Duration) -> SystemTime { - let intervals = self.intervals().checked_sub(dur2intervals(other)) - .expect("overflow when subtracting from time"); - SystemTime::from_intervals(intervals) + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + let intervals = self.intervals().checked_sub(checked_dur2intervals(other)?)?; + Some(SystemTime::from_intervals(intervals)) } } @@ -184,16 +175,12 @@ impl Hash for SystemTime { } } -fn checked_dur2intervals(d: &Duration) -> Option { - d.as_secs() - .checked_mul(INTERVALS_PER_SEC) - .and_then(|i| i.checked_add(d.subsec_nanos() as u64 / 100)) - .and_then(|i| i.try_into().ok()) -} - -fn dur2intervals(d: &Duration) -> i64 { - checked_dur2intervals(d) - .expect("overflow when converting duration to intervals") +fn checked_dur2intervals(dur: &Duration) -> Option { + dur.as_secs() + .checked_mul(INTERVALS_PER_SEC)? + .checked_add(dur.subsec_nanos() as u64 / 100)? + .try_into() + .ok() } fn intervals2dur(intervals: u64) -> Duration { diff --git a/src/libstd/time.rs b/src/libstd/time.rs index 667810485ee39..63cede79e4843 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -208,6 +208,22 @@ impl Instant { pub fn elapsed(&self) -> Duration { Instant::now() - *self } + + /// 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_add(&self, duration: Duration) -> Option { + 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 { + self.0.checked_sub_duration(&duration).map(|t| Instant(t)) + } } #[stable(feature = "time2", since = "1.8.0")] @@ -215,7 +231,8 @@ impl Add for Instant { type Output = Instant; fn add(self, other: Duration) -> Instant { - Instant(self.0.add_duration(&other)) + self.checked_add(other) + .expect("overflow when adding duration to instant") } } @@ -231,7 +248,8 @@ impl Sub for Instant { type Output = Instant; fn sub(self, other: Duration) -> Instant { - Instant(self.0.sub_duration(&other)) + self.checked_sub(other) + .expect("overflow when subtracting duration from instant") } } @@ -365,6 +383,14 @@ impl SystemTime { pub fn checked_add(&self, duration: Duration) -> Option { 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 { + self.0.checked_sub_duration(&duration).map(|t| SystemTime(t)) + } } #[stable(feature = "time2", since = "1.8.0")] @@ -372,7 +398,8 @@ impl Add for SystemTime { type Output = SystemTime; fn add(self, dur: Duration) -> SystemTime { - SystemTime(self.0.add_duration(&dur)) + self.checked_add(dur) + .expect("overflow when adding duration to instant") } } @@ -388,7 +415,8 @@ impl Sub for SystemTime { type Output = SystemTime; fn sub(self, dur: Duration) -> SystemTime { - SystemTime(self.0.sub_duration(&dur)) + self.checked_sub(dur) + .expect("overflow when subtracting duration from instant") } } @@ -521,6 +549,20 @@ mod tests { let second = Duration::new(1, 0); 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 + let mut maybe_t = Some(Instant::now()); + let max_duration = Duration::from_secs(u64::max_value()); + // in case `Instant` can store `>= now + max_duration`. + for _ in 0..2 { + maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration)); + } + assert_eq!(maybe_t, None); + + // checked_add_duration calculates the right time and will work for another year + let year = Duration::from_secs(60 * 60 * 24 * 365); + assert_eq!(a + year, a.checked_add(year).unwrap()); } #[test] @@ -557,6 +599,7 @@ mod tests { .duration(), second); 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 if !(cfg!(unix) && ::mem::size_of::<::libc::time_t>() <= 4) {