Repository: rust-lang/rust
Pull request: Use common Timestamp impl in Hermit (attempt 2)

The goal is to have less code to maintain, so to be able to make changes easier.

Previous attempt https://github.com/rust-lang/rust/pull/148847 was asked to postpone because there was restructure of code, which is complete now.

r? joboet

Changed files:
filename: library/std/src/sys/fs/hermit.rs
patch: @@ -109,15 +109,15 @@ pub struct DirBuilder {
 
 impl FileAttr {
     pub fn modified(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::new(self.stat_val.st_mtim.tv_sec, self.stat_val.st_mtim.tv_nsec))
+        SystemTime::new(self.stat_val.st_mtim.tv_sec, self.stat_val.st_mtim.tv_nsec.into())
     }
 
     pub fn accessed(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::new(self.stat_val.st_atim.tv_sec, self.stat_val.st_atim.tv_nsec))
+        SystemTime::new(self.stat_val.st_atim.tv_sec, self.stat_val.st_atim.tv_nsec.into())
     }
 
     pub fn created(&self) -> io::Result<SystemTime> {
-        Ok(SystemTime::new(self.stat_val.st_ctim.tv_sec, self.stat_val.st_ctim.tv_nsec))
+        SystemTime::new(self.stat_val.st_ctim.tv_sec, self.stat_val.st_ctim.tv_nsec.into())
     }
 
     pub fn size(&self) -> u64 {

filename: library/std/src/sys/pal/hermit/mod.rs
patch: @@ -22,6 +22,7 @@ use crate::os::raw::c_char;
 use crate::sys::env;
 
 pub mod futex;
+#[path = "../unix/time.rs"]
 pub mod time;
 
 pub fn unsupported<T>() -> io::Result<T> {

filename: library/std/src/sys/pal/hermit/time.rs
patch: @@ -1,110 +0,0 @@
-use hermit_abi::{self, timespec};
-
-use crate::cmp::Ordering;
-use crate::hash::{Hash, Hasher};
-use crate::time::Duration;
-
-const NSEC_PER_SEC: i32 = 1_000_000_000;
-
-#[derive(Copy, Clone, Debug)]
-pub struct Timespec {
-    pub t: timespec,
-}
-
-impl Timespec {
-    pub const MAX: Timespec = Self::new(i64::MAX, 1_000_000_000 - 1);
-
-    pub const MIN: Timespec = Self::new(i64::MIN, 0);
-
-    pub const fn zero() -> Timespec {
-        Timespec { t: timespec { tv_sec: 0, tv_nsec: 0 } }
-    }
-
-    pub const fn new(tv_sec: i64, tv_nsec: i32) -> Timespec {
-        assert!(tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC);
-        // SAFETY: The assert above checks tv_nsec is within the valid range
-        Timespec { t: timespec { tv_sec, tv_nsec } }
-    }
-
-    pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
-        fn sub_ge_to_unsigned(a: i64, b: i64) -> u64 {
-            debug_assert!(a >= b);
-            a.wrapping_sub(b).cast_unsigned()
-        }
-
-        if self >= other {
-            // Logic here is identical to Unix version of `Timestamp::sub_timespec`,
-            // check comments there why operations do not overflow.
-            Ok(if self.t.tv_nsec >= other.t.tv_nsec {
-                Duration::new(
-                    sub_ge_to_unsigned(self.t.tv_sec, other.t.tv_sec),
-                    (self.t.tv_nsec - other.t.tv_nsec) as u32,
-                )
-            } else {
-                Duration::new(
-                    sub_ge_to_unsigned(self.t.tv_sec - 1, other.t.tv_sec),
-                    (self.t.tv_nsec + NSEC_PER_SEC - other.t.tv_nsec) as u32,
-                )
-            })
-        } else {
-            match other.sub_timespec(self) {
-                Ok(d) => Err(d),
-                Err(d) => Ok(d),
-            }
-        }
-    }
-
-    pub 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();
-            secs = secs.checked_add(1)?;
-        }
-        Some(Timespec { t: timespec { tv_sec: secs, tv_nsec: nsec as _ } })
-    }
-
-    pub 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.
-        let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
-        if nsec < 0 {
-            nsec += NSEC_PER_SEC as i32;
-            secs = secs.checked_sub(1)?;
-        }
-        Some(Timespec { t: timespec { tv_sec: secs, tv_nsec: nsec as _ } })
-    }
-}
-
-impl PartialEq for Timespec {
-    fn eq(&self, other: &Timespec) -> bool {
-        self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec
-    }
-}
-
-impl Eq for Timespec {}
-
-impl PartialOrd for Timespec {
-    fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-impl Ord for Timespec {
-    fn cmp(&self, other: &Timespec) -> Ordering {
-        let me = (self.t.tv_sec, self.t.tv_nsec);
-        let other = (other.t.tv_sec, other.t.tv_nsec);
-        me.cmp(&other)
-    }
-}
-
-impl Hash for Timespec {
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        self.t.tv_sec.hash(state);
-        self.t.tv_nsec.hash(state);
-    }
-}

