use core::cell::Cell;
use crate::ctypes::*;
#[repr(transparent)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TimeTicks(pub(crate) u32); impl TimeTicks {
pub fn from_milliseconds(millis: u32) -> Self {
TimeTicks(millis)
}
pub fn from_seconds_lossy(sec: f32) -> Self {
TimeTicks((sec * 1000f32) as u32)
}
pub fn total_whole_hours(&self) -> u32 {
self.0 / (1000 * 60 * 60)
}
pub fn total_whole_minutes(&self) -> u32 {
self.0 / (1000 * 60)
}
pub fn total_whole_seconds(&self) -> u32 {
self.0 / 1000
}
pub fn total_whole_milliseconds(&self) -> u32 {
self.0
}
pub fn to_seconds(self) -> f32 {
(self.0 as f32) / 1000f32
}
pub(crate) fn from_sample_frames(frames: u32) -> Self {
TimeTicks(frames * 1000 / crate::sound::SAMPLE_FRAMES_PER_SEC as u32)
}
pub(crate) fn to_sample_frames(self) -> u32 {
self.total_whole_milliseconds() * crate::sound::SAMPLE_FRAMES_PER_SEC as u32 / 1000
}
}
#[repr(transparent)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TimeDelta(i32); impl TimeDelta {
pub const fn from_days(h: i32) -> Self {
Self::from_hours(h * 24)
}
pub const fn from_hours(h: i32) -> Self {
Self::from_minutes(h * 60)
}
pub const fn from_minutes(m: i32) -> Self {
Self::from_seconds(m * 60)
}
pub const fn from_seconds(s: i32) -> Self {
TimeDelta(s * 1000)
}
pub const fn from_milliseconds(s: i32) -> Self {
TimeDelta(s)
}
pub fn from_seconds_lossy(sec: f32) -> Self {
TimeDelta((sec * 1000f32) as i32)
}
pub fn total_whole_hours(&self) -> i32 {
self.0 / (1000 * 60 * 60)
}
pub fn total_whole_minutes(&self) -> i32 {
self.0 / (1000 * 60)
}
pub fn total_whole_seconds(&self) -> i32 {
self.0 / 1000
}
pub fn total_whole_milliseconds(&self) -> i32 {
self.0
}
pub fn to_seconds(self) -> f32 {
(self.0 as f32) / 1000f32
}
#[allow(dead_code)] pub(crate) fn from_sample_frames(frames: i32) -> Self {
TimeDelta(frames * 1000 / crate::sound::SAMPLE_FRAMES_PER_SEC)
}
pub(crate) fn to_sample_frames(self) -> i32 {
self.total_whole_milliseconds() * crate::sound::SAMPLE_FRAMES_PER_SEC / 1000
}
}
impl core::ops::Add<TimeDelta> for TimeTicks {
type Output = TimeTicks;
fn add(self, rhs: TimeDelta) -> Self::Output {
if rhs.0 >= 0 {
TimeTicks(self.0.checked_add(rhs.0 as u32).unwrap())
} else {
TimeTicks(self.0.checked_sub((-rhs.0) as u32).unwrap())
}
}
}
impl core::ops::Sub<TimeDelta> for TimeTicks {
type Output = TimeTicks;
fn sub(self, rhs: TimeDelta) -> Self::Output {
if rhs.0 >= 0 {
TimeTicks(self.0.checked_sub(rhs.0 as u32).unwrap())
} else {
TimeTicks(self.0.checked_add((-rhs.0) as u32).unwrap())
}
}
}
impl core::ops::Sub<TimeTicks> for TimeTicks {
type Output = TimeDelta;
fn sub(self, rhs: TimeTicks) -> Self::Output {
if self > rhs {
let positive_val = self.0 - rhs.0;
TimeDelta(positive_val as i32)
} else {
let positive_val = rhs.0 - self.0;
TimeDelta(-(positive_val as i32))
}
}
}
impl core::fmt::Display for TimeTicks {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{} seconds", self.to_seconds())
}
}
impl core::fmt::Display for TimeDelta {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{} seconds", self.to_seconds())
}
}
#[derive(Debug)]
pub struct HighResolutionTimer<'a> {
csystem: &'static CSystemApi,
active_marker: &'a Cell<bool>,
}
impl<'a> HighResolutionTimer<'a> {
pub(crate) fn new(csystem: &'static CSystemApi, active_marker: &'a Cell<bool>) -> Self {
active_marker.set(true);
HighResolutionTimer {
csystem,
active_marker,
}
}
fn elapsed(&self) -> f32 {
unsafe { self.csystem.getElapsedTime.unwrap()() }
}
pub fn elapsed_seconds_lossy(&self) -> f32 {
self.elapsed()
}
pub fn elapsed_microseconds(&self) -> u32 {
let seconds = self.elapsed();
let seconds_whole = unsafe { core::intrinsics::truncf32(seconds) };
let seconds_fract = seconds - seconds_whole;
let micros_from_whole = (seconds_whole * 1000000f32) as u32;
let micros_from_fract = (seconds_fract * 1000000f32) as u32;
micros_from_whole.checked_add(micros_from_fract).unwrap_or(u32::MAX)
}
}
impl Drop for HighResolutionTimer<'_> {
fn drop(&mut self) {
self.active_marker.set(false)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WallClockTime(pub(crate) u32);
impl WallClockTime {
#[allow(dead_code)]
pub const PLAYDATE_EPOCH: WallClockTime = WallClockTime(0);
}
impl core::ops::Add<TimeDelta> for WallClockTime {
type Output = TimeTicks;
fn add(self, rhs: TimeDelta) -> Self::Output {
if rhs.0 >= 0 {
TimeTicks(self.0.checked_add(rhs.0 as u32).unwrap())
} else {
TimeTicks(self.0.checked_sub((-rhs.0) as u32).unwrap())
}
}
}
impl core::ops::Sub<TimeDelta> for WallClockTime {
type Output = TimeTicks;
fn sub(self, rhs: TimeDelta) -> Self::Output {
if rhs.0 >= 0 {
TimeTicks(self.0.checked_sub(rhs.0 as u32).unwrap())
} else {
TimeTicks(self.0.checked_add((-rhs.0) as u32).unwrap())
}
}
}
impl core::ops::Sub<WallClockTime> for WallClockTime {
type Output = TimeDelta;
fn sub(self, rhs: WallClockTime) -> Self::Output {
if self > rhs {
let positive_val = self.0 - rhs.0;
TimeDelta(positive_val as i32)
} else {
let positive_val = rhs.0 - self.0;
TimeDelta(-(positive_val as i32))
}
}
}
#[derive(Debug)]
pub struct TimeSpan {
pub start: TimeTicks,
pub end: TimeTicks,
}
#[derive(Debug)]
pub struct RelativeTimeSpan {
pub start: TimeDelta,
pub end: TimeDelta,
}