Skip to content

Commit f5a99c3

Browse files
committed
Add checked_sub for Instant and SystemTime
1 parent 13f0463 commit f5a99c3

File tree

6 files changed

+83
-87
lines changed

6 files changed

+83
-87
lines changed

src/libstd/sys/cloudabi/time.rs

+14-23
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,6 @@ fn checked_dur2intervals(dur: &Duration) -> Option<abi::timestamp> {
2525
.checked_add(dur.subsec_nanos() as abi::timestamp)
2626
}
2727

28-
pub fn dur2intervals(dur: &Duration) -> abi::timestamp {
29-
checked_dur2intervals(dur)
30-
.expect("overflow converting duration to nanoseconds")
31-
}
32-
3328
impl Instant {
3429
pub fn now() -> Instant {
3530
unsafe {
@@ -48,17 +43,15 @@ impl Instant {
4843
}
4944

5045
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
51-
checked_dur2intervals(other)?
52-
.checked_add(self.t)
53-
.map(|t| Instant {t})
46+
Some(Instant {
47+
t: self.t.checked_add(checked_dur2intervals(other)?)?,
48+
})
5449
}
5550

56-
pub fn sub_duration(&self, other: &Duration) -> Instant {
57-
Instant {
58-
t: self.t
59-
.checked_sub(dur2intervals(other))
60-
.expect("overflow when subtracting duration from instant"),
61-
}
51+
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
52+
Some(Instant {
53+
t: self.t.checked_sub(checked_dur2intervals(other)?)?,
54+
})
6255
}
6356
}
6457

@@ -94,17 +87,15 @@ impl SystemTime {
9487
}
9588

9689
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
97-
checked_dur2intervals(other)
98-
.and_then(|d| self.t.checked_add(d))
99-
.map(|t| SystemTime {t})
90+
Some(SystemTime {
91+
t: self.t.checked_add(checked_dur2intervals(other)?)?,
92+
})
10093
}
10194

102-
pub fn sub_duration(&self, other: &Duration) -> SystemTime {
103-
SystemTime {
104-
t: self.t
105-
.checked_sub(dur2intervals(other))
106-
.expect("overflow when subtracting duration from instant"),
107-
}
95+
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
96+
Some(SystemTime {
97+
t: self.t.checked_sub(checked_dur2intervals(other)?)?,
98+
})
10899
}
109100
}
110101

src/libstd/sys/redox/time.rs

+11-13
Original file line numberDiff line numberDiff line change
@@ -63,27 +63,25 @@ impl Timespec {
6363
})
6464
}
6565

66-
fn sub_duration(&self, other: &Duration) -> Timespec {
66+
fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
6767
let mut secs = other
6868
.as_secs()
6969
.try_into() // <- target type would be `i64`
7070
.ok()
71-
.and_then(|secs| self.t.tv_sec.checked_sub(secs))
72-
.expect("overflow when subtracting duration from time");
71+
.and_then(|secs| self.t.tv_sec.checked_sub(secs))?;
7372

7473
// Similar to above, nanos can't overflow.
7574
let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
7675
if nsec < 0 {
7776
nsec += NSEC_PER_SEC as i32;
78-
secs = secs.checked_sub(1).expect("overflow when subtracting \
79-
duration from time");
77+
secs = secs.checked_sub(1)?;
8078
}
81-
Timespec {
79+
Some(Timespec {
8280
t: syscall::TimeSpec {
8381
tv_sec: secs,
8482
tv_nsec: nsec as i32,
8583
},
86-
}
84+
})
8785
}
8886
}
8987

@@ -147,11 +145,11 @@ impl Instant {
147145
}
148146

149147
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
150-
self.t.checked_add_duration(other).map(|t| Instant { t })
148+
Some(Instant { t: self.t.checked_add_duration(other)? })
151149
}
152150

153-
pub fn sub_duration(&self, other: &Duration) -> Instant {
154-
Instant { t: self.t.sub_duration(other) }
151+
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
152+
Some(Instant { t: self.t.checked_sub_duration(other)? })
155153
}
156154
}
157155

@@ -175,11 +173,11 @@ impl SystemTime {
175173
}
176174

177175
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
178-
self.t.checked_add_duration(other).map(|t| SystemTime { t })
176+
Some(SystemTime { t: self.t.checked_add_duration(other)? })
179177
}
180178

181-
pub fn sub_duration(&self, other: &Duration) -> SystemTime {
182-
SystemTime { t: self.t.sub_duration(other) }
179+
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
180+
Some(SystemTime { t: self.t.checked_sub_duration(other)? })
183181
}
184182
}
185183

src/libstd/sys/unix/time.rs

+21-27
Original file line numberDiff line numberDiff line change
@@ -64,27 +64,25 @@ impl Timespec {
6464
})
6565
}
6666

