use core::task::Waker;
use core::time::Duration;
use crate::time::{Driver, Instant};
unsafe extern "Rust" {
fn proxima_time_external_now_millis() -> u64;
fn proxima_time_external_schedule_wake(deadline_millis: u64, waker: Waker);
}
pub static DRIVER: ExternalDriver = ExternalDriver;
pub struct ExternalDriver;
impl Driver for ExternalDriver {
fn now(&self) -> Instant {
let millis = unsafe { proxima_time_external_now_millis() };
Instant::from_monotonic(Duration::from_millis(millis))
}
fn schedule_wake(&self, deadline: Instant, waker: Waker) {
let deadline_millis =
u64::try_from(deadline.into_monotonic().as_millis()).unwrap_or(u64::MAX);
unsafe { proxima_time_external_schedule_wake(deadline_millis, waker) }
}
}
#[cfg(all(test, proxima_external_driver))]
mod test_host {
use core::task::Waker;
use std::sync::OnceLock;
use std::time::{Duration, Instant};
fn epoch() -> Instant {
static EPOCH: OnceLock<Instant> = OnceLock::new();
*EPOCH.get_or_init(Instant::now)
}
#[unsafe(no_mangle)]
extern "Rust" fn proxima_time_external_now_millis() -> u64 {
u64::try_from(epoch().elapsed().as_millis()).unwrap_or(u64::MAX)
}
#[unsafe(no_mangle)]
extern "Rust" fn proxima_time_external_schedule_wake(deadline_millis: u64, waker: Waker) {
let now_millis = proxima_time_external_now_millis();
let delay = Duration::from_millis(deadline_millis.saturating_sub(now_millis));
std::thread::spawn(move || {
std::thread::sleep(delay);
waker.wake();
});
}
}