use crate::{NonZeroU32, Ratio, nz, unwrap};
#[doc = crate::_tags!(time)]
#[doc = crate::_doc_location!("phys/time")]
#[rustfmt::skip]
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub enum TimeScale {
Years,
Days,
Hours,
Minutes,
#[default]
Seconds,
Milliseconds,
Microseconds,
Nanoseconds,
Ratio(Ratio<NonZeroU32, NonZeroU32>),
}
#[allow(non_upper_case_globals)]
impl TimeScale {
pub const Mins: Self = Self::Minutes;
pub const Secs: Self = Self::Seconds;
pub const Millis: Self = Self::Milliseconds;
pub const Micros: Self = Self::Microseconds;
pub const Nanos: Self = Self::Nanoseconds;
}
impl TimeScale {
pub const fn is_calendar(self) -> bool {
matches!(self, Self::Years | Self::Days)
}
pub const fn is_fixed(self) -> bool {
!self.is_calendar()
}
pub const fn is_subsecond(self) -> bool {
matches!(self, Self::Milliseconds | Self::Microseconds | Self::Nanoseconds)
}
pub const fn is_second_based(self) -> bool {
matches!(
self,
Self::Seconds
| Self::Milliseconds
| Self::Microseconds
| Self::Nanoseconds
| Self::Ratio(_)
)
}
pub const fn name(self) -> &'static str {
match self {
Self::Years => "years",
Self::Days => "days",
Self::Hours => "hours",
Self::Minutes => "minutes",
Self::Seconds => "seconds",
Self::Milliseconds => "milliseconds",
Self::Microseconds => "microseconds",
Self::Nanoseconds => "nanoseconds",
Self::Ratio(_) => "ratio",
}
}
pub const fn convert(self, value: u64, target: TimeScale) -> Option<u64> {
let (from, to) = (unwrap![some? self.to_ratio()], unwrap![some? target.to_ratio()]);
let num = (value as u128) * (from.n.get() as u128) * (to.d.get() as u128);
let den = (from.d.get() as u128) * (to.n.get() as u128);
Some((num / den) as u64)
}
pub fn convert_simulated(self, value: u64, target: TimeScale) -> u64 {
let from = self.to_ratio_simulated();
let to = target.to_ratio_simulated();
let num = (value as u128) * (from.n.get() as u128) * (to.d.get() as u128);
let den = (from.d.get() as u128) * (to.n.get() as u128);
(num / den) as u64
}
}
impl TimeScale {
pub const fn new_ratio(num: u32, den: u32) -> Option<Self> {
match (NonZeroU32::new(num), NonZeroU32::new(den)) {
(Some(n), Some(d)) => Some(Self::Ratio(Ratio::new(n, d))),
_ => None,
}
}
pub const fn some_ratio(self) -> Option<Ratio<NonZeroU32, NonZeroU32>> {
match self {
Self::Ratio(r) => Some(r),
_ => None,
}
}
pub const fn to_ratio(self) -> Option<Ratio<NonZeroU32, NonZeroU32>> {
match self {
Self::Seconds => Some(Ratio::new(nz!(1u32), nz!(1u32))),
Self::Milliseconds => Some(Ratio::new(nz!(1u32), nz!(1_000u32))),
Self::Microseconds => Some(Ratio::new(nz!(1u32), nz!(1_000_000u32))),
Self::Nanoseconds => Some(Ratio::new(nz!(1u32), nz!(1_000_000_000u32))),
Self::Minutes => Some(Ratio::new(nz!(60u32), nz!(1u32))),
Self::Hours => Some(Ratio::new(nz!(3_600u32), nz!(1u32))),
Self::Ratio(r) => Some(r),
Self::Days | Self::Years => None,
}
}
pub const fn to_ratio_simulated(self) -> Ratio<NonZeroU32, NonZeroU32> {
match self {
Self::Seconds => Ratio::new(nz!(1u32), nz!(1u32)),
Self::Milliseconds => Ratio::new(nz!(1u32), nz!(1_000u32)),
Self::Microseconds => Ratio::new(nz!(1u32), nz!(1_000_000u32)),
Self::Nanoseconds => Ratio::new(nz!(1u32), nz!(1_000_000_000u32)),
Self::Minutes => Ratio::new(nz!(60u32), nz!(1u32)),
Self::Hours => Ratio::new(nz!(3_600u32), nz!(1u32)),
Self::Ratio(r) => r,
Self::Days => Ratio::new(nz!(86_400u32), nz!(1u32)), Self::Years => Ratio::new(nz!(31_536_000u32), nz!(1u32)), }
}
}