filename: library/std/src/sys/pal/unix/time.rs
patch: @@ -17,7 +17,7 @@ pub(in crate::sys) const TIMESPEC_MAX_CAPPED: libc::timespec = libc::timespec {
     tv_nsec: (u64::MAX % NSEC_PER_SEC) as i64,
 };
 
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
 pub(crate) struct Timespec {
     pub tv_sec: i64,
     pub tv_nsec: Nanoseconds,
@@ -66,6 +66,7 @@ impl Timespec {
         }
     }
 
+    #[allow(dead_code)]
     pub fn now(clock: libc::clockid_t) -> Timespec {
         use crate::mem::MaybeUninit;
         use crate::sys::cvt;

filename: library/std/src/sys/time/hermit.rs
patch: @@ -1,18 +1,21 @@
 use hermit_abi::{self, CLOCK_MONOTONIC, CLOCK_REALTIME};
 
-use crate::hash::Hash;
+use crate::io;
 use crate::sys::pal::time::Timespec;
 use crate::time::Duration;
 
+fn clock_gettime(clock: hermit_abi::clockid_t) -> Timespec {
+    let mut t = hermit_abi::timespec { tv_sec: 0, tv_nsec: 0 };
+    let _ = unsafe { hermit_abi::clock_gettime(clock, &raw mut t) };
+    Timespec::new(t.tv_sec, t.tv_nsec.into()).unwrap()
+}
+
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
 pub struct Instant(Timespec);
 
 impl Instant {
     pub fn now() -> Instant {
-        let mut time: Timespec = Timespec::zero();
-        let _ = unsafe { hermit_abi::clock_gettime(CLOCK_MONOTONIC, &raw mut time.t) };
-
-        Instant(time)
+        Instant(clock_gettime(CLOCK_MONOTONIC))
     }
 
     pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
@@ -38,15 +41,12 @@ impl SystemTime {
 
     pub const MIN: SystemTime = SystemTime(Timespec::MIN);
 
-    pub fn new(tv_sec: i64, tv_nsec: i32) -> SystemTime {
-        SystemTime(Timespec::new(tv_sec, tv_nsec))
+    pub fn new(tv_sec: i64, tv_nsec: i64) -> Result<SystemTime, io::Error> {
+        Ok(SystemTime(Timespec::new(tv_sec, tv_nsec)?))
     }
 
     pub fn now() -> SystemTime {
-        let mut time: Timespec = Timespec::zero();
-        let _ = unsafe { hermit_abi::clock_gettime(CLOCK_REALTIME, &raw mut time.t) };
-
-        SystemTime(time)
+        SystemTime(clock_gettime(CLOCK_REALTIME))
     }
 
     pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {