Skip to main content

cronoq_core/
time.rs

1//! Engine time. The core never reads a clock: every input carries `now`.
2
3use core::ops::{Add, Sub};
4use core::time::Duration;
5
6/// Engine time: nanoseconds since the engine epoch.
7///
8/// The engine only requires that time never goes backwards; it makes no assumption about where
9/// the epoch is. The `cronoq` runtime uses the Unix epoch, so `Time(n)` is `n` nanoseconds after
10/// 1970-01-01T00:00:00Z (representable until the year 2554). Tests often use small values.
11#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
12pub struct Time(pub u64);
13
14impl Time {
15    /// The epoch itself.
16    pub const ZERO: Time = Time(0);
17    /// The latest representable time (also used as "never").
18    pub const MAX: Time = Time(u64::MAX);
19
20    /// Time from (fractional) seconds since the epoch; negative values clamp to zero.
21    #[inline]
22    pub fn from_secs_f64(s: f64) -> Time {
23        Time((s.max(0.0) * 1e9) as u64)
24    }
25    /// Seconds since the epoch.
26    #[inline]
27    pub fn as_secs_f64(self) -> f64 {
28        self.0 as f64 / 1e9
29    }
30    /// `self - other`, or zero if `other` is later.
31    #[inline]
32    pub fn saturating_sub(self, other: Time) -> Duration {
33        Duration::from_nanos(self.0.saturating_sub(other.0))
34    }
35    /// Signed difference `self - other` in seconds.
36    #[inline]
37    pub fn diff_secs(self, other: Time) -> f64 {
38        (self.0 as i64).wrapping_sub(other.0 as i64) as f64 / 1e9
39    }
40}
41
42impl Add<Duration> for Time {
43    type Output = Time;
44    #[inline]
45    fn add(self, d: Duration) -> Time {
46        Time(
47            self.0
48                .saturating_add(d.as_nanos().min(u64::MAX as u128) as u64),
49        )
50    }
51}
52
53impl Sub<Duration> for Time {
54    type Output = Time;
55    #[inline]
56    fn sub(self, d: Duration) -> Time {
57        Time(
58            self.0
59                .saturating_sub(d.as_nanos().min(u64::MAX as u128) as u64),
60        )
61    }
62}
63
64#[inline]
65pub(crate) fn secs(d: Duration) -> f64 {
66    d.as_secs_f64()
67}