Skip to content

Constify SystemTime methods #144519

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions library/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,9 +281,11 @@
#![feature(cfg_target_thread_local)]
#![feature(cfi_encoding)]
#![feature(char_max_len)]
#![feature(const_trait_impl)]
#![feature(core_float_math)]
#![feature(decl_macro)]
#![feature(deprecated_suggestion)]
#![feature(derive_const)]
#![feature(doc_cfg)]
#![feature(doc_cfg_hide)]
#![feature(doc_masked)]
Expand Down Expand Up @@ -329,6 +331,10 @@
#![feature(bstr_internals)]
#![feature(char_internals)]
#![feature(clone_to_uninit)]
#![feature(const_cmp)]
#![feature(const_ops)]
#![feature(const_option_ops)]
#![feature(const_try)]
#![feature(core_intrinsics)]
#![feature(core_io_borrowed_buf)]
#![feature(drop_guard)]
Expand Down
32 changes: 22 additions & 10 deletions library/std/src/sys/pal/hermit/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,15 @@ impl Timespec {
Timespec { t: timespec { tv_sec, tv_nsec } }
}

fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
if self >= other {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
const fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
// FIXME: const PartialOrd
let mut cmp = self.t.tv_sec - other.t.tv_sec;
if cmp == 0 {
cmp = self.t.tv_nsec as i64 - other.t.tv_nsec as i64;
}

if cmp >= 0 {
Ok(if self.t.tv_nsec >= other.t.tv_nsec {
Duration::new(
(self.t.tv_sec - other.t.tv_sec) as u64,
Expand All @@ -46,20 +53,22 @@ impl Timespec {
}
}

fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
const fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
let mut secs = self.t.tv_sec.checked_add_unsigned(other.as_secs())?;

// Nano calculations can't overflow because nanos are <1B which fit
// in a u32.
let mut nsec = other.subsec_nanos() + u32::try_from(self.t.tv_nsec).unwrap();
if nsec >= NSEC_PER_SEC.try_into().unwrap() {
nsec -= u32::try_from(NSEC_PER_SEC).unwrap();
let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
if nsec >= NSEC_PER_SEC as u32 {
nsec -= NSEC_PER_SEC as u32;
secs = secs.checked_add(1)?;
}
Some(Timespec { t: timespec { tv_sec: secs, tv_nsec: nsec as _ } })
}

fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
const fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
let mut secs = self.t.tv_sec.checked_sub_unsigned(other.as_secs())?;

// Similar to above, nanos can't overflow.
Expand Down Expand Up @@ -213,15 +222,18 @@ impl SystemTime {
SystemTime(time)
}

pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
self.0.sub_timespec(&other.0)
}

pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_add_duration(other)?))
}

pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_sub_duration(other)?))
}
}
15 changes: 11 additions & 4 deletions library/std/src/sys/pal/sgx/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,22 @@ impl SystemTime {
SystemTime(usercalls::insecure_time())
}

pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
// FIXME: ok_or_else with const closures
match self.0.checked_sub(other.0) {
Some(duration) => Ok(duration),
None => Err(other.0 - self.0),
}
}

pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_add(*other)?))
}

pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_sub(*other)?))
}
}
9 changes: 6 additions & 3 deletions library/std/src/sys/pal/solid/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,22 @@ impl SystemTime {
Self(t)
}

pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
if self.0 >= other.0 {
Ok(Duration::from_secs((self.0 as u64).wrapping_sub(other.0 as u64)))
} else {
Err(Duration::from_secs((other.0 as u64).wrapping_sub(self.0 as u64)))
}
}

pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_add_unsigned(other.as_secs())?))
}

pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_sub_unsigned(other.as_secs())?))
}
}
27 changes: 20 additions & 7 deletions library/std/src/sys/pal/uefi/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,32 @@ impl SystemTime {
.unwrap_or_else(|| panic!("time not implemented on this platform"))
}

pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
// FIXME: ok_or_else with const closures
match self.0.checked_sub(other.0) {
Some(duration) => Ok(duration),
None => Err(other.0 - self.0),
}
}

pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
let temp = Self(self.0.checked_add(*other)?);
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
let temp = self.0.checked_add(*other)?;

// Check if can be represented in UEFI
if temp <= MAX_UEFI_TIME { Some(temp) } else { None }
// FIXME: const PartialOrd
let mut cmp = temp.as_secs() - MAX_UEFI_TIME.0.as_secs();
if cmp == 0 {
cmp = temp.subsec_nanos() as u64 - MAX_UEFI_TIME.0.subsec_nanos() as u64;
}

if cmp <= 0 { Some(SystemTime(temp)) } else { None }
}

pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
self.0.checked_sub(*other).map(Self)
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_sub(*other)?))
}
}

Expand Down
30 changes: 21 additions & 9 deletions library/std/src/sys/pal/unix/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,18 @@ impl SystemTime {
SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) }
}

pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
self.t.sub_timespec(&other.t)
}

pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime { t: self.t.checked_add_duration(other)? })
}

pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime { t: self.t.checked_sub_duration(other)? })
}
}
Expand Down Expand Up @@ -133,8 +136,15 @@ impl Timespec {
Timespec::new(t.tv_sec as i64, t.tv_nsec as i64).unwrap()
}

pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
if self >= other {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
// FIXME: const PartialOrd
let mut cmp = self.tv_sec - other.tv_sec;
if cmp == 0 {
cmp = self.tv_nsec.as_inner() as i64 - other.tv_nsec.as_inner() as i64;
}

if cmp >= 0 {
// NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM
// to optimize it into a branchless form (see also #75545):
//
Expand Down Expand Up @@ -169,7 +179,8 @@ impl Timespec {
}
}

pub fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
let mut secs = self.tv_sec.checked_add_unsigned(other.as_secs())?;

// Nano calculations can't overflow because nanos are <1B which fit
Expand All @@ -179,10 +190,11 @@ impl Timespec {
nsec -= NSEC_PER_SEC as u32;
secs = secs.checked_add(1)?;
}
Some(unsafe { Timespec::new_unchecked(secs, nsec.into()) })
Some(unsafe { Timespec::new_unchecked(secs, nsec as i64) })
}

pub fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
let mut secs = self.tv_sec.checked_sub_unsigned(other.as_secs())?;

// Similar to above, nanos can't overflow.
Expand All @@ -191,7 +203,7 @@ impl Timespec {
nsec += NSEC_PER_SEC as i32;
secs = secs.checked_sub(1)?;
}
Some(unsafe { Timespec::new_unchecked(secs, nsec.into()) })
Some(unsafe { Timespec::new_unchecked(secs, nsec as i64) })
}

#[allow(dead_code)]
Expand Down
15 changes: 11 additions & 4 deletions library/std/src/sys/pal/unsupported/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,22 @@ impl SystemTime {
panic!("time not implemented on this platform")
}

pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
// FIXME: ok_or_else with const closures
match self.0.checked_sub(other.0) {
Some(duration) => Ok(duration),
None => Err(other.0 - self.0),
}
}

pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_add(*other)?))
}

pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_sub(*other)?))
}
}
25 changes: 18 additions & 7 deletions library/std/src/sys/pal/wasi/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,23 +43,34 @@ impl SystemTime {
SystemTime(current_time(wasi::CLOCKID_REALTIME))
}

pub fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime {
SystemTime(Duration::from_nanos(ts))
}

pub fn to_wasi_timestamp(&self) -> Option<wasi::Timestamp> {
self.0.as_nanos().try_into().ok()
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn to_wasi_timestamp(&self) -> Option<wasi::Timestamp> {
// FIXME: const TryInto
let ns = self.0.as_nanos();
if ns <= u64::MAX as u128 { Some(ns as u64) } else { None }
}

pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
// FIXME: ok_or_else with const closures
match self.0.checked_sub(other.0) {
Some(duration) => Ok(duration),
None => Err(other.0 - self.0),
}
}

pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_add(*other)?))
}

pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_sub(*other)?))
}
}
30 changes: 19 additions & 11 deletions library/std/src/sys/pal/windows/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ impl SystemTime {
}
}

fn from_intervals(intervals: i64) -> SystemTime {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
const fn from_intervals(intervals: i64) -> SystemTime {
SystemTime {
t: c::FILETIME {
dwLowDateTime: intervals as u32,
Expand All @@ -81,11 +82,13 @@ impl SystemTime {
}
}

fn intervals(&self) -> i64 {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
const fn intervals(&self) -> i64 {
(self.t.dwLowDateTime as i64) | ((self.t.dwHighDateTime as i64) << 32)
}

pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
let me = self.intervals();
let other = other.intervals();
if me >= other {
Expand All @@ -95,12 +98,14 @@ impl SystemTime {
}
}

pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
let intervals = self.intervals().checked_add(checked_dur2intervals(other)?)?;
Some(SystemTime::from_intervals(intervals))
}

pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
let intervals = self.intervals().checked_sub(checked_dur2intervals(other)?)?;
Some(SystemTime::from_intervals(intervals))
}
Expand Down Expand Up @@ -150,15 +155,18 @@ impl Hash for SystemTime {
}
}

fn checked_dur2intervals(dur: &Duration) -> Option<i64> {
dur.as_secs()
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
const fn checked_dur2intervals(dur: &Duration) -> Option<i64> {
// FIXME: const TryInto
let secs = dur
.as_secs()
.checked_mul(INTERVALS_PER_SEC)?
.checked_add(dur.subsec_nanos() as u64 / 100)?
.try_into()
.ok()
.checked_add(dur.subsec_nanos() as u64 / 100)?;
if secs <= i64::MAX as u64 { Some(secs.cast_signed()) } else { None }
}

fn intervals2dur(intervals: u64) -> Duration {
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
const fn intervals2dur(intervals: u64) -> Duration {
Duration::new(intervals / INTERVALS_PER_SEC, ((intervals % INTERVALS_PER_SEC) * 100) as u32)
}

Expand Down
Loading
Loading