Skip to content

Commit 8e4869e

Browse files
authored
Rollup merge of #102368 - beetrees:nano-niche, r=joshtriplett
Add a niche to `Duration`, unix `SystemTime`, and non-apple `Instant` As the nanoseconds fields is always between `0` and `(NANOS_PER_SEC - 1)` inclusive, use the `rustc_layout_scalar_valid_range` attributes to create a niche in the nanosecond field of `Duration` and `Timespec` (which is used to implement unix `SystemTime` and non-apple unix `Instant`; windows `Instant` is implemented with `Duration` and therefore will also benefit). This change has the benefit of making `Option<T>` the same size as `T` for the previously mentioned types. Also shrinks the nanoseconds field of `Timespec` to a `u32` as nanoseconds do not need the extra range of an `i64`, shrinking `Timespec` by 4 bytes on 32-bit platforms. r? ```@joshtriplett```
2 parents 19e84b9 + a913277 commit 8e4869e

File tree

3 files changed

+75
-61
lines changed

3 files changed

+75
-61
lines changed

library/core/src/time.rs

+52-46
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,20 @@ const NANOS_PER_MICRO: u32 = 1_000;
2929
const MILLIS_PER_SEC: u64 = 1_000;
3030
const 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")]
7286
pub 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

7791
impl 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

Comments
 (0)