@@ -29,6 +29,20 @@ const NANOS_PER_MICRO: u32 = 1_000;
29
29
const MILLIS_PER_SEC : u64 = 1_000 ;
30
30
const MICROS_PER_SEC : u64 = 1_000_000 ;
31
31
32
+ #[ derive( Clone , Copy , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
33
+ #[ repr( transparent) ]
34
+ #[ rustc_layout_scalar_valid_range_start( 0 ) ]
35
+ #[ rustc_layout_scalar_valid_range_end( 999_999_999 ) ]
36
+ struct Nanoseconds ( u32 ) ;
37
+
38
+ impl Default for Nanoseconds {
39
+ #[ inline]
40
+ fn default ( ) -> Self {
41
+ // SAFETY: 0 is within the valid range
42
+ unsafe { Nanoseconds ( 0 ) }
43
+ }
44
+ }
45
+
32
46
/// A `Duration` type to represent a span of time, typically used for system
33
47
/// timeouts.
34
48
///
@@ -71,7 +85,7 @@ const MICROS_PER_SEC: u64 = 1_000_000;
71
85
#[ cfg_attr( not( test) , rustc_diagnostic_item = "Duration" ) ]
72
86
pub struct Duration {
73
87
secs : u64 ,
74
- nanos : u32 , // Always 0 <= nanos < NANOS_PER_SEC
88
+ nanos : Nanoseconds , // Always 0 <= nanos < NANOS_PER_SEC
75
89
}
76
90
77
91
impl Duration {
@@ -188,7 +202,8 @@ impl Duration {
188
202
None => panic ! ( "overflow in Duration::new" ) ,
189
203
} ;
190
204
let nanos = nanos % NANOS_PER_SEC ;
191
- Duration { secs, nanos }
205
+ // SAFETY: nanos % NANOS_PER_SEC < NANOS_PER_SEC, therefore nanos is within the valid range
206
+ Duration { secs, nanos : unsafe { Nanoseconds ( nanos) } }
192
207
}
193
208
194
209
/// Creates a new `Duration` from the specified number of whole seconds.
@@ -208,7 +223,7 @@ impl Duration {
208
223
#[ inline]
209
224
#[ rustc_const_stable( feature = "duration_consts" , since = "1.32.0" ) ]
210
225
pub const fn from_secs ( secs : u64 ) -> Duration {
211
- Duration { secs, nanos : 0 }
226
+ Duration :: new ( secs, 0 )
212
227
}
213
228
214
229
/// Creates a new `Duration` from the specified number of milliseconds.
@@ -228,10 +243,7 @@ impl Duration {
228
243
#[ inline]
229
244
#[ rustc_const_stable( feature = "duration_consts" , since = "1.32.0" ) ]
230
245
pub const fn from_millis ( millis : u64 ) -> Duration {
231
- Duration {
232
- secs : millis / MILLIS_PER_SEC ,
233
- nanos : ( ( millis % MILLIS_PER_SEC ) as u32 ) * NANOS_PER_MILLI ,
234
- }
246
+ Duration :: new ( millis / MILLIS_PER_SEC , ( ( millis % MILLIS_PER_SEC ) as u32 ) * NANOS_PER_MILLI )
235
247
}
236
248
237
249
/// Creates a new `Duration` from the specified number of microseconds.
@@ -251,10 +263,7 @@ impl Duration {
251
263
#[ inline]
252
264
#[ rustc_const_stable( feature = "duration_consts" , since = "1.32.0" ) ]
253
265
pub const fn from_micros ( micros : u64 ) -> Duration {
254
- Duration {
255
- secs : micros / MICROS_PER_SEC ,
256
- nanos : ( ( micros % MICROS_PER_SEC ) as u32 ) * NANOS_PER_MICRO ,
257
- }
266
+ Duration :: new ( micros / MICROS_PER_SEC , ( ( micros % MICROS_PER_SEC ) as u32 ) * NANOS_PER_MICRO )
258
267
}
259
268
260
269
/// Creates a new `Duration` from the specified number of nanoseconds.
@@ -274,10 +283,7 @@ impl Duration {
274
283
#[ inline]
275
284
#[ rustc_const_stable( feature = "duration_consts" , since = "1.32.0" ) ]
276
285
pub const fn from_nanos ( nanos : u64 ) -> Duration {
277
- Duration {
278
- secs : nanos / ( NANOS_PER_SEC as u64 ) ,
279
- nanos : ( nanos % ( NANOS_PER_SEC as u64 ) ) as u32 ,
280
- }
286
+ Duration :: new ( nanos / ( NANOS_PER_SEC as u64 ) , ( nanos % ( NANOS_PER_SEC as u64 ) ) as u32 )
281
287
}
282
288
283
289
/// Returns true if this `Duration` spans no time.
@@ -301,7 +307,7 @@ impl Duration {
301
307
#[ rustc_const_stable( feature = "duration_zero" , since = "1.53.0" ) ]
302
308
#[ inline]
303
309
pub const fn is_zero ( & self ) -> bool {
304
- self . secs == 0 && self . nanos == 0
310
+ self . secs == 0 && self . nanos . 0 == 0
305
311
}
306
312
307
313
/// Returns the number of _whole_ seconds contained by this `Duration`.
@@ -352,7 +358,7 @@ impl Duration {
352
358
#[ must_use]
353
359
#[ inline]
354
360
pub const fn subsec_millis ( & self ) -> u32 {
355
- self . nanos / NANOS_PER_MILLI
361
+ self . nanos . 0 / NANOS_PER_MILLI
356
362
}
357
363
358
364
/// Returns the fractional part of this `Duration`, in whole microseconds.
@@ -375,7 +381,7 @@ impl Duration {
375
381
#[ must_use]
376
382
#[ inline]
377
383
pub const fn subsec_micros ( & self ) -> u32 {
378
- self . nanos / NANOS_PER_MICRO
384
+ self . nanos . 0 / NANOS_PER_MICRO
379
385
}
380
386
381
387
/// Returns the fractional part of this `Duration`, in nanoseconds.
@@ -398,7 +404,7 @@ impl Duration {
398
404
#[ must_use]
399
405
#[ inline]
400
406
pub const fn subsec_nanos ( & self ) -> u32 {
401
- self . nanos
407
+ self . nanos . 0
402
408
}
403
409
404
410
/// Returns the total number of whole milliseconds contained by this `Duration`.
@@ -416,7 +422,7 @@ impl Duration {
416
422
#[ must_use]
417
423
#[ inline]
418
424
pub const fn as_millis ( & self ) -> u128 {
419
- self . secs as u128 * MILLIS_PER_SEC as u128 + ( self . nanos / NANOS_PER_MILLI ) as u128
425
+ self . secs as u128 * MILLIS_PER_SEC as u128 + ( self . nanos . 0 / NANOS_PER_MILLI ) as u128
420
426
}
421
427
422
428
/// Returns the total number of whole microseconds contained by this `Duration`.
@@ -434,7 +440,7 @@ impl Duration {
434
440
#[ must_use]
435
441
#[ inline]
436
442
pub const fn as_micros ( & self ) -> u128 {
437
- self . secs as u128 * MICROS_PER_SEC as u128 + ( self . nanos / NANOS_PER_MICRO ) as u128
443
+ self . secs as u128 * MICROS_PER_SEC as u128 + ( self . nanos . 0 / NANOS_PER_MICRO ) as u128
438
444
}
439
445
440
446
/// Returns the total number of nanoseconds contained by this `Duration`.
@@ -452,7 +458,7 @@ impl Duration {
452
458
#[ must_use]
453
459
#[ inline]
454
460
pub const fn as_nanos ( & self ) -> u128 {
455
- self . secs as u128 * NANOS_PER_SEC as u128 + self . nanos as u128
461
+ self . secs as u128 * NANOS_PER_SEC as u128 + self . nanos . 0 as u128
456
462
}
457
463
458
464
/// Checked `Duration` addition. Computes `self + other`, returning [`None`]
@@ -475,7 +481,7 @@ impl Duration {
475
481
#[ rustc_const_stable( feature = "duration_consts_2" , since = "1.58.0" ) ]
476
482
pub const fn checked_add ( self , rhs : Duration ) -> Option < Duration > {
477
483
if let Some ( mut secs) = self . secs . checked_add ( rhs. secs ) {
478
- let mut nanos = self . nanos + rhs. nanos ;
484
+ let mut nanos = self . nanos . 0 + rhs. nanos . 0 ;
479
485
if nanos >= NANOS_PER_SEC {
480
486
nanos -= NANOS_PER_SEC ;
481
487
if let Some ( new_secs) = secs. checked_add ( 1 ) {
@@ -485,7 +491,7 @@ impl Duration {
485
491
}
486
492
}
487
493
debug_assert ! ( nanos < NANOS_PER_SEC ) ;
488
- Some ( Duration { secs, nanos } )
494
+ Some ( Duration :: new ( secs, nanos) )
489
495
} else {
490
496
None
491
497
}
@@ -535,16 +541,16 @@ impl Duration {
535
541
#[ rustc_const_stable( feature = "duration_consts_2" , since = "1.58.0" ) ]
536
542
pub const fn checked_sub ( self , rhs : Duration ) -> Option < Duration > {
537
543
if let Some ( mut secs) = self . secs . checked_sub ( rhs. secs ) {
538
- let nanos = if self . nanos >= rhs. nanos {
539
- self . nanos - rhs. nanos
544
+ let nanos = if self . nanos . 0 >= rhs. nanos . 0 {
545
+ self . nanos . 0 - rhs. nanos . 0
540
546
} else if let Some ( sub_secs) = secs. checked_sub ( 1 ) {
541
547
secs = sub_secs;
542
- self . nanos + NANOS_PER_SEC - rhs. nanos
548
+ self . nanos . 0 + NANOS_PER_SEC - rhs. nanos . 0
543
549
} else {
544
550
return None ;
545
551
} ;
546
552
debug_assert ! ( nanos < NANOS_PER_SEC ) ;
547
- Some ( Duration { secs, nanos } )
553
+ Some ( Duration :: new ( secs, nanos) )
548
554
} else {
549
555
None
550
556
}
@@ -593,13 +599,13 @@ impl Duration {
593
599
#[ rustc_const_stable( feature = "duration_consts_2" , since = "1.58.0" ) ]
594
600
pub const fn checked_mul ( self , rhs : u32 ) -> Option < Duration > {
595
601
// Multiply nanoseconds as u64, because it cannot overflow that way.
596
- let total_nanos = self . nanos as u64 * rhs as u64 ;
602
+ let total_nanos = self . nanos . 0 as u64 * rhs as u64 ;
597
603
let extra_secs = total_nanos / ( NANOS_PER_SEC as u64 ) ;
598
604
let nanos = ( total_nanos % ( NANOS_PER_SEC as u64 ) ) as u32 ;
599
605
if let Some ( s) = self . secs . checked_mul ( rhs as u64 ) {
600
606
if let Some ( secs) = s. checked_add ( extra_secs) {
601
607
debug_assert ! ( nanos < NANOS_PER_SEC ) ;
602
- return Some ( Duration { secs, nanos } ) ;
608
+ return Some ( Duration :: new ( secs, nanos) ) ;
603
609
}
604
610
}
605
611
None
@@ -653,9 +659,9 @@ impl Duration {
653
659
let secs = self . secs / ( rhs as u64 ) ;
654
660
let carry = self . secs - secs * ( rhs as u64 ) ;
655
661
let extra_nanos = carry * ( NANOS_PER_SEC as u64 ) / ( rhs as u64 ) ;
656
- let nanos = self . nanos / rhs + ( extra_nanos as u32 ) ;
662
+ let nanos = self . nanos . 0 / rhs + ( extra_nanos as u32 ) ;
657
663
debug_assert ! ( nanos < NANOS_PER_SEC ) ;
658
- Some ( Duration { secs, nanos } )
664
+ Some ( Duration :: new ( secs, nanos) )
659
665
} else {
660
666
None
661
667
}
@@ -677,7 +683,7 @@ impl Duration {
677
683
#[ inline]
678
684
#[ rustc_const_unstable( feature = "duration_consts_float" , issue = "72440" ) ]
679
685
pub const fn as_secs_f64 ( & self ) -> f64 {
680
- ( self . secs as f64 ) + ( self . nanos as f64 ) / ( NANOS_PER_SEC as f64 )
686
+ ( self . secs as f64 ) + ( self . nanos . 0 as f64 ) / ( NANOS_PER_SEC as f64 )
681
687
}
682
688
683
689
/// Returns the number of seconds contained by this `Duration` as `f32`.
@@ -696,7 +702,7 @@ impl Duration {
696
702
#[ inline]
697
703
#[ rustc_const_unstable( feature = "duration_consts_float" , issue = "72440" ) ]
698
704
pub const fn as_secs_f32 ( & self ) -> f32 {
699
- ( self . secs as f32 ) + ( self . nanos as f32 ) / ( NANOS_PER_SEC as f32 )
705
+ ( self . secs as f32 ) + ( self . nanos . 0 as f32 ) / ( NANOS_PER_SEC as f32 )
700
706
}
701
707
702
708
/// Creates a new `Duration` from the specified number of seconds represented
@@ -987,21 +993,21 @@ macro_rules! sum_durations {
987
993
for entry in $iter {
988
994
total_secs =
989
995
total_secs. checked_add( entry. secs) . expect( "overflow in iter::sum over durations" ) ;
990
- total_nanos = match total_nanos. checked_add( entry. nanos as u64 ) {
996
+ total_nanos = match total_nanos. checked_add( entry. nanos. 0 as u64 ) {
991
997
Some ( n) => n,
992
998
None => {
993
999
total_secs = total_secs
994
1000
. checked_add( total_nanos / NANOS_PER_SEC as u64 )
995
1001
. expect( "overflow in iter::sum over durations" ) ;
996
- ( total_nanos % NANOS_PER_SEC as u64 ) + entry. nanos as u64
1002
+ ( total_nanos % NANOS_PER_SEC as u64 ) + entry. nanos. 0 as u64
997
1003
}
998
1004
} ;
999
1005
}
1000
1006
total_secs = total_secs
1001
1007
. checked_add( total_nanos / NANOS_PER_SEC as u64 )
1002
1008
. expect( "overflow in iter::sum over durations" ) ;
1003
1009
total_nanos = total_nanos % NANOS_PER_SEC as u64 ;
1004
- Duration { secs : total_secs, nanos : total_nanos as u32 }
1010
+ Duration :: new ( total_secs, total_nanos as u32 )
1005
1011
} } ;
1006
1012
}
1007
1013
@@ -1166,27 +1172,27 @@ impl fmt::Debug for Duration {
1166
1172
let prefix = if f. sign_plus ( ) { "+" } else { "" } ;
1167
1173
1168
1174
if self . secs > 0 {
1169
- fmt_decimal ( f, self . secs , self . nanos , NANOS_PER_SEC / 10 , prefix, "s" )
1170
- } else if self . nanos >= NANOS_PER_MILLI {
1175
+ fmt_decimal ( f, self . secs , self . nanos . 0 , NANOS_PER_SEC / 10 , prefix, "s" )
1176
+ } else if self . nanos . 0 >= NANOS_PER_MILLI {
1171
1177
fmt_decimal (
1172
1178
f,
1173
- ( self . nanos / NANOS_PER_MILLI ) as u64 ,
1174
- self . nanos % NANOS_PER_MILLI ,
1179
+ ( self . nanos . 0 / NANOS_PER_MILLI ) as u64 ,
1180
+ self . nanos . 0 % NANOS_PER_MILLI ,
1175
1181
NANOS_PER_MILLI / 10 ,
1176
1182
prefix,
1177
1183
"ms" ,
1178
1184
)
1179
- } else if self . nanos >= NANOS_PER_MICRO {
1185
+ } else if self . nanos . 0 >= NANOS_PER_MICRO {
1180
1186
fmt_decimal (
1181
1187
f,
1182
- ( self . nanos / NANOS_PER_MICRO ) as u64 ,
1183
- self . nanos % NANOS_PER_MICRO ,
1188
+ ( self . nanos . 0 / NANOS_PER_MICRO ) as u64 ,
1189
+ self . nanos . 0 % NANOS_PER_MICRO ,
1184
1190
NANOS_PER_MICRO / 10 ,
1185
1191
prefix,
1186
1192
"µs" ,
1187
1193
)
1188
1194
} else {
1189
- fmt_decimal ( f, self . nanos as u64 , 0 , 1 , prefix, "ns" )
1195
+ fmt_decimal ( f, self . nanos . 0 as u64 , 0 , 1 , prefix, "ns" )
1190
1196
}
1191
1197
}
1192
1198
}
@@ -1317,7 +1323,7 @@ macro_rules! try_from_secs {
1317
1323
return Err ( FromFloatSecsError { kind: FromFloatSecsErrorKind :: OverflowOrNan } ) ;
1318
1324
} ;
1319
1325
1320
- Ok ( Duration { secs, nanos } )
1326
+ Ok ( Duration :: new ( secs, nanos) )
1321
1327
} } ;
1322
1328
}
1323
1329
0 commit comments