Skip to content

Commit 8134a10

Browse files
Add Duration::from_nanos_u128
Tracking issue: RUST-139201 Co-authored-by: omanirudh <[email protected]>
1 parent fe55364 commit 8134a10

File tree

3 files changed

+56
-0
lines changed

3 files changed

+56
-0
lines changed

library/core/src/time.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,42 @@ impl Duration {
308308
Duration { secs, nanos: subsec_nanos }
309309
}
310310

311+
/// Creates a new `Duration` from the specified number of nanoseconds.
312+
///
313+
/// # Panics
314+
///
315+
/// Panics if the given number of nanoseconds is greater than [`Duration::MAX`].
316+
///
317+
/// # Examples
318+
///
319+
/// ```
320+
/// #![feature(duration_from_nanos_u128)]
321+
/// use std::time::Duration;
322+
///
323+
/// let nanos = 10_u128.pow(24) + 321;
324+
/// let duration = Duration::from_nanos_u128(nanos);
325+
///
326+
/// assert_eq!(10_u64.pow(15), duration.as_secs());
327+
/// assert_eq!(321, duration.subsec_nanos());
328+
/// ```
329+
#[unstable(feature = "duration_from_nanos_u128", issue = "139201")]
330+
// This is necessary because of const `try_from`, but can be removed if a trait-free impl is used instead
331+
#[rustc_const_unstable(feature = "duration_from_nanos_u128", issue = "139201")]
332+
#[must_use]
333+
#[inline]
334+
#[track_caller]
335+
pub const fn from_nanos_u128(nanos: u128) -> Duration {
336+
const NANOS_PER_SEC: u128 = self::NANOS_PER_SEC as u128;
337+
let Ok(secs) = u64::try_from(nanos / NANOS_PER_SEC) else {
338+
panic!("overflow in `Duration::from_nanos_u128`");
339+
};
340+
let subsec_nanos = (nanos % NANOS_PER_SEC) as u32;
341+
// SAFETY: x % 1_000_000_000 < 1_000_000_000 also, subsec_nanos >= 0 since u128 >=0 and u32 >=0
342+
let subsec_nanos = unsafe { Nanoseconds::new_unchecked(subsec_nanos) };
343+
344+
Duration { secs: secs as u64, nanos: subsec_nanos }
345+
}
346+
311347
/// Creates a new `Duration` from the specified number of weeks.
312348
///
313349
/// # Panics

library/coretests/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#![feature(drop_guard)]
3737
#![feature(duration_constants)]
3838
#![feature(duration_constructors)]
39+
#![feature(duration_from_nanos_u128)]
3940
#![feature(error_generic_member_access)]
4041
#![feature(exact_div)]
4142
#![feature(exact_size_is_empty)]

library/coretests/tests/time.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ fn from_weeks_overflow() {
4545
let _ = Duration::from_weeks(overflow);
4646
}
4747

48+
#[test]
49+
#[should_panic]
50+
fn from_nanos_u128_overflow() {
51+
let nanos_per_sec: u128 = 1_000_000_000;
52+
let overflow = (u64::MAX as u128 * nanos_per_sec) + (nanos_per_sec - 1) + 1;
53+
let _ = Duration::from_nanos_u128(overflow);
54+
}
55+
4856
#[test]
4957
fn constructor_weeks() {
5058
assert_eq!(Duration::from_weeks(1), Duration::from_secs(7 * 24 * 60 * 60));
@@ -81,6 +89,8 @@ fn secs() {
8189
assert_eq!(Duration::from_micros(1_000_001).as_secs(), 1);
8290
assert_eq!(Duration::from_nanos(999_999_999).as_secs(), 0);
8391
assert_eq!(Duration::from_nanos(1_000_000_001).as_secs(), 1);
92+
assert_eq!(Duration::from_nanos_u128(999_999_999).as_secs(), 0);
93+
assert_eq!(Duration::from_nanos_u128(1_000_000_001).as_secs(), 1);
8494
}
8595

8696
#[test]
@@ -95,6 +105,8 @@ fn millis() {
95105
assert_eq!(Duration::from_micros(1_001_000).subsec_millis(), 1);
96106
assert_eq!(Duration::from_nanos(999_999_999).subsec_millis(), 999);
97107
assert_eq!(Duration::from_nanos(1_001_000_000).subsec_millis(), 1);
108+
assert_eq!(Duration::from_nanos_u128(999_999_999).subsec_millis(), 999);
109+
assert_eq!(Duration::from_nanos_u128(1_001_000_001).subsec_millis(), 1);
98110
}
99111

100112
#[test]
@@ -109,6 +121,8 @@ fn micros() {
109121
assert_eq!(Duration::from_micros(1_000_001).subsec_micros(), 1);
110122
assert_eq!(Duration::from_nanos(999_999_999).subsec_micros(), 999_999);
111123
assert_eq!(Duration::from_nanos(1_000_001_000).subsec_micros(), 1);
124+
assert_eq!(Duration::from_nanos_u128(999_999_999).subsec_micros(), 999_999);
125+
assert_eq!(Duration::from_nanos_u128(1_000_001_000).subsec_micros(), 1);
112126
}
113127

114128
#[test]
@@ -123,6 +137,8 @@ fn nanos() {
123137
assert_eq!(Duration::from_micros(1_000_001).subsec_nanos(), 1000);
124138
assert_eq!(Duration::from_nanos(999_999_999).subsec_nanos(), 999_999_999);
125139
assert_eq!(Duration::from_nanos(1_000_000_001).subsec_nanos(), 1);
140+
assert_eq!(Duration::from_nanos_u128(999_999_999).subsec_nanos(), 999_999_999);
141+
assert_eq!(Duration::from_nanos_u128(1_000_000_001).subsec_nanos(), 1);
126142
}
127143

128144
#[test]
@@ -520,6 +536,9 @@ fn duration_const() {
520536
const FROM_NANOS: Duration = Duration::from_nanos(1_000_000_000);
521537
assert_eq!(FROM_NANOS, Duration::SECOND);
522538

539+
const FROM_NANOS_U128: Duration = Duration::from_nanos_u128(NANOS);
540+
assert_eq!(FROM_NANOS_U128, Duration::SECOND);
541+
523542
const MAX: Duration = Duration::new(u64::MAX, 999_999_999);
524543

525544
const CHECKED_ADD: Option<Duration> = MAX.checked_add(Duration::SECOND);

0 commit comments

Comments
 (0)