1use std::borrow::Cow;
4use std::ffi::{CStr, CString};
5use std::sync::atomic::{AtomicU64, Ordering};
6use std::time::{Duration, Instant};
7
8use mach2::mach_time::{mach_absolute_time, mach_timebase_info};
9
10use crate::TimeError;
11
12pub(crate) fn convert_mach_time_to_instant(mach_time: u64) -> Result<Instant, TimeError> {
14 let now = Instant::now();
15 let now_mach = unsafe { mach_absolute_time() } as i128;
17 let time_til_ticks = (mach_time as i128) - now_mach;
19 let back_in_time = time_til_ticks < 0;
20 let time_til = convert_mach_time_to_duration(time_til_ticks.unsigned_abs() as u64);
21
22 if back_in_time {
23 now.checked_sub(time_til).ok_or(TimeError::Overflow)
24 } else {
25 now.checked_add(time_til).ok_or(TimeError::Overflow)
26 }
27}
28
29pub(crate) fn convert_mach_time_to_duration(mach_time: u64) -> Duration {
31 static TIME_BASE_RAW_INFO: AtomicU64 = AtomicU64::new(0);
35
36 let mut value = mti_from_u64(TIME_BASE_RAW_INFO.load(Ordering::Relaxed));
37
38 if value.denom == 0 || value.numer == 0 {
40 unsafe { mach_timebase_info(&mut value) };
42
43 TIME_BASE_RAW_INFO.store(u64_from_mti(value), Ordering::Relaxed)
44 }
45
46 let nanos = (mach_time * u64::from(value.numer)) / u64::from(value.denom);
47
48 Duration::from_nanos(nanos)
49}
50
51fn mti_from_u64(raw_info: u64) -> mach_timebase_info {
53 mach_timebase_info {
54 numer: raw_info as u32,
55 denom: (raw_info >> 32) as u32,
56 }
57}
58
59fn u64_from_mti(info: mach_timebase_info) -> u64 {
61 (u64::from(info.denom) << 32) | u64::from(info.numer)
62}
63
64#[inline(always)]
66pub(crate) fn convert_timespec_to_duration(t: endpoint_sec_sys::timespec) -> Duration {
67 Duration::new(t.tv_sec as u64, t.tv_nsec as u32)
68}
69
70#[inline(always)]
77pub(crate) fn convert_byte_slice_to_cow_cstr(bytes: &[u8]) -> Cow<'_, CStr> {
78 match bytes.iter().position(|x| *x == b'\0').map(|x| x.checked_add(1)) {
79 Some(Some(one_past_nul)) => {
80 Cow::Borrowed(unsafe { CStr::from_bytes_with_nul_unchecked(&bytes[..one_past_nul]) })
82 },
83 Some(None) => Cow::Borrowed(unsafe { CStr::from_bytes_with_nul_unchecked(bytes) }),
85 None => Cow::Owned(unsafe { CString::from_vec_unchecked(bytes.into()) }),
88 }
89}