use core::{ ops::{Add, AddAssign, Sub, SubAssign}, time::Duration, }; use serde::{Deserialize, Serialize}; use crate::ScriptContext; mod tortuise { #[link(wasm_import_module = "tortuise")] unsafe extern "C" { pub safe fn system_now(context: u64) -> u64; pub safe fn monotonic_now(context: u64) -> u64; pub safe fn delta_time(context: u64) -> u64; } } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] #[repr(transparent)] #[serde(transparent)] pub struct SystemTime(u128); #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] #[repr(transparent)] #[serde(transparent)] pub struct Instant(u128); impl ScriptContext { pub fn delta_time(&self) -> Duration { Duration::from_nanos(tortuise::delta_time(self.0)) } } impl SystemTime { pub const UNIX_EPOCH: Self = Self(0); pub fn now(context: &ScriptContext) -> Self { Self(tortuise::system_now(context.0) as u128) } pub fn duration_since(self, earlier: SystemTime) -> Option { if self < earlier { return None; } Some(Duration::from_nanos_u128(self.0 - earlier.0)) } pub fn checked_add(self, duration: Duration) -> Option { Some(Self(self.0.checked_add(duration.as_nanos())?)) } pub fn checked_sub(self, duration: Duration) -> Option { Some(Self(self.0.checked_sub(duration.as_nanos())?)) } } impl Add for SystemTime { type Output = Self; fn add(self, rhs: Duration) -> Self::Output { self.checked_add(rhs).unwrap() } } impl AddAssign for SystemTime { fn add_assign(&mut self, rhs: Duration) { *self = self.add(rhs); } } impl Sub for SystemTime { type Output = Self; fn sub(self, rhs: Duration) -> Self::Output { self.checked_sub(rhs).unwrap() } } impl SubAssign for SystemTime { fn sub_assign(&mut self, rhs: Duration) { *self = self.sub(rhs) } } impl Instant { pub fn now(context: &ScriptContext) -> Self { Self(tortuise::monotonic_now(context.0) as u128) } pub fn duration_since(self, earlier: Instant) -> Option { if earlier > self { return None; } Some(Duration::from_nanos_u128(self.0 - earlier.0)) } pub fn elapsed(self, context: &ScriptContext) -> Duration { Self::now(context) .duration_since(self) .unwrap_or(Duration::ZERO) } pub fn checked_add(self, duration: Duration) -> Option { Some(Self(self.0.checked_add(duration.as_nanos())?)) } pub fn checked_sub(self, duration: Duration) -> Option { Some(Self(self.0.checked_sub(duration.as_nanos())?)) } } impl Add for Instant { type Output = Self; fn add(self, rhs: Duration) -> Self::Output { self.checked_add(rhs).unwrap() } } impl AddAssign for Instant { fn add_assign(&mut self, rhs: Duration) { *self = self.add(rhs); } } impl Sub for Instant { type Output = Self; fn sub(self, rhs: Duration) -> Self::Output { self.checked_sub(rhs).unwrap() } } impl SubAssign for Instant { fn sub_assign(&mut self, rhs: Duration) { *self = self.sub(rhs) } }