clocksource/precise/
unix_instant.rs1use core::ops::{Add, AddAssign, Sub, SubAssign};
2
3use super::Duration;
4
5#[repr(transparent)]
26#[derive(Copy, Clone, Default, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
27pub struct UnixInstant {
28 pub(crate) ns: u64,
29}
30
31impl UnixInstant {
32 pub const EPOCH: UnixInstant = UnixInstant { ns: 0 };
35
36 pub const fn from_nanos(ns: u64) -> Self {
39 Self { ns }
40 }
41
42 pub const fn as_nanos(&self) -> u64 {
44 self.ns
45 }
46
47 pub fn now() -> Self {
49 crate::sys::realtime::precise()
50 }
51
52 pub fn elapsed(&self) -> Duration {
54 Self::now() - *self
55 }
56
57 pub fn duration_since(&self, earlier: Self) -> Duration {
60 *self - earlier
61 }
62
63 pub fn checked_duration_since(&self, earlier: Self) -> Option<Duration> {
65 self.ns.checked_sub(earlier.ns).map(|ns| Duration { ns })
66 }
67
68 pub fn checked_sub(&self, duration: Duration) -> Option<Self> {
70 self.ns.checked_sub(duration.ns).map(|ns| Self { ns })
71 }
72
73 pub const fn as_secs(&self) -> u64 {
75 self.ns / 1_000_000_000
76 }
77
78 pub fn checked_add(&self, duration: Duration) -> Option<Self> {
80 self.ns
81 .checked_add(duration.as_nanos())
82 .map(|ns| Self { ns })
83 }
84}
85
86impl Add<Duration> for UnixInstant {
87 type Output = UnixInstant;
88
89 fn add(self, rhs: Duration) -> Self::Output {
90 UnixInstant {
91 ns: self.ns + rhs.ns,
92 }
93 }
94}
95
96impl Add<core::time::Duration> for UnixInstant {
97 type Output = UnixInstant;
98
99 fn add(self, rhs: core::time::Duration) -> Self::Output {
100 UnixInstant {
101 ns: self.ns + rhs.as_nanos() as u64,
102 }
103 }
104}
105
106impl Sub<UnixInstant> for UnixInstant {
107 type Output = Duration;
108
109 fn sub(self, rhs: UnixInstant) -> Self::Output {
110 Duration {
111 ns: self.ns - rhs.ns,
112 }
113 }
114}
115
116impl AddAssign<Duration> for UnixInstant {
117 fn add_assign(&mut self, rhs: Duration) {
118 self.ns += rhs.ns;
119 }
120}
121
122impl Sub<Duration> for UnixInstant {
123 type Output = UnixInstant;
124
125 fn sub(self, rhs: Duration) -> Self::Output {
126 UnixInstant {
127 ns: self.ns - rhs.ns,
128 }
129 }
130}
131
132impl SubAssign<Duration> for UnixInstant {
133 fn sub_assign(&mut self, rhs: Duration) {
134 self.ns -= rhs.ns;
135 }
136}
137
138impl AddAssign<core::time::Duration> for UnixInstant {
139 fn add_assign(&mut self, rhs: core::time::Duration) {
140 self.ns += rhs.as_nanos() as u64;
141 }
142}
143
144impl Sub<core::time::Duration> for UnixInstant {
145 type Output = UnixInstant;
146
147 fn sub(self, rhs: core::time::Duration) -> Self::Output {
148 UnixInstant {
149 ns: self.ns - rhs.as_nanos() as u64,
150 }
151 }
152}
153
154impl SubAssign<core::time::Duration> for UnixInstant {
155 fn sub_assign(&mut self, rhs: core::time::Duration) {
156 self.ns -= rhs.as_nanos() as u64;
157 }
158}
159
160impl From<crate::coarse::UnixInstant> for UnixInstant {
161 fn from(other: crate::coarse::UnixInstant) -> Self {
162 Self {
163 ns: other.secs as u64 * super::Duration::SECOND.as_nanos(),
164 }
165 }
166}
167
168#[derive(Debug)]
169pub struct TryFromError {
170 kind: TryFromErrorKind,
171}
172
173#[derive(Debug)]
174enum TryFromErrorKind {
175 Overflow,
176 BeforeEpoch,
177}
178
179impl TryFromError {
180 const fn description(&self) -> &'static str {
181 match self.kind {
182 TryFromErrorKind::Overflow => "can not convert to UnixInstant: value is too big",
183 TryFromErrorKind::BeforeEpoch => {
184 "can not convert to UnixInstant: value is before unix epoch"
185 }
186 }
187 }
188}
189
190impl core::fmt::Display for TryFromError {
191 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
192 self.description().fmt(f)
193 }
194}
195
196impl std::error::Error for TryFromError {}
197
198impl TryFrom<std::time::SystemTime> for UnixInstant {
199 type Error = TryFromError;
200
201 fn try_from(other: std::time::SystemTime) -> Result<Self, Self::Error> {
202 let other = other
203 .duration_since(std::time::SystemTime::UNIX_EPOCH)
204 .map_err(|_| TryFromError {
205 kind: TryFromErrorKind::BeforeEpoch,
206 })?
207 .as_nanos();
208 if other > u64::MAX as u128 {
209 Err(TryFromError {
210 kind: TryFromErrorKind::Overflow,
211 })
212 } else {
213 Ok(Self { ns: other as u64 })
214 }
215 }
216}
217
218#[cfg(test)]
219mod tests {
220 #[test]
221 fn from_coarse_unix_instant() {
222 let coarse = crate::coarse::UnixInstant::from_secs(5);
223 let precise = super::UnixInstant::from(coarse);
224 assert_eq!(precise.as_nanos(), 5_000_000_000);
225 }
226}