67-
fn sub_duration(&self, other: &Duration) -> Timespec {
67+
fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
6868
let mut secs = other
6969
.as_secs()
7070
.try_into() // <- target type would be `libc::time_t`
7171
.ok()
72-
.and_then(|secs| self.t.tv_sec.checked_sub(secs))
73-
.expect("overflow when subtracting duration from time");
72+
.and_then(|secs| self.t.tv_sec.checked_sub(secs))?;
7473

7574
// Similar to above, nanos can't overflow.
7675
let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
7776
if nsec < 0 {
7877
nsec += NSEC_PER_SEC as i32;
79-
secs = secs.checked_sub(1).expect("overflow when subtracting \
80-
duration from time");
78+
secs = secs.checked_sub(1)?;
8179
}
82-
Timespec {
80+
Some(Timespec {
8381
t: libc::timespec {
8482
tv_sec: secs,
8583
tv_nsec: nsec as _,
8684
},
87-
}
85+
})
8886
}
8987
}
9088

@@ -162,14 +160,15 @@ mod inner {
162160
}
163161

164162
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
165-
checked_dur2intervals(other)?.checked_add(self.t).map(|t| Instant {t})
163+
Some(Instant {
164+
t: self.t.checked_add(checked_dur2intervals(other)?)?,
165+
})
166166
}
167167

168-
pub fn sub_duration(&self, other: &Duration) -> Instant {
169-
Instant {
170-
t: self.t.checked_sub(dur2intervals(other))
171-
.expect("overflow when subtracting duration from instant"),
172-
}
168+
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
169+
Some(Instant {
170+
t: self.t.checked_sub(checked_dur2intervals(other)?)?,
171+
})
173172
}
174173
}
175174

@@ -193,11 +192,11 @@ mod inner {
193192
}
194193

195194
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
196-
self.t.checked_add_duration(other).map(|t| SystemTime { t })
195+
Some(SystemTime { t: self.t.checked_add_duration(other)? })
197196
}
198197

199-
pub fn sub_duration(&self, other: &Duration) -> SystemTime {
200-
SystemTime { t: self.t.sub_duration(other) }
198+
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
199+
Some(SystemTime { t: self.t.checked_sub_duration(other)? })
201200
}
202201
}
203202

@@ -225,11 +224,6 @@ mod inner {
225224
}
226225
}
227226

228-
fn dur2intervals(dur: &Duration) -> u64 {
229-
checked_dur2intervals(dur)
230-
.expect("overflow converting duration to nanoseconds")
231-
}
232-
233227
fn checked_dur2intervals(dur: &Duration) -> Option<u64> {
234228
let nanos = dur.as_secs()
235229
.checked_mul(NSEC_PER_SEC)?
@@ -294,11 +288,11 @@ mod inner {
294288
}
295289

296290
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
297-
self.t.checked_add_duration(other).map(|t| Instant { t })
291+
Some(Instant { t: self.t.checked_add_duration(other)? })
298292
}
299293

300-
pub fn sub_duration(&self, other: &Duration) -> Instant {
301-
Instant { t: self.t.sub_duration(other) }
294+
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
295+
Some(Instant { t: self.t.checked_sub_duration(other)? })
302296
}
303297
}
304298

@@ -322,11 +316,11 @@ mod inner {
322316
}
323317

324318
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
325-
self.t.checked_add_duration(other).map(|t| SystemTime { t })
319+
Some(SystemTime { t: self.t.checked_add_duration(other)? })
326320
}
327321

328-
pub fn sub_duration(&self, other: &Duration) -> SystemTime {
329-
SystemTime { t: self.t.sub_duration(other) }
322+
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
323+
Some(SystemTime { t: self.t.checked_sub_duration(other)? })
330324
}
331325
}
332326

src/libstd/sys/wasm/time.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ impl Instant {
2929
}
3030

3131
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
32-
self.0.checked_add(*other).map(|d| Instant(d))
32+
Some(Instant(self.0.checked_add(*other)?))
3333
}
3434

35-
pub fn sub_duration(&self, other: &Duration) -> Instant {
36-
Instant(self.0 - *other)
35+
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
36+
Some(Instant(self.0.checked_sub(*other)?))
3737
}
3838
}
3939

@@ -48,10 +48,10 @@ impl SystemTime {
4848
}
4949

5050
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
51-
self.0.checked_add(*other).map(|d| SystemTime(d))
51+
Some(SystemTime(self.0.checked_add(*other)?))
5252
}
5353

54-
pub fn sub_duration(&self, other: &Duration) -> SystemTime {
55-
SystemTime(self.0 - *other)
54+
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
55+
Some(SystemTime(self.0.checked_sub(*other)?))
5656
}
5757
}

src/libstd/sys/windows/time.rs

+9-16
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,16 @@ impl Instant {
7979
})
8080
}
8181

