summaryrefslogtreecommitdiff
path: root/src/time.rs
blob: 35e1a86e49bae0f4364dc8983e8858f63fcd8bff (plain)
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<Duration> {
		if self < earlier {
			return None;
		}

		Some(Duration::from_nanos_u128(self.0 - earlier.0))
	}

	pub fn checked_add(self, duration: Duration) -> Option<Self> {
		Some(Self(self.0.checked_add(duration.as_nanos())?))
	}

	pub fn checked_sub(self, duration: Duration) -> Option<Self> {
		Some(Self(self.0.checked_sub(duration.as_nanos())?))
	}
}

impl Add<Duration> for SystemTime {
	type Output = Self;

	fn add(self, rhs: Duration) -> Self::Output {
		self.checked_add(rhs).unwrap()
	}
}

impl AddAssign<Duration> for SystemTime {
	fn add_assign(&mut self, rhs: Duration) {
		*self = self.add(rhs);
	}
}

impl Sub<Duration> for SystemTime {
	type Output = Self;

	fn sub(self, rhs: Duration) -> Self::Output {
		self.checked_sub(rhs).unwrap()
	}
}

impl SubAssign<Duration> 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<Duration> {
		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<Self> {
		Some(Self(self.0.checked_add(duration.as_nanos())?))
	}

	pub fn checked_sub(self, duration: Duration) -> Option<Self> {
		Some(Self(self.0.checked_sub(duration.as_nanos())?))
	}
}

impl Add<Duration> for Instant {
	type Output = Self;

	fn add(self, rhs: Duration) -> Self::Output {
		self.checked_add(rhs).unwrap()
	}
}

impl AddAssign<Duration> for Instant {
	fn add_assign(&mut self, rhs: Duration) {
		*self = self.add(rhs);
	}
}

impl Sub<Duration> for Instant {
	type Output = Self;

	fn sub(self, rhs: Duration) -> Self::Output {
		self.checked_sub(rhs).unwrap()
	}
}

impl SubAssign<Duration> for Instant {
	fn sub_assign(&mut self, rhs: Duration) {
		*self = self.sub(rhs)
	}
}