use std::borrow::Cow;
use std::ffi::{CStr, CString};
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::{Duration, Instant};
use mach2::mach_time::{mach_absolute_time, mach_timebase_info};
use crate::TimeError;
pub(crate) fn convert_mach_time_to_instant(mach_time: u64) -> Result<Instant, TimeError> {
let now = Instant::now();
let now_mach = unsafe { mach_absolute_time() } as i128;
let time_til_ticks = (mach_time as i128) - now_mach;
let back_in_time = time_til_ticks < 0;
let time_til = convert_mach_time_to_duration(time_til_ticks.unsigned_abs() as u64);
if back_in_time {
now.checked_sub(time_til).ok_or(TimeError::Overflow)
} else {
now.checked_add(time_til).ok_or(TimeError::Overflow)
}
}
pub(crate) fn convert_mach_time_to_duration(mach_time: u64) -> Duration {
static TIME_BASE_RAW_INFO: AtomicU64 = AtomicU64::new(0);
let mut value = mti_from_u64(TIME_BASE_RAW_INFO.load(Ordering::Relaxed));
if value.denom == 0 || value.numer == 0 {
unsafe { mach_timebase_info(&mut value) };
TIME_BASE_RAW_INFO.store(u64_from_mti(value), Ordering::Relaxed)
}
let nanos = (mach_time * u64::from(value.numer)) / u64::from(value.denom);
Duration::from_nanos(nanos)
}
fn mti_from_u64(raw_info: u64) -> mach_timebase_info {
mach_timebase_info {
numer: raw_info as u32,
denom: (raw_info >> 32) as u32,
}
}
fn u64_from_mti(info: mach_timebase_info) -> u64 {
u64::from(info.denom) << 32 | u64::from(info.numer)
}
#[inline(always)]
pub(crate) fn convert_timespec_to_duration(t: endpoint_sec_sys::timespec) -> Duration {
Duration::new(t.tv_sec as u64, t.tv_nsec as u32)
}
#[inline(always)]
pub(crate) fn convert_byte_slice_to_cow_cstr(bytes: &[u8]) -> Cow<'_, CStr> {
match bytes.iter().position(|x| *x == b'\0').map(|x| x.checked_add(1)) {
Some(Some(one_past_nul)) => {
Cow::Borrowed(unsafe { CStr::from_bytes_with_nul_unchecked(&bytes[..one_past_nul]) })
},
Some(None) => Cow::Borrowed(unsafe { CStr::from_bytes_with_nul_unchecked(bytes) }),
None => Cow::Owned(unsafe { CString::from_vec_unchecked(bytes.into()) }),
}
}