@@ -29,6 +29,20 @@ const NANOS_PER_MICRO: u32 = 1_000;
2929const MILLIS_PER_SEC : u64 = 1_000 ;
3030const MICROS_PER_SEC : u64 = 1_000_000 ;
3131
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+
3246/// A `Duration` type to represent a span of time, typically used for system
3347/// timeouts.
3448///
@@ -71,7 +85,7 @@ const MICROS_PER_SEC: u64 = 1_000_000;
7185#[ cfg_attr( not( test) , rustc_diagnostic_item = "Duration" ) ]
7286pub struct Duration {
7387 secs : u64 ,
74- nanos : u32 , // Always 0 <= nanos < NANOS_PER_SEC
88+ nanos : Nanoseconds , // Always 0 <= nanos < NANOS_PER_SEC
7589}
7690
7791impl Duration {
@@ -188,7 +202,8 @@ impl Duration {
188202 None => panic ! ( "overflow in Duration::new" ) ,
189203 } ;
190204 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) } }
192207 }
193208
194209 /// Creates a new `Duration` from the specified number of whole seconds.
@@ -208,7 +223,7 @@ impl Duration {
208223 #[ inline]
209224 #[ rustc_const_stable( feature = "duration_consts" , since = "1.32.0" ) ]
210225 pub const fn from_secs ( secs : u64 ) -> Duration {
211- Duration { secs, nanos : 0 }
226+ Duration :: new ( secs, 0 )
212227 }
213228
214229 /// Creates a new `Duration` from the specified number of milliseconds.
@@ -228,10 +243,7 @@ impl Duration {
228243 #[ inline]
229244 #[ rustc_const_stable( feature = "duration_consts" , since = "1.32.0" ) ]
230245 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 )
235247 }
236248
237249 /// Creates a new `Duration` from the specified number of microseconds.
@@ -251,10 +263,7 @@ impl Duration {
251263 #[ inline]
252264 #[ rustc_const_stable( feature = "duration_consts" , since = "1.32.0" ) ]
253265 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 )
258267 }
259268
260269 /// Creates a new `Duration` from the specified number of nanoseconds.
@@ -274,10 +283,7 @@ impl Duration {
274283 #[ inline]
275284 #[ rustc_const_stable( feature = "duration_consts" , since = "1.32.0" ) ]
276285 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 )
281287 }
282288
283289 /// Returns true if this `Duration` spans no time.
@@ -301,7 +307,7 @@ impl Duration {
301307 #[ rustc_const_stable( feature = "duration_zero" , since = "1.53.0" ) ]
302308 #[ inline]
303309 pub const fn is_zero ( & self ) -> bool {
304- self . secs == 0 && self . nanos == 0
310+ self . secs == 0 && self . nanos . 0 == 0
305311 }
306312
307313 /// Returns the number of _whole_ seconds contained by this `Duration`.
@@ -352,7 +358,7 @@ impl Duration {
352358 #[ must_use]
353359 #[ inline]
354360 pub const fn subsec_millis ( & self ) -> u32 {
355- self . nanos / NANOS_PER_MILLI
361+ self . nanos . 0 / NANOS_PER_MILLI
356362 }
357363
358364 /// Returns the fractional part of this `Duration`, in whole microseconds.
@@ -375,7 +381,7 @@ impl Duration {
375381 #[ must_use]
376382 #[ inline]
377383 pub const fn subsec_micros ( & self ) -> u32 {
378- self . nanos / NANOS_PER_MICRO
384+ self . nanos . 0 / NANOS_PER_MICRO
379385 }
380386
381387 /// Returns the fractional part of this `Duration`, in nanoseconds.
@@ -398,7 +404,7 @@ impl Duration {
398404 #[ must_use]
399405 #[ inline]
400406 pub const fn subsec_nanos ( & self ) -> u32 {
401- self . nanos
407+ self . nanos . 0
402408 }
403409
404410 /// Returns the total number of whole milliseconds contained by this `Duration`.
@@ -416,7 +422,7 @@ impl Duration {
416422 #[ must_use]
417423 #[ inline]
418424 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
420426 }
421427
422428 /// Returns the total number of whole microseconds contained by this `Duration`.
@@ -434,7 +440,7 @@ impl Duration {
434440 #[ must_use]
435441 #[ inline]
436442 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
438444 }
439445
440446 /// Returns the total number of nanoseconds contained by this `Duration`.
@@ -452,7 +458,7 @@ impl Duration {
452458 #[ must_use]
453459 #[ inline]
454460 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
456462 }
457463
458464 /// Checked `Duration` addition. Computes `self + other`, returning [`None`]
@@ -475,7 +481,7 @@ impl Duration {
475481 #[ rustc_const_stable( feature = "duration_consts_2" , since = "1.58.0" ) ]
476482 pub const fn checked_add ( self , rhs : Duration ) -> Option < Duration > {
477483 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 ;
479485 if nanos >= NANOS_PER_SEC {
480486 nanos -= NANOS_PER_SEC ;
481487 if let Some ( new_secs) = secs. checked_add ( 1 ) {
@@ -485,7 +491,7 @@ impl Duration {
485491 }
486492 }
487493 debug_assert ! ( nanos < NANOS_PER_SEC ) ;
488- Some ( Duration { secs, nanos } )
494+ Some ( Duration :: new ( secs, nanos) )
489495 } else {
490496 None
491497 }
@@ -535,16 +541,16 @@ impl Duration {
535541 #[ rustc_const_stable( feature = "duration_consts_2" , since = "1.58.0" ) ]
536542 pub const fn checked_sub ( self , rhs : Duration ) -> Option < Duration > {
537543 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
540546 } else if let Some ( sub_secs) = secs. checked_sub ( 1 ) {
541547 secs = sub_secs;
542- self . nanos + NANOS_PER_SEC - rhs. nanos
548+ self . nanos . 0 + NANOS_PER_SEC - rhs. nanos . 0
543549 } else {
544550 return None ;
545551 } ;
546552 debug_assert ! ( nanos < NANOS_PER_SEC ) ;
547- Some ( Duration { secs, nanos } )
553+ Some ( Duration :: new ( secs, nanos) )
548554 } else {
549555 None
550556 }
@@ -593,13 +599,13 @@ impl Duration {
593599 #[ rustc_const_stable( feature = "duration_consts_2" , since = "1.58.0" ) ]
594600 pub const fn checked_mul ( self , rhs : u32 ) -> Option < Duration > {
595601 // 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 ;
597603 let extra_secs = total_nanos / ( NANOS_PER_SEC as u64 ) ;
598604 let nanos = ( total_nanos % ( NANOS_PER_SEC as u64 ) ) as u32 ;
599605 if let Some ( s) = self . secs . checked_mul ( rhs as u64 ) {
600606 if let Some ( secs) = s. checked_add ( extra_secs) {
601607 debug_assert ! ( nanos < NANOS_PER_SEC ) ;
602- return Some ( Duration { secs, nanos } ) ;
608+ return Some ( Duration :: new ( secs, nanos) ) ;
603609 }
604610 }
605611 None
@@ -653,9 +659,9 @@ impl Duration {
653659 let secs = self . secs / ( rhs as u64 ) ;
654660 let carry = self . secs - secs * ( rhs as u64 ) ;
655661 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 ) ;
657663 debug_assert ! ( nanos < NANOS_PER_SEC ) ;
658- Some ( Duration { secs, nanos } )
664+ Some ( Duration :: new ( secs, nanos) )
659665 } else {
660666 None
661667 }
@@ -677,7 +683,7 @@ impl Duration {
677683 #[ inline]
678684 #[ rustc_const_unstable( feature = "duration_consts_float" , issue = "72440" ) ]
679685 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 )
681687 }
682688
683689 /// Returns the number of seconds contained by this `Duration` as `f32`.
@@ -696,7 +702,7 @@ impl Duration {
696702 #[ inline]
697703 #[ rustc_const_unstable( feature = "duration_consts_float" , issue = "72440" ) ]
698704 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 )
700706 }
701707
702708 /// Creates a new `Duration` from the specified number of seconds represented
@@ -987,21 +993,21 @@ macro_rules! sum_durations {
987993 for entry in $iter {
988994 total_secs =
989995 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 ) {
991997 Some ( n) => n,
992998 None => {
993999 total_secs = total_secs
9941000 . checked_add( total_nanos / NANOS_PER_SEC as u64 )
9951001 . 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
9971003 }
9981004 } ;
9991005 }
10001006 total_secs = total_secs
10011007 . checked_add( total_nanos / NANOS_PER_SEC as u64 )
10021008 . expect( "overflow in iter::sum over durations" ) ;
10031009 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 )
10051011 } } ;
10061012}
10071013
@@ -1166,27 +1172,27 @@ impl fmt::Debug for Duration {
11661172 let prefix = if f. sign_plus ( ) { "+" } else { "" } ;
11671173
11681174 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 {
11711177 fmt_decimal (
11721178 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 ,
11751181 NANOS_PER_MILLI / 10 ,
11761182 prefix,
11771183 "ms" ,
11781184 )
1179- } else if self . nanos >= NANOS_PER_MICRO {
1185+ } else if self . nanos . 0 >= NANOS_PER_MICRO {
11801186 fmt_decimal (
11811187 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 ,
11841190 NANOS_PER_MICRO / 10 ,
11851191 prefix,
11861192 "µs" ,
11871193 )
11881194 } 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" )
11901196 }
11911197 }
11921198}
@@ -1317,7 +1323,7 @@ macro_rules! try_from_secs {
13171323 return Err ( FromFloatSecsError { kind: FromFloatSecsErrorKind :: OverflowOrNan } ) ;
13181324 } ;
13191325
1320- Ok ( Duration { secs, nanos } )
1326+ Ok ( Duration :: new ( secs, nanos) )
13211327 } } ;
13221328}
13231329
0 commit comments