1use crate::sys::AsInner;
2use crate::sys::pal::time::Timespec;
3use crate::time::Duration;
4use crate::{fmt, io};
5
6pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
7
8#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
9pub struct SystemTime {
10 pub(crate) t: Timespec,
11}
12
13impl SystemTime {
14 pub const MAX: SystemTime = SystemTime { t: Timespec::MAX };
15
16 pub const MIN: SystemTime = SystemTime { t: Timespec::MIN };
17
18 #[cfg_attr(any(target_os = "horizon", target_os = "hurd", target_os = "teeos"), expect(unused))]
19 pub fn new(tv_sec: i64, tv_nsec: i64) -> Result<SystemTime, io::Error> {
20 Ok(SystemTime { t: Timespec::new(tv_sec, tv_nsec)? })
21 }
22
23 pub fn now() -> SystemTime {
24 SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) }
25 }
26
27 pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
28 self.t.sub_timespec(&other.t)
29 }
30
31 pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
32 Some(SystemTime { t: self.t.checked_add_duration(other)? })
33 }
34
35 pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
36 Some(SystemTime { t: self.t.checked_sub_duration(other)? })
37 }
38}
39
40impl fmt::Debug for SystemTime {
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 f.debug_struct("SystemTime")
43 .field("tv_sec", &self.t.tv_sec)
44 .field("tv_nsec", &self.t.tv_nsec)
45 .finish()
46 }
47}
48
49#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
50pub struct Instant {
51 t: Timespec,
52}
53
54impl Instant {
55 #[cfg(target_vendor = "apple")]
67 pub(crate) const CLOCK_ID: libc::clockid_t = libc::CLOCK_UPTIME_RAW;
68
69 #[cfg(not(target_vendor = "apple"))]
70 pub(crate) const CLOCK_ID: libc::clockid_t = libc::CLOCK_MONOTONIC;
71
72 pub fn now() -> Instant {
73 Instant { t: Timespec::now(Self::CLOCK_ID) }
75 }
76
77 pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
78 self.t.sub_timespec(&other.t).ok()
79 }
80
81 pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
82 Some(Instant { t: self.t.checked_add_duration(other)? })
83 }
84
85 pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
86 Some(Instant { t: self.t.checked_sub_duration(other)? })
87 }
88
89 #[cfg_attr(
90 not(target_os = "linux"),
91 allow(unused, reason = "needed by the `sleep_until` on some unix platforms")
92 )]
93 pub(crate) fn into_timespec(self) -> Timespec {
94 self.t
95 }
96
97 #[cfg(target_vendor = "apple")]
102 pub fn into_mach_absolute_time_ceil(self) -> Option<u128> {
103 #[repr(C)]
104 struct mach_timebase_info {
105 numer: u32,
106 denom: u32,
107 }
108
109 unsafe extern "C" {
110 unsafe fn mach_timebase_info(info: *mut mach_timebase_info) -> libc::kern_return_t;
111 }
112
113 let secs = u64::try_from(self.t.tv_sec).ok()?;
114
115 let mut timebase = mach_timebase_info { numer: 0, denom: 0 };
116 assert_eq!(unsafe { mach_timebase_info(&mut timebase) }, libc::KERN_SUCCESS);
117
118 let nanos = 1_000_000_000 * u128::from(secs) + u128::from(self.t.tv_nsec.as_inner());
121 Some((nanos * u128::from(timebase.denom)).div_ceil(u128::from(timebase.numer)))
125 }
126}
127
128impl AsInner<Timespec> for Instant {
129 fn as_inner(&self) -> &Timespec {
130 &self.t
131 }
132}
133
134impl fmt::Debug for Instant {
135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136 f.debug_struct("Instant")
137 .field("tv_sec", &self.t.tv_sec)
138 .field("tv_nsec", &self.t.tv_nsec)
139 .finish()
140 }
141}