#![allow(dead_code)]
use libc::c_void;
use std::time::{Duration, Instant};
#[link(name = "CoreFoundation", kind = "framework")]
extern "C" {
fn CFRunLoopGetMain() -> *mut c_void;
fn CFRunLoopRunInMode(
mode: *const c_void,
seconds: f64,
return_after_source_handled: bool,
) -> i32;
static kCFRunLoopDefaultMode: *const c_void;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RunLoopResult {
Finished = 1,
Stopped = 2,
TimedOut = 3,
HandledSource = 4,
}
impl From<i32> for RunLoopResult {
fn from(value: i32) -> Self {
match value {
1 => RunLoopResult::Finished,
2 => RunLoopResult::Stopped,
3 => RunLoopResult::TimedOut,
4 => RunLoopResult::HandledSource,
_ => RunLoopResult::Finished,
}
}
}
pub fn run_once(timeout: Duration, return_after_source_handled: bool) -> RunLoopResult {
unsafe {
let result = CFRunLoopRunInMode(
kCFRunLoopDefaultMode,
timeout.as_secs_f64(),
return_after_source_handled,
);
RunLoopResult::from(result)
}
}
pub fn run_for_duration<F>(duration: Duration, mut on_tick: F)
where
F: FnMut(Duration),
{
let start = Instant::now();
while start.elapsed() < duration {
run_once(Duration::from_millis(100), false);
on_tick(start.elapsed());
}
}
pub fn run_while<F>(condition: F, interval: Duration, timeout: Option<Duration>) -> bool
where
F: Fn() -> bool,
{
let start = Instant::now();
while condition() {
if let Some(timeout) = timeout {
if start.elapsed() >= timeout {
return false; }
}
run_once(interval, false);
}
true }
pub fn run_until_some<T, F>(
check: F,
interval: Duration,
timeout: Duration,
) -> Option<T>
where
F: Fn() -> Option<T>,
{
let start = Instant::now();
loop {
if let Some(value) = check() {
return Some(value);
}
if start.elapsed() >= timeout {
return None;
}
run_once(interval, false);
}
}