use super::*;
pub type Time = TimeOf<float>;
pub type DeltaTime = Time;
pub type DeltaTimeOf<T> = TimeOf<T>;
new_unit!(
TimeOf
);
pub trait ToTime<T>: ToTimeComposite<Output = TimeOf<T>>
where
T: CastIntoFloat,
{
}
impl<S, T> ToTime<T> for S
where
S: ToTimeComposite<Output = TimeOf<T>>,
T: CastIntoFloat,
{
}
pub trait ToTimeComposite
{
type Output;
fn millis(self) -> Self::Output;
fn secs(self) -> Self::Output;
fn mins(self) -> Self::Output;
fn hours(self) -> Self::Output;
fn days(self) -> Self::Output;
}
map_on_number!(
($name:ident) =>
{
impl ToTimeComposite for $name
{
type Output = Time;
fn millis(self) -> Self::Output { Time::from_millis(self.to_float()) }
fn secs (self) -> Self::Output { Time::from_secs (self.to_float()) }
fn mins (self) -> Self::Output { Time::from_mins (self.to_float()) }
fn hours (self) -> Self::Output { Time::from_hours (self.to_float()) }
fn days (self) -> Self::Output { Time::from_days (self.to_float()) }
}
}
);
impl<T> ToTimeComposite for T
where
T: Map,
T::Item: ToTimeComposite,
{
type Output = T::WithType<<T::Item as ToTimeComposite>::Output>;
fn millis(self) -> Self::Output { self.map(ToTimeComposite::millis) }
fn secs(self) -> Self::Output { self.map(ToTimeComposite::secs) }
fn mins(self) -> Self::Output { self.map(ToTimeComposite::mins) }
fn hours(self) -> Self::Output { self.map(ToTimeComposite::hours) }
fn days(self) -> Self::Output { self.map(ToTimeComposite::days) }
}
impl<T: Float> Debug for TimeOf<T>
{
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { write!(f, "{}", self) }
}
impl<T: Float> TimeOf<T>
{
fn display_non_zero_unit(f: &mut Formatter<'_>, val: i32, unit: &str) -> FmtResult
{
if val != 0
{
Self::display_unit(f, val, unit)?;
write!(f, " ")
}
else
{
Ok(())
}
}
fn display_unit(f: &mut Formatter<'_>, val: i32, unit: &str) -> FmtResult
{
write!(f, "{}{}", val, unit)
}
}
impl<T: Float> Display for TimeOf<T>
{
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult
{
if self.is_zero()
{
return write!(f, "0s");
}
if self.is_strictly_negative()
{
write!(f, "-")?;
}
Self::display_non_zero_unit(f, self.timer_days(), "d")?;
Self::display_non_zero_unit(f, self.timer_hours(), "h")?;
Self::display_non_zero_unit(f, self.timer_mins(), "min")?;
Self::display_non_zero_unit(f, self.timer_secs(), "s")?;
Self::display_non_zero_unit(f, self.timer_millis(), "ms")?;
Ok(())
}
}
impl<T: Float> TimeOf<T>
{
pub fn from_millis(ms: T) -> Self { Self::from_secs(ms / 1000.cast_into()) }
pub fn millis(self) -> T { self.0 * 1000.cast_into() }
pub fn whole_millis(self) -> i32 { self.millis().round_toward_zero().to_i32() }
pub fn timer_millis(self) -> i32 { self.millis().abs().floor().to_i32() % 1000 }
pub const fn from_secs(second: T) -> Self { Self(second) }
pub fn secs(self) -> T { self.0 }
pub fn whole_secs(self) -> i32 { self.secs().round_toward_zero().to_i32() }
pub fn timer_secs(self) -> i32 { self.secs().abs().floor().to_i32() % 60 }
pub fn from_mins(min: T) -> Self { Self::from_secs(min * T::SIXTY) }
pub fn mins(self) -> T { self.0 / T::SIXTY }
pub fn whole_mins(self) -> i32 { self.mins().round_toward_zero().to_i32() }
pub fn timer_mins(self) -> i32 { self.mins().abs().floor().to_i32() % 60 }
pub fn from_hours(hours: T) -> Self { Self::from_secs(hours * (T::SIXTY * T::SIXTY)) }
pub fn hours(self) -> T { self.0 / (T::SIXTY * T::SIXTY) }
pub fn whole_hours(self) -> i32 { self.hours().round_toward_zero().to_i32() }
pub fn timer_hours(self) -> i32 { self.hours().abs().floor().to_i32() % 24 }
pub fn from_days(day: T) -> Self
{
Self::from_secs(day * (T::SIXTY * T::SIXTY * T::TWENTY_FOUR))
}
pub fn days(self) -> T { self.0 / (T::SIXTY * T::SIXTY * T::TWENTY_FOUR) }
pub fn whole_days(self) -> i32 { self.days().round_toward_zero().to_i32() }
pub fn timer_days(self) -> i32 { self.days().abs().floor().to_i32() }
}
impl<T: Float> RangeDefault for TimeOf<T>
where
T: RangeDefault,
{
const RANGE_MIN: Self = Self(T::RANGE_MIN);
const RANGE_HALF: Self = Self(T::RANGE_HALF);
const RANGE_MAX: Self = Self(T::RANGE_MAX);
const RANGE: Self = Self(T::RANGE);
}
#[cfg(feature = "serde")]
impl<T> Serialize for TimeOf<T>
where
T: Float + Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.secs().serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, T> Deserialize<'de> for TimeOf<T>
where
T: Float + Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Ok(Self::from_secs(T::deserialize(deserializer)?))
}
}
pub trait TimeNow: Additive
{
fn since_launch() -> Self;
}
impl<F> TimeNow for TimeOf<F>
where
F: Float + CastFrom<f64>,
{
fn since_launch() -> Self
{
#[cfg(not(target_arch = "wasm32"))]
{
use std::{sync::Once, time::Instant};
static mut START_TIME: Option<Instant> = None;
static INIT: Once = Once::new();
INIT.call_once(|| unsafe {
START_TIME = Some(Instant::now());
});
let elapsed = unsafe { Instant::now() - START_TIME.unwrap() };
return TimeOf::from_secs(F::cast_from(elapsed.as_secs_f64()));
}
#[cfg(target_arch = "wasm32")]
{
use std::sync::Once;
use web_time::Instant;
static mut START_TIME: Option<Instant> = None;
static INIT: Once = Once::new();
INIT.call_once(|| unsafe {
START_TIME = Some(Instant::now());
});
let elapsed = unsafe { Instant::now() - START_TIME.unwrap() };
return TimeOf::from_secs(F::cast_from(elapsed.as_secs_f64()));
}
}
}