about summary refs log tree commit diff
diff options
context:
space:
mode:
authorStuart Cook <Zalathar@users.noreply.github.com>2025-08-30 20:29:08 +1000
committerGitHub <noreply@github.com>2025-08-30 20:29:08 +1000
commitf655e6a863c0bd3ffd74468939b3819001624f4d (patch)
treeacef1a03320b28652754613b1f31b065b2669aed
parentdfbba07012ac533ad4dd1f770347cfd547b7eb8c (diff)
parent8134a10ec76e7c357d207ea83b215a15af63519c (diff)
downloadrust-f655e6a863c0bd3ffd74468939b3819001624f4d.tar.gz
rust-f655e6a863c0bd3ffd74468939b3819001624f4d.zip
Rollup merge of #145969 - actuallylost:duration-from-nanos-128, r=tgross35
Add Duration::from_nanos_u128

Feature Gate: `#![feature(duration_from_nanos_u128)]`
ACP: https://github.com/rust-lang/libs-team/issues/567
Tracking issue: https://github.com/rust-lang/rust/issues/139201
Recreated from https://github.com/rust-lang/rust/pull/139243
-rw-r--r--library/core/src/time.rs36
-rw-r--r--library/coretests/tests/lib.rs1
-rw-r--r--library/coretests/tests/time.rs19
3 files changed, 56 insertions, 0 deletions
diff --git a/library/core/src/time.rs b/library/core/src/time.rs
index f37e47f132d..d205bc376f1 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -308,6 +308,42 @@ impl Duration {
         Duration { secs, nanos: subsec_nanos }
     }
 
+    /// Creates a new `Duration` from the specified number of nanoseconds.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the given number of nanoseconds is greater than [`Duration::MAX`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(duration_from_nanos_u128)]
+    /// use std::time::Duration;
+    ///
+    /// let nanos = 10_u128.pow(24) + 321;
+    /// let duration = Duration::from_nanos_u128(nanos);
+    ///
+    /// assert_eq!(10_u64.pow(15), duration.as_secs());
+    /// assert_eq!(321, duration.subsec_nanos());
+    /// ```
+    #[unstable(feature = "duration_from_nanos_u128", issue = "139201")]
+    // This is necessary because of const `try_from`, but can be removed if a trait-free impl is used instead
+    #[rustc_const_unstable(feature = "duration_from_nanos_u128", issue = "139201")]
+    #[must_use]
+    #[inline]
+    #[track_caller]
+    pub const fn from_nanos_u128(nanos: u128) -> Duration {
+        const NANOS_PER_SEC: u128 = self::NANOS_PER_SEC as u128;
+        let Ok(secs) = u64::try_from(nanos / NANOS_PER_SEC) else {
+            panic!("overflow in `Duration::from_nanos_u128`");
+        };
+        let subsec_nanos = (nanos % NANOS_PER_SEC) as u32;
+        // SAFETY: x % 1_000_000_000 < 1_000_000_000 also, subsec_nanos >= 0 since u128 >=0 and u32 >=0
+        let subsec_nanos = unsafe { Nanoseconds::new_unchecked(subsec_nanos) };
+
+        Duration { secs: secs as u64, nanos: subsec_nanos }
+    }
+
     /// Creates a new `Duration` from the specified number of weeks.
     ///
     /// # Panics
diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs
index a260c4743d7..bf0a3ae7870 100644
--- a/library/coretests/tests/lib.rs
+++ b/library/coretests/tests/lib.rs
@@ -36,6 +36,7 @@
 #![feature(drop_guard)]
 #![feature(duration_constants)]
 #![feature(duration_constructors)]
+#![feature(duration_from_nanos_u128)]
 #![feature(error_generic_member_access)]
 #![feature(exact_div)]
 #![feature(exact_size_is_empty)]
diff --git a/library/coretests/tests/time.rs b/library/coretests/tests/time.rs
index bb98e59bf5a..fb3c50f9bde 100644
--- a/library/coretests/tests/time.rs
+++ b/library/coretests/tests/time.rs
@@ -46,6 +46,14 @@ fn from_weeks_overflow() {
 }
 
 #[test]
+#[should_panic]
+fn from_nanos_u128_overflow() {
+    let nanos_per_sec: u128 = 1_000_000_000;
+    let overflow = (u64::MAX as u128 * nanos_per_sec) + (nanos_per_sec - 1) + 1;
+    let _ = Duration::from_nanos_u128(overflow);
+}
+
+#[test]
 fn constructor_weeks() {
     assert_eq!(Duration::from_weeks(1), Duration::from_secs(7 * 24 * 60 * 60));
     assert_eq!(Duration::from_weeks(0), Duration::ZERO);
@@ -81,6 +89,8 @@ fn secs() {
     assert_eq!(Duration::from_micros(1_000_001).as_secs(), 1);
     assert_eq!(Duration::from_nanos(999_999_999).as_secs(), 0);
     assert_eq!(Duration::from_nanos(1_000_000_001).as_secs(), 1);
+    assert_eq!(Duration::from_nanos_u128(999_999_999).as_secs(), 0);
+    assert_eq!(Duration::from_nanos_u128(1_000_000_001).as_secs(), 1);
 }
 
 #[test]
@@ -95,6 +105,8 @@ fn millis() {
     assert_eq!(Duration::from_micros(1_001_000).subsec_millis(), 1);
     assert_eq!(Duration::from_nanos(999_999_999).subsec_millis(), 999);
     assert_eq!(Duration::from_nanos(1_001_000_000).subsec_millis(), 1);
+    assert_eq!(Duration::from_nanos_u128(999_999_999).subsec_millis(), 999);
+    assert_eq!(Duration::from_nanos_u128(1_001_000_001).subsec_millis(), 1);
 }
 
 #[test]
@@ -109,6 +121,8 @@ fn micros() {
     assert_eq!(Duration::from_micros(1_000_001).subsec_micros(), 1);
     assert_eq!(Duration::from_nanos(999_999_999).subsec_micros(), 999_999);
     assert_eq!(Duration::from_nanos(1_000_001_000).subsec_micros(), 1);
+    assert_eq!(Duration::from_nanos_u128(999_999_999).subsec_micros(), 999_999);
+    assert_eq!(Duration::from_nanos_u128(1_000_001_000).subsec_micros(), 1);
 }
 
 #[test]
@@ -123,6 +137,8 @@ fn nanos() {
     assert_eq!(Duration::from_micros(1_000_001).subsec_nanos(), 1000);
     assert_eq!(Duration::from_nanos(999_999_999).subsec_nanos(), 999_999_999);
     assert_eq!(Duration::from_nanos(1_000_000_001).subsec_nanos(), 1);
+    assert_eq!(Duration::from_nanos_u128(999_999_999).subsec_nanos(), 999_999_999);
+    assert_eq!(Duration::from_nanos_u128(1_000_000_001).subsec_nanos(), 1);
 }
 
 #[test]
@@ -520,6 +536,9 @@ fn duration_const() {
     const FROM_NANOS: Duration = Duration::from_nanos(1_000_000_000);
     assert_eq!(FROM_NANOS, Duration::SECOND);
 
+    const FROM_NANOS_U128: Duration = Duration::from_nanos_u128(NANOS);
+    assert_eq!(FROM_NANOS_U128, Duration::SECOND);
+
     const MAX: Duration = Duration::new(u64::MAX, 999_999_999);
 
     const CHECKED_ADD: Option<Duration> = MAX.checked_add(Duration::SECOND);