@@ -97,22 +97,154 @@ impl Duration {
97
97
#[ stable( feature = "duration" , since = "1.3.0" ) ]
98
98
#[ inline]
99
99
pub fn subsec_nanos ( & self ) -> u32 { self . nanos }
100
+
101
+ /// Checked duration addition. Computes `self + other`, returning `None`
102
+ /// if overflow occurred.
103
+ ///
104
+ /// # Examples
105
+ ///
106
+ /// Basic usage:
107
+ ///
108
+ /// ```
109
+ /// #![feature(duration_checked_ops)]
110
+ ///
111
+ /// use std::time::Duration;
112
+ ///
113
+ /// assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1)));
114
+ /// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(std::u64::MAX, 0)), None);
115
+ /// ```
116
+ #[ unstable( feature = "duration_checked_ops" , issue = "35774" ) ]
117
+ #[ inline]
118
+ pub fn checked_add ( self , rhs : Duration ) -> Option < Duration > {
119
+ if let Some ( mut secs) = self . secs . checked_add ( rhs. secs ) {
120
+ let mut nanos = self . nanos + rhs. nanos ;
121
+ if nanos >= NANOS_PER_SEC {
122
+ nanos -= NANOS_PER_SEC ;
123
+ if let Some ( new_secs) = secs. checked_add ( 1 ) {
124
+ secs = new_secs;
125
+ } else {
126
+ return None ;
127
+ }
128
+ }
129
+ debug_assert ! ( nanos < NANOS_PER_SEC ) ;
130
+ Some ( Duration {
131
+ secs : secs,
132
+ nanos : nanos,
133
+ } )
134
+ } else {
135
+ None
136
+ }
137
+ }
138
+
139
+ /// Checked duration subtraction. Computes `self + other`, returning `None`
140
+ /// if the result would be negative or if underflow occurred.
141
+ ///
142
+ /// # Examples
143
+ ///
144
+ /// Basic usage:
145
+ ///
146
+ /// ```
147
+ /// #![feature(duration_checked_ops)]
148
+ ///
149
+ /// use std::time::Duration;
150
+ ///
151
+ /// assert_eq!(Duration::new(0, 1).checked_sub(Duration::new(0, 0)), Some(Duration::new(0, 1)));
152
+ /// assert_eq!(Duration::new(0, 0).checked_sub(Duration::new(0, 1)), None);
153
+ /// ```
154
+ #[ unstable( feature = "duration_checked_ops" , issue = "35774" ) ]
155
+ #[ inline]
156
+ pub fn checked_sub ( self , rhs : Duration ) -> Option < Duration > {
157
+ if let Some ( mut secs) = self . secs . checked_sub ( rhs. secs ) {
158
+ let nanos = if self . nanos >= rhs. nanos {
159
+ self . nanos - rhs. nanos
160
+ } else {
161
+ if let Some ( sub_secs) = secs. checked_sub ( 1 ) {
162
+ secs = sub_secs;
163
+ self . nanos + NANOS_PER_SEC - rhs. nanos
164
+ } else {
165
+ return None ;
166
+ }
167
+ } ;
168
+ debug_assert ! ( nanos < NANOS_PER_SEC ) ;
169
+ Some ( Duration { secs : secs, nanos : nanos } )
170
+ } else {
171
+ None
172
+ }
173
+ }
174
+
175
+ /// Checked duration multiplication. Computes `self * other`, returning
176
+ /// `None` if underflow or overflow occurred.
177
+ ///
178
+ /// # Examples
179
+ ///
180
+ /// Basic usage:
181
+ ///
182
+ /// ```
183
+ /// #![feature(duration_checked_ops)]
184
+ ///
185
+ /// use std::time::Duration;
186
+ ///
187
+ /// assert_eq!(Duration::new(0, 500_000_001).checked_mul(2), Some(Duration::new(1, 2)));
188
+ /// assert_eq!(Duration::new(std::u64::MAX - 1, 0).checked_mul(2), None);
189
+ /// ```
190
+ #[ unstable( feature = "duration_checked_ops" , issue = "35774" ) ]
191
+ #[ inline]
192
+ pub fn checked_mul ( self , rhs : u32 ) -> Option < Duration > {
193
+ // Multiply nanoseconds as u64, because it cannot overflow that way.
194
+ let total_nanos = self . nanos as u64 * rhs as u64 ;
195
+ let extra_secs = total_nanos / ( NANOS_PER_SEC as u64 ) ;
196
+ let nanos = ( total_nanos % ( NANOS_PER_SEC as u64 ) ) as u32 ;
197
+ if let Some ( secs) = self . secs
198
+ . checked_mul ( rhs as u64 )
199
+ . and_then ( |s| s. checked_add ( extra_secs) ) {
200
+ debug_assert ! ( nanos < NANOS_PER_SEC ) ;
201
+ Some ( Duration {
202
+ secs : secs,
203
+ nanos : nanos,
204
+ } )
205
+ } else {
206
+ None
207
+ }
208
+ }
209
+
210
+ /// Checked duration division. Computes `self / other`, returning `None`
211
+ /// if `other == 0` or the operation results in underflow or overflow.
212
+ ///
213
+ /// # Examples
214
+ ///
215
+ /// Basic usage:
216
+ ///
217
+ /// ```
218
+ /// #![feature(duration_checked_ops)]
219
+ ///
220
+ /// use std::time::Duration;
221
+ ///
222
+ /// assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0)));
223
+ /// assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000)));
224
+ /// assert_eq!(Duration::new(2, 0).checked_div(0), None);
225
+ /// ```
226
+ #[ unstable( feature = "duration_checked_ops" , issue = "35774" ) ]
227
+ #[ inline]
228
+ pub fn checked_div ( self , rhs : u32 ) -> Option < Duration > {
229
+ if rhs != 0 {
230
+ let secs = self . secs / ( rhs as u64 ) ;
231
+ let carry = self . secs - secs * ( rhs as u64 ) ;
232
+ let extra_nanos = carry * ( NANOS_PER_SEC as u64 ) / ( rhs as u64 ) ;
233
+ let nanos = self . nanos / rhs + ( extra_nanos as u32 ) ;
234
+ debug_assert ! ( nanos < NANOS_PER_SEC ) ;
235
+ Some ( Duration { secs : secs, nanos : nanos } )
236
+ } else {
237
+ None
238
+ }
239
+ }
100
240
}
101
241
102
242
#[ stable( feature = "duration" , since = "1.3.0" ) ]
103
243
impl Add for Duration {
104
244
type Output = Duration ;
105
245
106
246
fn add ( self , rhs : Duration ) -> Duration {
107
- let mut secs = self . secs . checked_add ( rhs. secs )
108
- . expect ( "overflow when adding durations" ) ;
109
- let mut nanos = self . nanos + rhs. nanos ;
110
- if nanos >= NANOS_PER_SEC {
111
- nanos -= NANOS_PER_SEC ;
112
- secs = secs. checked_add ( 1 ) . expect ( "overflow when adding durations" ) ;
113
- }
114
- debug_assert ! ( nanos < NANOS_PER_SEC ) ;
115
- Duration { secs : secs, nanos : nanos }
247
+ self . checked_add ( rhs) . expect ( "overflow when adding durations" )
116
248
}
117
249
}
118
250
@@ -128,17 +260,7 @@ impl Sub for Duration {
128
260
type Output = Duration ;
129
261
130
262
fn sub ( self , rhs : Duration ) -> Duration {
131
- let mut secs = self . secs . checked_sub ( rhs. secs )
132
- . expect ( "overflow when subtracting durations" ) ;
133
- let nanos = if self . nanos >= rhs. nanos {
134
- self . nanos - rhs. nanos
135
- } else {
136
- secs = secs. checked_sub ( 1 )
137
- . expect ( "overflow when subtracting durations" ) ;
138
- self . nanos + NANOS_PER_SEC - rhs. nanos
139
- } ;
140
- debug_assert ! ( nanos < NANOS_PER_SEC ) ;
141
- Duration { secs : secs, nanos : nanos }
263
+ self . checked_sub ( rhs) . expect ( "overflow when subtracting durations" )
142
264
}
143
265
}
144
266
@@ -154,15 +276,7 @@ impl Mul<u32> for Duration {
154
276
type Output = Duration ;
155
277
156
278
fn mul ( self , rhs : u32 ) -> Duration {
157
- // Multiply nanoseconds as u64, because it cannot overflow that way.
158
- let total_nanos = self . nanos as u64 * rhs as u64 ;
159
- let extra_secs = total_nanos / ( NANOS_PER_SEC as u64 ) ;
160
- let nanos = ( total_nanos % ( NANOS_PER_SEC as u64 ) ) as u32 ;
161
- let secs = self . secs . checked_mul ( rhs as u64 )
162
- . and_then ( |s| s. checked_add ( extra_secs) )
163
- . expect ( "overflow when multiplying duration" ) ;
164
- debug_assert ! ( nanos < NANOS_PER_SEC ) ;
165
- Duration { secs : secs, nanos : nanos }
279
+ self . checked_mul ( rhs) . expect ( "overflow when multiplying duration by scalar" )
166
280
}
167
281
}
168
282
@@ -178,12 +292,7 @@ impl Div<u32> for Duration {
178
292
type Output = Duration ;
179
293
180
294
fn div ( self , rhs : u32 ) -> Duration {
181
- let secs = self . secs / ( rhs as u64 ) ;
182
- let carry = self . secs - secs * ( rhs as u64 ) ;
183
- let extra_nanos = carry * ( NANOS_PER_SEC as u64 ) / ( rhs as u64 ) ;
184
- let nanos = self . nanos / rhs + ( extra_nanos as u32 ) ;
185
- debug_assert ! ( nanos < NANOS_PER_SEC ) ;
186
- Duration { secs : secs, nanos : nanos }
295
+ self . checked_div ( rhs) . expect ( "divide by zero error when dividing duration by scalar" )
187
296
}
188
297
}
189
298
@@ -234,6 +343,15 @@ mod tests {
234
343
Duration :: new( 1 , 1 ) ) ;
235
344
}
236
345
346
+ #[ test]
347
+ fn checked_add ( ) {
348
+ assert_eq ! ( Duration :: new( 0 , 0 ) . checked_add( Duration :: new( 0 , 1 ) ) ,
349
+ Some ( Duration :: new( 0 , 1 ) ) ) ;
350
+ assert_eq ! ( Duration :: new( 0 , 500_000_000 ) . checked_add( Duration :: new( 0 , 500_000_001 ) ) ,
351
+ Some ( Duration :: new( 1 , 1 ) ) ) ;
352
+ assert_eq ! ( Duration :: new( 1 , 0 ) . checked_add( Duration :: new( :: u64 :: MAX , 0 ) ) , None ) ;
353
+ }
354
+
237
355
#[ test]
238
356
fn sub ( ) {
239
357
assert_eq ! ( Duration :: new( 0 , 1 ) - Duration :: new( 0 , 0 ) ,
@@ -244,6 +362,18 @@ mod tests {
244
362
Duration :: new( 0 , 999_999_999 ) ) ;
245
363
}
246
364
365
+ #[ test]
366
+ fn checked_sub ( ) {
367
+ let zero = Duration :: new ( 0 , 0 ) ;
368
+ let one_nano = Duration :: new ( 0 , 1 ) ;
369
+ let one_sec = Duration :: new ( 1 , 0 ) ;
370
+ assert_eq ! ( one_nano. checked_sub( zero) , Some ( Duration :: new( 0 , 1 ) ) ) ;
371
+ assert_eq ! ( one_sec. checked_sub( one_nano) ,
372
+ Some ( Duration :: new( 0 , 999_999_999 ) ) ) ;
373
+ assert_eq ! ( zero. checked_sub( one_nano) , None ) ;
374
+ assert_eq ! ( zero. checked_sub( one_sec) , None ) ;
375
+ }
376
+
247
377
#[ test] #[ should_panic]
248
378
fn sub_bad1 ( ) {
249
379
Duration :: new ( 0 , 0 ) - Duration :: new ( 0 , 1 ) ;
@@ -263,11 +393,28 @@ mod tests {
263
393
Duration :: new( 2000 , 4000 ) ) ;
264
394
}
265
395
396
+ #[ test]
397
+ fn checked_mul ( ) {
398
+ assert_eq ! ( Duration :: new( 0 , 1 ) . checked_mul( 2 ) , Some ( Duration :: new( 0 , 2 ) ) ) ;
399
+ assert_eq ! ( Duration :: new( 1 , 1 ) . checked_mul( 3 ) , Some ( Duration :: new( 3 , 3 ) ) ) ;
400
+ assert_eq ! ( Duration :: new( 0 , 500_000_001 ) . checked_mul( 4 ) , Some ( Duration :: new( 2 , 4 ) ) ) ;
401
+ assert_eq ! ( Duration :: new( 0 , 500_000_001 ) . checked_mul( 4000 ) ,
402
+ Some ( Duration :: new( 2000 , 4000 ) ) ) ;
403
+ assert_eq ! ( Duration :: new( :: u64 :: MAX - 1 , 0 ) . checked_mul( 2 ) , None ) ;
404
+ }
405
+
266
406
#[ test]
267
407
fn div ( ) {
268
408
assert_eq ! ( Duration :: new( 0 , 1 ) / 2 , Duration :: new( 0 , 0 ) ) ;
269
409
assert_eq ! ( Duration :: new( 1 , 1 ) / 3 , Duration :: new( 0 , 333_333_333 ) ) ;
270
410
assert_eq ! ( Duration :: new( 99 , 999_999_000 ) / 100 ,
271
411
Duration :: new( 0 , 999_999_990 ) ) ;
272
412
}
413
+
414
+ #[ test]
415
+ fn checked_div ( ) {
416
+ assert_eq ! ( Duration :: new( 2 , 0 ) . checked_div( 2 ) , Some ( Duration :: new( 1 , 0 ) ) ) ;
417
+ assert_eq ! ( Duration :: new( 1 , 0 ) . checked_div( 2 ) , Some ( Duration :: new( 0 , 500_000_000 ) ) ) ;
418
+ assert_eq ! ( Duration :: new( 2 , 0 ) . checked_div( 0 ) , None ) ;
419
+ }
273
420
}
0 commit comments