xref: /drstd/src/std/sys/hermit/time.rs (revision 9670759b785600bf6315e4173e46a602f16add7a)
1 #![allow(dead_code)]
2 
3 use crate::std::cmp::Ordering;
4 use crate::std::ops::{Add, AddAssign, Sub, SubAssign};
5 use crate::std::sys::hermit::abi;
6 use crate::std::sys::hermit::abi::timespec;
7 use crate::std::sys::hermit::abi::{CLOCK_MONOTONIC, CLOCK_REALTIME, NSEC_PER_SEC};
8 use crate::std::time::Duration;
9 use core::hash::{Hash, Hasher};
10 
11 #[derive(Copy, Clone, Debug)]
12 struct Timespec {
13     t: timespec,
14 }
15 
16 impl Timespec {
zero() -> Timespec17     const fn zero() -> Timespec {
18         Timespec {
19             t: timespec {
20                 tv_sec: 0,
21                 tv_nsec: 0,
22             },
23         }
24     }
25 
sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration>26     fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
27         if self >= other {
28             Ok(if self.t.tv_nsec >= other.t.tv_nsec {
29                 Duration::new(
30                     (self.t.tv_sec - other.t.tv_sec) as u64,
31                     (self.t.tv_nsec - other.t.tv_nsec) as u32,
32                 )
33             } else {
34                 Duration::new(
35                     (self.t.tv_sec - 1 - other.t.tv_sec) as u64,
36                     self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - other.t.tv_nsec as u32,
37                 )
38             })
39         } else {
40             match other.sub_timespec(self) {
41                 Ok(d) => Err(d),
42                 Err(d) => Ok(d),
43             }
44         }
45     }
46 
checked_add_duration(&self, other: &Duration) -> Option<Timespec>47     fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
48         let mut secs = self.t.tv_sec.checked_add_unsigned(other.as_secs())?;
49 
50         // Nano calculations can't overflow because nanos are <1B which fit
51         // in a u32.
52         let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
53         if nsec >= NSEC_PER_SEC as u32 {
54             nsec -= NSEC_PER_SEC as u32;
55             secs = secs.checked_add(1)?;
56         }
57         Some(Timespec {
58             t: timespec {
59                 tv_sec: secs,
60                 tv_nsec: nsec as _,
61             },
62         })
63     }
64 
checked_sub_duration(&self, other: &Duration) -> Option<Timespec>65     fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
66         let mut secs = self.t.tv_sec.checked_sub_unsigned(other.as_secs())?;
67 
68         // Similar to above, nanos can't overflow.
69         let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
70         if nsec < 0 {
71             nsec += NSEC_PER_SEC as i32;
72             secs = secs.checked_sub(1)?;
73         }
74         Some(Timespec {
75             t: timespec {
76                 tv_sec: secs,
77                 tv_nsec: nsec as _,
78             },
79         })
80     }
81 }
82 
83 impl PartialEq for Timespec {
eq(&self, other: &Timespec) -> bool84     fn eq(&self, other: &Timespec) -> bool {
85         self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec
86     }
87 }
88 
89 impl Eq for Timespec {}
90 
91 impl PartialOrd for Timespec {
partial_cmp(&self, other: &Timespec) -> Option<Ordering>92     fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> {
93         Some(self.cmp(other))
94     }
95 }
96 
97 impl Ord for Timespec {
cmp(&self, other: &Timespec) -> Ordering98     fn cmp(&self, other: &Timespec) -> Ordering {
99         let me = (self.t.tv_sec, self.t.tv_nsec);
100         let other = (other.t.tv_sec, other.t.tv_nsec);
101         me.cmp(&other)
102     }
103 }
104 
105 impl Hash for Timespec {
hash<H: Hasher>(&self, state: &mut H)106     fn hash<H: Hasher>(&self, state: &mut H) {
107         self.t.tv_sec.hash(state);
108         self.t.tv_nsec.hash(state);
109     }
110 }
111 
112 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
113 pub struct Instant(Timespec);
114 
115 impl Instant {
now() -> Instant116     pub fn now() -> Instant {
117         let mut time: Timespec = Timespec::zero();
118         let _ = unsafe { abi::clock_gettime(CLOCK_MONOTONIC, &mut time.t as *mut timespec) };
119 
120         Instant(time)
121     }
122 
elapsed(&self) -> Duration123     pub fn elapsed(&self) -> Duration {
124         Instant::now() - *self
125     }
126 
duration_since(&self, earlier: Instant) -> Duration127     pub fn duration_since(&self, earlier: Instant) -> Duration {
128         self.checked_duration_since(earlier).unwrap_or_default()
129     }
130 
checked_duration_since(&self, earlier: Instant) -> Option<Duration>131     pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
132         self.checked_sub_instant(&earlier)
133     }
134 
checked_sub_instant(&self, other: &Instant) -> Option<Duration>135     pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
136         self.0.sub_timespec(&other.0).ok()
137     }
138 
checked_add_duration(&self, other: &Duration) -> Option<Instant>139     pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
140         Some(Instant(self.0.checked_add_duration(other)?))
141     }
142 
checked_sub_duration(&self, other: &Duration) -> Option<Instant>143     pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
144         Some(Instant(self.0.checked_sub_duration(other)?))
145     }
146 
checked_add(&self, duration: Duration) -> Option<Instant>147     pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
148         self.0.checked_add_duration(&duration).map(Instant)
149     }
150 
checked_sub(&self, duration: Duration) -> Option<Instant>151     pub fn checked_sub(&self, duration: Duration) -> Option<Instant> {
152         self.0.checked_sub_duration(&duration).map(Instant)
153     }
154 }
155 
156 impl Add<Duration> for Instant {
157     type Output = Instant;
158 
159     /// # Panics
160     ///
161     /// This function may panic if the resulting point in time cannot be represented by the
162     /// underlying data structure. See [`Instant::checked_add`] for a version without panic.
add(self, other: Duration) -> Instant163     fn add(self, other: Duration) -> Instant {
164         self.checked_add(other)
165             .expect("overflow when adding duration to instant")
166     }
167 }
168 
169 impl AddAssign<Duration> for Instant {
add_assign(&mut self, other: Duration)170     fn add_assign(&mut self, other: Duration) {
171         *self = *self + other;
172     }
173 }
174 
175 impl Sub<Duration> for Instant {
176     type Output = Instant;
177 
sub(self, other: Duration) -> Instant178     fn sub(self, other: Duration) -> Instant {
179         self.checked_sub(other)
180             .expect("overflow when subtracting duration from instant")
181     }
182 }
183 
184 impl SubAssign<Duration> for Instant {
sub_assign(&mut self, other: Duration)185     fn sub_assign(&mut self, other: Duration) {
186         *self = *self - other;
187     }
188 }
189 
190 impl Sub<Instant> for Instant {
191     type Output = Duration;
192 
193     /// Returns the amount of time elapsed from another instant to this one,
194     /// or zero duration if that instant is later than this one.
195     ///
196     /// # Panics
197     ///
198     /// Previous rust versions panicked when `other` was later than `self`. Currently this
199     /// method saturates. Future versions may reintroduce the panic in some circumstances.
200     /// See [Monotonicity].
201     ///
202     /// [Monotonicity]: Instant#monotonicity
sub(self, other: Instant) -> Duration203     fn sub(self, other: Instant) -> Duration {
204         self.duration_since(other)
205     }
206 }
207 
208 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
209 pub struct SystemTime(Timespec);
210 
211 pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero());
212 
213 impl SystemTime {
now() -> SystemTime214     pub fn now() -> SystemTime {
215         let mut time: Timespec = Timespec::zero();
216         let _ = unsafe { abi::clock_gettime(CLOCK_REALTIME, &mut time.t as *mut timespec) };
217 
218         SystemTime(time)
219     }
220 
sub_time(&self, other: &SystemTime) -> Result<Duration, Duration>221     pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
222         self.0.sub_timespec(&other.0)
223     }
224 
checked_add_duration(&self, other: &Duration) -> Option<SystemTime>225     pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
226         Some(SystemTime(self.0.checked_add_duration(other)?))
227     }
228 
checked_sub_duration(&self, other: &Duration) -> Option<SystemTime>229     pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
230         Some(SystemTime(self.0.checked_sub_duration(other)?))
231     }
232 }
233