82-
pub fn sub_duration(&self, other: &Duration) -> Instant {
82+
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
8383
let freq = frequency() as u64;
8484
let t = other.as_secs().checked_mul(freq).and_then(|i| {
8585
(self.t as u64).checked_sub(i)
8686
}).and_then(|i| {
8787
i.checked_sub(mul_div_u64(other.subsec_nanos() as u64, freq, NANOS_PER_SEC))
88-
}).expect("overflow when subtracting duration from time");
89-
Instant {
88+
})?;
89+
Some(Instant {
9090
t: t as c::LARGE_INTEGER,
91-
}
91+
})
9292
}
9393
}
9494

@@ -125,15 +125,13 @@ impl SystemTime {
125125
}
126126

127127
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
128-
checked_dur2intervals(other)
129-
.and_then(|d| self.intervals().checked_add(d))
130-
.map(|i| SystemTime::from_intervals(i))
128+
let intervals = self.intervals().checked_add(checked_dur2intervals(other)?)?;
129+
Some(SystemTime::from_intervals(intervals))
131130
}
132131

133-
pub fn sub_duration(&self, other: &Duration) -> SystemTime {
134-
let intervals = self.intervals().checked_sub(dur2intervals(other))
135-
.expect("overflow when subtracting from time");
136-
SystemTime::from_intervals(intervals)
132+
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
133+
let intervals = self.intervals().checked_sub(checked_dur2intervals(other)?)?;
134+
Some(SystemTime::from_intervals(intervals))
137135
}
138136
}
139137

@@ -185,11 +183,6 @@ fn checked_dur2intervals(dur: &Duration) -> Option<i64> {
185183
.ok()
186184
}
187185

188-
fn dur2intervals(d: &Duration) -> i64 {
189-
checked_dur2intervals(d)
190-
.expect("overflow when converting duration to intervals")
191-
}
192-
193186
fn intervals2dur(intervals: u64) -> Duration {
194187
Duration::new(intervals / INTERVALS_PER_SEC,
195188
((intervals % INTERVALS_PER_SEC) * 100) as u32)

src/libstd/time.rs

+22-2
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,14 @@ impl Instant {
216216
pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
217217
self.0.checked_add_duration(&duration).map(|t| Instant(t))
218218
}
219+
220+
/// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as
221+
/// `Instant` (which means it's inside the bounds of the underlying data structure), `None`
222+
/// otherwise.
223+
#[unstable(feature = "time_checked_add", issue = "55940")]
224+
pub fn checked_sub(&self, duration: Duration) -> Option<Instant> {
225+
self.0.checked_sub_duration(&duration).map(|t| Instant(t))
226+
}
219227
}
220228

221229
#[stable(feature = "time2", since = "1.8.0")]
@@ -240,7 +248,8 @@ impl Sub<Duration> for Instant {
240248
type Output = Instant;
241249

242250
fn sub(self, other: Duration) -> Instant {
243-
Instant(self.0.sub_duration(&other))
251+
self.checked_sub(other)
252+
.expect("overflow when subtracting duration from instant")
244253
}
245254
}
246255

@@ -374,6 +383,14 @@ impl SystemTime {
374383
pub fn checked_add(&self, duration: Duration) -> Option<SystemTime> {
375384
self.0.checked_add_duration(&duration).map(|t| SystemTime(t))
376385
}
386+
387+
/// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be represented as
388+
/// `SystemTime` (which means it's inside the bounds of the underlying data structure), `None`
389+
/// otherwise.
390+
#[unstable(feature = "time_checked_add", issue = "55940")]
391+
pub fn checked_sub(&self, duration: Duration) -> Option<SystemTime> {
392+
self.0.checked_sub_duration(&duration).map(|t| SystemTime(t))
393+
}
377394
}
378395

379396
#[stable(feature = "time2", since = "1.8.0")]
@@ -398,7 +415,8 @@ impl Sub<Duration> for SystemTime {
398415
type Output = SystemTime;
399416

400417
fn sub(self, dur: Duration) -> SystemTime {
401-
SystemTime(self.0.sub_duration(&dur))
418+
self.checked_sub(dur)
419+
.expect("overflow when subtracting duration from instant")
402420
}
403421
}
404422

@@ -531,6 +549,7 @@ mod tests {
531549

532550
let second = Duration::new(1, 0);
533551
assert_almost_eq!(a - second + second, a);
552+
assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a);
534553

535554
// checked_add_duration will not panic on overflow
536555
let mut maybe_t = Some(Instant::now());
@@ -580,6 +599,7 @@ mod tests {
580599
.duration(), second);
581600

582601
assert_almost_eq!(a - second + second, a);
602+
assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a);
583603

584604
// A difference of 80 and 800 years cannot fit inside a 32-bit time_t
585605
if !(cfg!(unix) && ::mem::size_of::<::libc::time_t>() <= 4) {

0 commit comments

Comments
 (0)