@@ -97,6 +97,130 @@ 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
+ /// assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1)));
110
+ /// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(::u64::MAX, 0)), None);
111
+ /// ```
112
+ #[ unstable( feature = "duration_checked_ops" , issue = "35774" ) ]
113
+ #[ inline]
114
+ pub fn checked_add ( self , rhs : Duration ) -> Option < Duration > {
115
+ if let Some ( mut secs) = self . secs . checked_add ( rhs. secs ) {
116
+ let mut nanos = self . nanos + rhs. nanos ;
117
+ if nanos >= NANOS_PER_SEC {
118
+ nanos -= NANOS_PER_SEC ;
119
+ if let Some ( new_secs) = secs. checked_add ( 1 ) {
120
+ secs = new_secs;
121
+ } else {
122
+ return None ;
123
+ }
124
+ }
125
+ debug_assert ! ( nanos < NANOS_PER_SEC ) ;
126
+ Some ( Duration {
127
+ secs : secs,
128
+ nanos : nanos,
129
+ } )
130
+ } else {
131
+ None
132
+ }
133
+ }
134
+
135
+ /// Checked duration subtraction. Computes `self + other`, returning `None`
136
+ /// if the result would be negative or if underflow occurred.
137
+ ///
138
+ /// # Examples
139
+ ///
140
+ /// Basic usage:
141
+ ///
142
+ /// ```
143
+ /// assert_eq!(Duration::new(0, 1).checked_sub(Duration::new(0, 0)), Some(Duration::new(0, 1)));
144
+ /// assert_eq!(Duration::new(0, 0).checked_sub(Duration::new(0, 1)), None);
145
+ /// ```
146
+ #[ unstable( feature = "duration_checked_ops" , issue = "35774" ) ]
147
+ #[ inline]
148
+ pub fn checked_sub ( self , rhs : Duration ) -> Option < Duration > {
149
+ if let Some ( mut secs) = self . secs . checked_sub ( rhs. secs ) {
150
+ let nanos = if self . nanos >= rhs. nanos {
151
+ self . nanos - rhs. nanos
152
+ } else {
153
+ if let Some ( sub_secs) = secs. checked_sub ( 1 ) {
154
+ secs = sub_secs;
155
+ self . nanos + NANOS_PER_SEC - rhs. nanos
156
+ } else {
157
+ return None ;
158
+ }
159
+ } ;
160
+ debug_assert ! ( nanos < NANOS_PER_SEC ) ;
161
+ Some ( Duration { secs : secs, nanos : nanos } )
162
+ } else {
163
+ None
164
+ }
165
+ }
166
+
167
+ /// Checked integer multiplication. Computes `self * other`, returning
168
+ /// `None` if underflow or overflow occurred.
169
+ ///
170
+ /// # Examples
171
+ ///
172
+ /// Basic usage:
173
+ ///
174
+ /// ```
175
+ /// assert_eq!(Duration::new(0, 500_000_001).checked_mul(2), Some(Duration::new(1, 2)));
176
+ /// assert_eq!(Duration::new(::u64::MAX - 1, 0).checked_mul(2), None);
177
+ /// ```
178
+ #[ unstable( feature = "duration_checked_ops" , issue = "35774" ) ]
179
+ #[ inline]
180
+ pub fn checked_mul ( self , rhs : u32 ) -> Option < Duration > {
181
+ // Multiply nanoseconds as u64, because it cannot overflow that way.
182
+ let total_nanos = self . nanos as u64 * rhs as u64 ;
183
+ let extra_secs = total_nanos / ( NANOS_PER_SEC as u64 ) ;
184
+ let nanos = ( total_nanos % ( NANOS_PER_SEC as u64 ) ) as u32 ;
185
+ if let Some ( secs) = self . secs
186
+ . checked_mul ( rhs as u64 )
187
+ . and_then ( |s| s. checked_add ( extra_secs) ) {
188
+ debug_assert ! ( nanos < NANOS_PER_SEC ) ;
189
+ Some ( Duration {
190
+ secs : secs,
191
+ nanos : nanos,
192
+ } )
193
+ } else {
194
+ None
195
+ }
196
+ }
197
+
198
+ /// Checked duration division. Computes `self / other`, returning `None`
199
+ /// if `other == 0` or the operation results in underflow or overflow.
200
+ ///
201
+ /// # Examples
202
+ ///
203
+ /// Basic usage:
204
+ ///
205
+ /// ```
206
+ /// assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0)));
207
+ /// assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000)));
208
+ /// assert_eq!(Duration::new(2, 0).checked_div(0), None);
209
+ /// ```
210
+ #[ unstable( feature = "duration_checked_ops" , issue = "35774" ) ]
211
+ #[ inline]
212
+ pub fn checked_div ( self , rhs : u32 ) -> Option < Duration > {
213
+ if rhs != 0 {
214
+ let secs = self . secs / ( rhs as u64 ) ;
215
+ let carry = self . secs - secs * ( rhs as u64 ) ;
216
+ let extra_nanos = carry * ( NANOS_PER_SEC as u64 ) / ( rhs as u64 ) ;
217
+ let nanos = self . nanos / rhs + ( extra_nanos as u32 ) ;
218
+ debug_assert ! ( nanos < NANOS_PER_SEC ) ;
219
+ Some ( Duration { secs : secs, nanos : nanos } )
220
+ } else {
221
+ None
222
+ }
223
+ }
100
224
}
101
225
102
226
#[ stable( feature = "duration" , since = "1.3.0" ) ]
@@ -234,6 +358,15 @@ mod tests {
234
358
Duration :: new( 1 , 1 ) ) ;
235
359
}
236
360
361
+ #[ test]
362
+ fn checked_add ( ) {
363
+ assert_eq ! ( Duration :: new( 0 , 0 ) . checked_add( Duration :: new( 0 , 1 ) ) ,
364
+ Some ( Duration :: new( 0 , 1 ) ) ) ;
365
+ assert_eq ! ( Duration :: new( 0 , 500_000_000 ) . checked_add( Duration :: new( 0 , 500_000_001 ) ) ,
366
+ Some ( Duration :: new( 1 , 1 ) ) ) ;
367
+ assert_eq ! ( Duration :: new( 1 , 0 ) . checked_add( Duration :: new( :: u64 :: MAX , 0 ) ) , None ) ;
368
+ }
369
+
237
370
#[ test]
238
371
fn sub ( ) {
239
372
assert_eq ! ( Duration :: new( 0 , 1 ) - Duration :: new( 0 , 0 ) ,
@@ -244,6 +377,18 @@ mod tests {
244
377
Duration :: new( 0 , 999_999_999 ) ) ;
245
378
}
246
379
380
+ #[ test]
381
+ fn checked_sub ( ) {
382
+ let zero = Duration :: new ( 0 , 0 ) ;
383
+ let one_nano = Duration :: new ( 0 , 1 ) ;
384
+ let one_sec = Duration :: new ( 1 , 0 ) ;
385
+ assert_eq ! ( one_nano. checked_sub( zero) , Some ( Duration :: new( 0 , 1 ) ) ) ;
386
+ assert_eq ! ( one_sec. checked_sub( one_nano) ,
387
+ Some ( Duration :: new( 0 , 999_999_999 ) ) ) ;
388
+ assert_eq ! ( zero. checked_sub( one_nano) , None ) ;
389
+ assert_eq ! ( zero. checked_sub( one_sec) , None ) ;
390
+ }
391
+
247
392
#[ test] #[ should_panic]
248
393
fn sub_bad1 ( ) {
249
394
Duration :: new ( 0 , 0 ) - Duration :: new ( 0 , 1 ) ;
@@ -263,11 +408,28 @@ mod tests {
263
408
Duration :: new( 2000 , 4000 ) ) ;
264
409
}
265
410
411
+ #[ test]
412
+ fn checked_mul ( ) {
413
+ assert_eq ! ( Duration :: new( 0 , 1 ) . checked_mul( 2 ) , Some ( Duration :: new( 0 , 2 ) ) ) ;
414
+ assert_eq ! ( Duration :: new( 1 , 1 ) . checked_mul( 3 ) , Some ( Duration :: new( 3 , 3 ) ) ) ;
415
+ assert_eq ! ( Duration :: new( 0 , 500_000_001 ) . checked_mul( 4 ) , Some ( Duration :: new( 2 , 4 ) ) ) ;
416
+ assert_eq ! ( Duration :: new( 0 , 500_000_001 ) . checked_mul( 4000 ) ,
417
+ Some ( Duration :: new( 2000 , 4000 ) ) ) ;
418
+ assert_eq ! ( Duration :: new( :: u64 :: MAX - 1 , 0 ) . checked_mul( 2 ) , None ) ;
419
+ }
420
+
266
421
#[ test]
267
422
fn div ( ) {
268
423
assert_eq ! ( Duration :: new( 0 , 1 ) / 2 , Duration :: new( 0 , 0 ) ) ;
269
424
assert_eq ! ( Duration :: new( 1 , 1 ) / 3 , Duration :: new( 0 , 333_333_333 ) ) ;
270
425
assert_eq ! ( Duration :: new( 99 , 999_999_000 ) / 100 ,
271
426
Duration :: new( 0 , 999_999_990 ) ) ;
272
427
}
428
+
429
+ #[ test]
430
+ fn checked_div ( ) {
431
+ assert_eq ! ( Duration :: new( 2 , 0 ) . checked_div( 2 ) , Some ( Duration :: new( 1 , 0 ) ) ) ;
432
+ assert_eq ! ( Duration :: new( 1 , 0 ) . checked_div( 2 ) , Some ( Duration :: new( 0 , 500_000_000 ) ) ) ;
433
+ assert_eq ! ( Duration :: new( 2 , 0 ) . checked_div( 0 ) , None ) ;
434
+ }
273
435
}
0 commit comments