use std::time::{Duration, Instant, SystemTime};
use crate::types::WallTime;
pub fn now_wall() -> WallTime {
SystemTime::now().into()
}
pub fn now_mono() -> Instant {
Instant::now()
}
pub fn deadline_from_now(d: Duration) -> Instant {
Instant::now() + d
}
pub fn thread_sleep_quantum() -> f64 {
#[cfg(target_os = "linux")]
{
let hz = unsafe { libc::sysconf(libc::_SC_CLK_TCK) } as f64;
if hz <= 0.0 { 0.0 } else { 1.0 / hz }
}
#[cfg(not(target_os = "linux"))]
{
0.01
}
}
pub fn quantize_to_sleep_quantum(seconds: f64) -> f64 {
let quantum = thread_sleep_quantum();
if quantum <= 0.0 {
return seconds;
}
let ticks = seconds / quantum;
let rounded = if ticks > 0.0 {
ticks + 0.5
} else {
ticks - 0.5
};
quantum * c_long_cast(rounded) as f64
}
fn c_long_cast(f: f64) -> i64 {
const MIN: f64 = -9_223_372_036_854_775_808.0; const LIMIT: f64 = 9_223_372_036_854_775_808.0; if f.is_nan() || f < MIN || f >= LIMIT {
i64::MIN
} else {
f as i64
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_now_wall() {
let t = now_wall();
assert!(t.since_unix_epoch().as_secs() > 0);
}
#[test]
fn test_now_mono() {
let t1 = now_mono();
let t2 = now_mono();
assert!(t2 >= t1);
}
#[test]
fn test_deadline_from_now() {
let before = Instant::now();
let deadline = deadline_from_now(Duration::from_secs(10));
assert!(deadline > before);
assert!(deadline <= before + Duration::from_secs(11));
}
#[test]
fn c_long_cast_matches_cvttsd2si() {
assert_eq!(c_long_cast(0.0), 0);
assert_eq!(c_long_cast(-0.0), 0);
assert_eq!(c_long_cast(0.5), 0);
assert_eq!(c_long_cast(-0.5), 0); assert_eq!(c_long_cast(1.9), 1);
assert_eq!(c_long_cast(-1.9), -1);
assert_eq!(c_long_cast(-9_223_372_036_854_775_808.0), i64::MIN);
assert_eq!(c_long_cast(9_223_372_036_854_775_808.0), i64::MIN); assert_eq!(c_long_cast(1e300), i64::MIN);
assert_eq!(c_long_cast(-1e300), i64::MIN);
assert_eq!(c_long_cast(f64::INFINITY), i64::MIN);
assert_eq!(c_long_cast(f64::NEG_INFINITY), i64::MIN);
assert_eq!(c_long_cast(f64::NAN), i64::MIN);
}
#[test]
fn quantize_dly_boundaries_match_c() {
let q = thread_sleep_quantum();
assert!(q > 0.0, "test assumes a positive clock quantum, got {q}");
let zero = quantize_to_sleep_quantum(0.0);
assert_eq!(zero, 0.0);
assert!(
zero.is_sign_positive(),
"DLY=0.0 must round to +0.0 (renders \"0\"), got a negative zero"
);
let neg_zero = quantize_to_sleep_quantum(-0.0);
assert_eq!(neg_zero, 0.0);
assert!(
neg_zero.is_sign_positive(),
"DLY=-0.0 must round to +0.0, got a negative zero"
);
let tiny = quantize_to_sleep_quantum(q / 4.0);
assert_eq!(tiny, 0.0);
assert!(tiny.is_sign_positive(), "tiny +dly rounds to +0.0");
let tiny_neg = quantize_to_sleep_quantum(-q / 4.0);
assert_eq!(tiny_neg, 0.0);
assert!(
tiny_neg.is_sign_positive(),
"a -dly rounding to zero must serve +0.0, not -0.0"
);
assert_eq!(quantize_to_sleep_quantum(3.0 * q), 3.0 * q);
assert_eq!(quantize_to_sleep_quantum(-3.0 * q), -3.0 * q);
assert_eq!(quantize_to_sleep_quantum(1.5 * q), 2.0 * q);
assert_eq!(quantize_to_sleep_quantum(-1.5 * q), -2.0 * q);
let huge = quantize_to_sleep_quantum(1e300);
assert_eq!(huge, q * (i64::MIN as f64));
assert!(
huge.is_finite() && huge < 0.0,
"a huge +dly must serve C's ~-9.22e16, not inf, got {huge}"
);
let huge_neg = quantize_to_sleep_quantum(-1e300);
assert_eq!(huge_neg, q * (i64::MIN as f64));
assert_eq!(
quantize_to_sleep_quantum(f64::INFINITY),
q * (i64::MIN as f64)
);
assert_eq!(
quantize_to_sleep_quantum(f64::NEG_INFINITY),
q * (i64::MIN as f64)
);
}
}