use crate::{
ConstInit, DebugExt, Duration, FmtResult, Formatter, TimeSplitNorm, f32bits, f32bits_niche,
impl_trait,
};
#[doc = crate::_tags!(event time)]
#[doc = crate::_doc_location!("ui/event")]
#[must_use]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum EventTimestampMode {
#[default]
Auto,
Float,
Int,
Dual,
}
impl DebugExt for EventTimestamp {
type Ctx = EventTimestampMode;
fn fmt_with(&self, f: &mut Formatter, ctx: &Self::Ctx) -> FmtResult<()> {
match ctx {
Self::Ctx::Auto => self.fmt_auto_ms(f),
Self::Ctx::Float => self.fmt_float_ms(f),
Self::Ctx::Int => self.fmt_int_ms(f),
Self::Ctx::Dual => self.fmt_dual_ms(f),
}
}
}
#[doc = crate::_tags!(event time)]
#[doc = crate::_doc_location!("ui/event")]
#[must_use]
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct EventTimestamp {
ms: f32bits_niche,
}
#[rustfmt::skip]
#[allow(dead_code)]
impl EventTimestamp {
pub(crate) const fn new(ms: f32bits_niche) -> Self { Self { ms } }
pub(crate) const fn from_non_niche(ms: f32bits) -> Self { Self::new(ms.to_niche()) }
pub(crate) const fn get_niche(self) -> f32bits_niche { self.ms }
pub(crate) const fn get_non_niche(self) -> f32bits { self.ms.to_non_niche() }
}
#[rustfmt::skip]
impl EventTimestamp {
pub fn as_duration(&self) -> Duration {
let ms = self.ms.as_float() as u64;
Duration::from_millis(ms)
}
}
#[rustfmt::skip]
impl EventTimestamp {
pub const fn from_secs_f32(seconds: f32) -> Self {
EventTimestamp::new(f32bits_niche::new(seconds * 1000.0))
}
pub const fn from_millis_f32(ms: f32) -> Self {
EventTimestamp::new(f32bits_niche::new(ms))
}
pub const fn as_secs_f32(self) -> f32 { self.ms.as_float() * 0.001 }
pub const fn as_millis_f32(self) -> f32 { self.ms.as_float() }
}
#[rustfmt::skip]
impl EventTimestamp {
pub const fn from_millis_u32(ms: u32) -> Self {
Self::new(f32bits_niche::from_bits(ms))
}
#[must_use]
pub const fn as_millis_u32(&self) -> u32 { self.ms.as_bits() }
pub const fn from_millis_u32_as_f32(ms: u32) -> Self {
Self::new(f32bits_niche::new(ms as f32))
}
#[must_use]
pub const fn as_millis_f32_to_u32(&self) -> u32 { self.ms.as_float() as u32 }
}
#[rustfmt::skip]
impl EventTimestamp {
pub fn fmt_auto_ms(&self, f: &mut Formatter) -> FmtResult<()> {
let sure_float = |f:f32| f.is_finite() && (1e-3..=1e9).contains(&f);
let sure_int = |f: f32| !f.is_finite() || !(1e-8..=1e12).contains(&f);
let float = self.ms.as_float();
if sure_float(float) { self.fmt_float_ms(f) }
else if sure_int(float) { self.fmt_int_ms(f) }
else { self.fmt_dual_ms(f) } }
pub fn fmt_int_ms(&self, f: &mut Formatter) -> FmtResult<()> {
write![f, "{} ms", self.ms.as_bits()]
}
pub fn fmt_float_ms(&self, f: &mut Formatter) -> FmtResult<()> {
write![f, "{} ms", self.ms.as_float()]
}
pub fn fmt_dual_ms(&self, f: &mut Formatter) -> FmtResult<()> {
write![f, "{}|{:.6} ms", self.ms.as_bits(), self.ms.as_float()]
}
pub fn fmt_split_full(&self, f: &mut Formatter) -> FmtResult<()> {
let split = TimeSplitNorm::from_duration(self.as_duration());
write!(f, "{}mo {}d {:02}h:{:02}m:{:02}s {:03}ms {:03}us {:03}ns",
split.mo, split.d, split.h, split.m, split.s, split.ms, split.us, split.ns
)
}
}
impl_trait! { fmt::Debug for EventTimestamp |self, f| self.fmt_auto_ms(f) }
impl_trait! { fmt::Display for EventTimestamp |self, f| self.as_millis_f32().fmt(f) }
impl ConstInit for EventTimestamp {
const INIT: Self = Self::new(f32bits_niche::INIT);
}
#[rustfmt::skip]
#[cfg(all(feature = "js", not(windows)))]
mod impl_js {
pub use super::*;
pub use crate::JsInstant;
impl EventTimestamp {
pub const fn from_js(from: JsInstant) -> EventTimestamp {
EventTimestamp::from_millis_f32(from.as_millis_f64() as f32)
}
pub const fn to_js(self) -> JsInstant {
JsInstant::from_millis_f64(self.as_millis_f32() as f64)
}
}
impl From<JsInstant> for EventTimestamp {
fn from(from: JsInstant) -> Self { EventTimestamp::from_js(from) }
}
impl From<EventTimestamp> for JsInstant {
fn from(from: EventTimestamp) -> Self { from.to_js() }
}
}