1use crate::ffi::{c_int, c_uint, c_ulonglong};
4use core::ops::{Add, Sub, AddAssign, SubAssign};
5use core::cmp::Ordering;
6use core::time::Duration;
7
8use crate::vm_types::integer_t;
9
10pub type alarm_type_t = c_int;
11pub type sleep_type_t = c_int;
12pub type clock_id_t = c_int;
13pub type clock_flavor_t = c_int;
14pub type clock_attr_t = *mut c_int;
15pub type clock_res_t = c_int;
16
17pub const SYSTEM_CLOCK: c_uint = 0;
18pub const CALENDAR_CLOCK: c_uint = 1;
19pub const REALTIME_CLOCK: c_uint = 0;
20
21pub const ALRMTYPE: c_uint = 0xff;
22pub const TIME_ABSOLUTE: c_uint = 0x00;
23pub const TIME_RELATIVE: c_uint = 0x01;
24
25pub const CLOCK_GET_TIME_RES: c_uint = 1;
26pub const CLOCK_ALARM_CURRES: c_uint = 3;
27pub const CLOCK_ALARM_MINRES: c_uint = 4;
28pub const CLOCK_ALARM_MAXRES: c_uint = 5;
29
30
31#[repr(C)]
32#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)]
33pub struct time_value_t {
34 pub seconds: integer_t,
35 pub microseconds: integer_t,
36}
37pub const TIME_MICROS_MAX: integer_t = 1_000_000;
38
39#[repr(C)]
40#[derive(Copy, Clone, Debug, Default, Hash)]
41pub struct mach_timespec_t {
42 pub tv_sec: c_uint,
43 pub tv_nsec: clock_res_t,
44}
45pub const USEC_PER_SEC: c_ulonglong = 1_000_000;
46pub const NSEC_PER_SEC: c_ulonglong = 1_000_000_000;
47pub const NSEC_PER_USEC: c_ulonglong = 1_000;
48pub const NSEC_PER_MSEC: c_ulonglong = 1_000_000;
49pub type mach_timespec = mach_timespec_t;
50
51impl PartialOrd for mach_timespec {
52 fn partial_cmp(&self, other: &mach_timespec) -> Option<Ordering> {
53 Some(mach_timespec::cmp(self, other))
54 }
55}
56impl Ord for mach_timespec {
57 fn cmp(&self, other: &mach_timespec) -> Ordering {
58 mach_timespec::cmp(self, other)
59 }
60}
61
62impl From<mach_timespec> for Duration {
63 fn from(val: mach_timespec) -> Duration {
64 val.to_duration()
65 }
66}
67impl From<&mach_timespec> for Duration {
68 fn from(val: &mach_timespec) -> Duration {
69 val.to_duration()
70 }
71}
72impl From<Duration> for mach_timespec {
73 fn from(val: Duration) -> mach_timespec {
74 mach_timespec::from_duration(val)
75 }
76}
77impl From<&Duration> for mach_timespec {
78 fn from(val: &Duration) -> mach_timespec {
79 mach_timespec::from_duration(*val)
80 }
81}
82
83impl<T> PartialEq<T> for mach_timespec
94where T: Into<Duration> + Clone
95{
96 fn eq(&self, other: &T) -> bool {
97 self.to_duration() == other.clone().into()
98 }
99}
100impl Eq for mach_timespec {}
101
102impl mach_timespec {
103 pub const fn new() -> Self {
104 Self {
105 tv_sec: 0,
106 tv_nsec: 0,
107 }
108 }
109
110 pub const fn from_secs(sec: c_uint) -> Self {
111 Self {
112 tv_sec: sec,
113 tv_nsec: 0
114 }
115 }
116 pub const fn from_nanos(nsec: clock_res_t) -> Self {
117 if nsec < 0 {
118 panic!("mach_timespec cannot convert from nanoseconds: `.tv_nsec` is a negative integer!");
119 }
120 Self::from_duration( Duration::from_nanos(nsec as u64) )
121 }
122
123 pub fn from_secs_f64(fsec: f64) -> Self {
125 Self::from_duration( Duration::from_secs_f64(fsec) )
126 }
127 pub fn as_secs_f64(&self) -> f64 {
128 self.to_duration().as_secs_f64()
129 }
130
131 pub fn from_secs_f32(fsec: f32) -> Self {
132 Self::from_duration( Duration::from_secs_f32(fsec) )
133 }
134 pub fn as_secs_f32(&self) -> f32 {
135 self.to_duration().as_secs_f32()
136 }
137 pub const fn to_duration(&self) -> Duration {
140 if ! self.is_valid() {
141 panic!("mach_timespec is invalid!");
142 }
143
144 let sec = self.tv_sec as u64;
145 let nsec = self.tv_nsec as u32;
146
147 Duration::new(sec, nsec)
148 }
149 pub const fn from_duration(dur: Duration) -> Self {
150 let tv_sec = {
151 let sec = dur.as_secs();
152
153 if sec > (c_uint::MAX as u64) {
155 panic!("cannot convert from Duration to mach_timespec: .tv_sec overflow c_uint!");
156 }
157
158 sec as c_uint
159 };
160
161 let tv_nsec = dur.subsec_nanos() as clock_res_t;
165
166 let this = Self {
167 tv_sec,
168 tv_nsec,
169 };
170 assert!(this.is_valid()); this
172 }
173
174 pub const fn is_valid(&self) -> bool {
175 if self.tv_nsec < 0 {
176 return false;
177 }
178
179 if (self.tv_nsec as c_ulonglong) >= NSEC_PER_SEC {
180 return false;
181 }
182
183 true
184 }
185
186 pub const fn cmp(&self, other: &Self) -> Ordering {
187 if self.tv_sec > other.tv_sec {
188 return Ordering::Greater;
189 }
190 if self.tv_sec < other.tv_sec {
191 return Ordering::Less;
192 }
193
194 if self.tv_nsec > other.tv_nsec {
197 return Ordering::Greater;
198 }
199 if self.tv_nsec < other.tv_nsec {
200 return Ordering::Less;
201 }
202
203 Ordering::Equal
206 }
207
208 pub const fn nsec_diff(&self, other: &Self)
209 -> c_ulonglong
210 {
211 if self.tv_sec > other.tv_sec {
212 return NSEC_PER_SEC;
213 }
214
215 if self.tv_sec < other.tv_sec {
216 return !NSEC_PER_SEC;
217 }
218
219 (self.tv_nsec - other.tv_nsec) as c_ulonglong
220 }
221
222 pub const fn add(&self, other: &Self) -> Self {
223 let mut result = Self::new();
224
225 result.tv_sec = self.tv_sec + other.tv_sec;
226 result.tv_nsec = self.tv_nsec + other.tv_nsec;
227
228 let t1ns = self.tv_nsec as c_ulonglong;
229 if t1ns >= NSEC_PER_SEC {
230 result.tv_nsec =
231 (t1ns - NSEC_PER_SEC) as clock_res_t;
232
233 result.tv_sec += 1;
234 }
235
236 result
237 }
238
239 pub const fn sub(&self, other: &Self) -> Self {
240 let mut result = Self::new();
241
242 result.tv_sec = self.tv_sec - other.tv_sec;
243 result.tv_nsec = self.tv_nsec - other.tv_nsec;
244
245 if result.tv_nsec < 0 {
246 result.tv_nsec +=
247 NSEC_PER_SEC as clock_res_t;
248
249 result.tv_sec -= 1;
250 }
251
252 result
253 }
254}
255
256macro_rules! _timespec_ops_impl {
257 ($op:tt, $func:tt) => {
258 _timespec_ops_impl!($op, $func, $func);
259 };
260
261 ($op:tt, $trait_func:tt, $orig_func:tt) => {
262 impl $op<mach_timespec> for mach_timespec {
263 type Output = mach_timespec;
264 fn $trait_func(self, other: mach_timespec)
265 -> mach_timespec
266 {
267 mach_timespec::$orig_func(&self, &other)
268 }
269 }
270
271 impl $op<&mach_timespec> for &mach_timespec {
273 type Output = mach_timespec;
274 fn $trait_func(self, other: &mach_timespec)
275 -> mach_timespec
276 {
277 mach_timespec::$orig_func(self, other)
278 }
279 }
280
281 impl $op<&mach_timespec> for mach_timespec {
282 type Output = mach_timespec;
283 fn $trait_func(self, other: &mach_timespec)
284 -> mach_timespec
285 {
286 mach_timespec::$orig_func(&self, other)
287 }
288 }
289 impl $op<mach_timespec> for &mach_timespec {
290 type Output = mach_timespec;
291 fn $trait_func(self, other: mach_timespec)
292 -> mach_timespec
293 {
294 mach_timespec::$orig_func(self, &other)
295 }
296 }
297 };
298}
299
300_timespec_ops_impl!(Add, add);
301_timespec_ops_impl!(Sub, sub);
302
303macro_rules! _timespec_ops_assign_impl {
304 ($op:tt, $func:tt, $orig_func:tt) => {
305 impl $op for mach_timespec {
306 fn $func(&mut self, other: mach_timespec) {
307 let ret = mach_timespec::$orig_func(&self, &other);
308 *self = ret;
309 }
310 }
311 }
312}
313
314_timespec_ops_assign_impl!(AddAssign, add_assign, add);
315_timespec_ops_assign_impl!(SubAssign, sub_assign, sub);
316
317#[allow(non_snake_case)]
320pub const fn BAD_MACH_TIMESPEC(t: mach_timespec) ->bool{
321 ! t.is_valid()
322}
323
324#[allow(non_snake_case)]
325pub const fn CMP_MACH_TIMESPEC(
326 t1: &mach_timespec,
327 t2: &mach_timespec
328) -> c_ulonglong {
329 t1.nsec_diff(t2)
330}
331
332pub const fn add_mach_timespec(
333 t1: &mach_timespec,
334 t2: &mach_timespec
335) -> mach_timespec {
336 mach_timespec::add(t1, t2)
337}
338pub const fn sub_mach_timespec(
339 t1: &mach_timespec,
340 t2: &mach_timespec
341) -> mach_timespec {
342 mach_timespec::sub(t1, t2)
343}
344
345#[allow(non_snake_case)]
346#[deprecated]
347pub fn ADD_MACH_TIMESPEC(
348 t1: &mut mach_timespec,
349 t2: &mach_timespec
350) {
351 *t1 = mach_timespec::add(t1, t2);
352}
353#[allow(non_snake_case)]
354#[deprecated]
355pub fn SUB_MACH_TIMESPEC(
356 t1: &mut mach_timespec,
357 t2: &mach_timespec
358) {
359 *t1 = mach_timespec::sub(t1, t2);
360}
361
362#[allow(non_snake_case)]
363pub const fn BAD_ALRMTYPE(t: c_uint) -> bool {
364 ( t & (!TIME_RELATIVE) ) != 0
365}
366
367#[cfg(test)]
368mod test {
369 use super::*;
370 use std::io::Write;
371
372 use crate::pl;
373
374 #[test]
375 fn ops_add() {
376 let mut rets = std::vec::Vec::new();
377 let c = 10240;
378 for _ in 0..c {
379 let n = fastrand::i32(clock_res_t::MIN as i32..clock_res_t::MAX as i32) as clock_res_t;
380 rets.push(_ops_add(n));
381 }
382
383 for out in
384 rets.into_iter()
385 .skip(c - 5)
386 .collect::<Vec<_>>()
387 {
388 pl!("{}", out);
389 }
390 }
391
392 fn _ops_add(n: clock_res_t) -> String {
393 let ret = std::panic::catch_unwind(|| {
394 mach_timespec::from_nanos(n)
395 });
396
397 let mut out = String::new();
398 if n >= 0 {
399 let spec = ret.expect("mach_timespec::from_nanos() parse failed");
400 assert!(spec.is_valid());
401 out.push_str(&format!("spec({spec:#?}) is valid"));
402 let dur = Duration::from_nanos(n as u64);
403
404 assert_eq!(spec, dur);
405 out.push_str(&format!("spec is equal to {:#?}", dur));
406 } else {
407 assert!(ret.is_err());
408 out.push_str(&format!("{n:?} is invalid"));
409 }
410 out
411 }
412}
413