use cap_std::time::{Duration, Instant, SystemClock, SystemTime};
use cap_std::{AmbientAuthority, ambient_authority};
use cap_time_ext::{MonotonicClockExt as _, SystemClockExt as _};
use wasmtime::component::{HasData, ResourceTable};
pub struct WasiClocks;
impl HasData for WasiClocks {
type Data<'a> = WasiClocksCtxView<'a>;
}
pub struct WasiClocksCtx {
pub(crate) wall_clock: Box<dyn HostWallClock + Send>,
pub(crate) monotonic_clock: Box<dyn HostMonotonicClock + Send>,
}
impl Default for WasiClocksCtx {
fn default() -> Self {
Self {
wall_clock: wall_clock(),
monotonic_clock: monotonic_clock(),
}
}
}
pub trait WasiClocksView: Send {
fn clocks(&mut self) -> WasiClocksCtxView<'_>;
}
pub struct WasiClocksCtxView<'a> {
pub ctx: &'a mut WasiClocksCtx,
pub table: &'a mut ResourceTable,
}
pub trait HostWallClock: Send {
fn resolution(&self) -> Duration;
fn now(&self) -> Duration;
}
pub trait HostMonotonicClock: Send {
fn resolution(&self) -> u64;
fn now(&self) -> u64;
}
pub struct WallClock {
clock: cap_std::time::SystemClock,
}
impl Default for WallClock {
fn default() -> Self {
Self::new(ambient_authority())
}
}
impl WallClock {
pub fn new(ambient_authority: AmbientAuthority) -> Self {
Self {
clock: cap_std::time::SystemClock::new(ambient_authority),
}
}
}
impl HostWallClock for WallClock {
fn resolution(&self) -> Duration {
self.clock.resolution()
}
fn now(&self) -> Duration {
self.clock
.now()
.duration_since(SystemClock::UNIX_EPOCH)
.unwrap()
}
}
pub struct MonotonicClock {
clock: cap_std::time::MonotonicClock,
initial: Instant,
}
impl Default for MonotonicClock {
fn default() -> Self {
Self::new(ambient_authority())
}
}
impl MonotonicClock {
pub fn new(ambient_authority: AmbientAuthority) -> Self {
let clock = cap_std::time::MonotonicClock::new(ambient_authority);
let initial = clock.now();
Self { clock, initial }
}
}
impl HostMonotonicClock for MonotonicClock {
fn resolution(&self) -> u64 {
self.clock.resolution().as_nanos().try_into().unwrap()
}
fn now(&self) -> u64 {
self.clock
.now()
.duration_since(self.initial)
.as_nanos()
.try_into()
.unwrap()
}
}
pub fn monotonic_clock() -> Box<dyn HostMonotonicClock + Send> {
Box::new(MonotonicClock::default())
}
pub fn wall_clock() -> Box<dyn HostWallClock + Send> {
Box::new(WallClock::default())
}
pub(crate) struct Datetime {
pub seconds: u64,
pub nanoseconds: u32,
}
impl TryFrom<SystemTime> for Datetime {
type Error = wasmtime::Error;
fn try_from(time: SystemTime) -> Result<Self, Self::Error> {
let duration =
time.duration_since(SystemTime::from_std(std::time::SystemTime::UNIX_EPOCH))?;
Ok(Self {
seconds: duration.as_secs(),
nanoseconds: duration.subsec_nanos(),
})
}
}