Skip to main content

cf_mach/nq_core/
time.rs

1// Copyright (c) 2023-2024 Cloudflare, Inc.
2// Licensed under the BSD-3-Clause license found in the LICENSE file or at https://opensource.org/licenses/BSD-3-Clause
3
4//! Defines a [`Time`] trait used to abstract over the different ways a
5//! timestamp can be created or a process slept. This lets us switch between
6//! tokio, system and in the future, wasi/wasm based time implementations.
7
8use std::ops::{Add, Sub};
9use std::sync::Arc;
10use std::time::Duration;
11use tokio::time::Instant;
12
13/// A timestamp with `Instant` for precise time measurement.
14#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
15pub struct Timestamp(Instant);
16
17impl Timestamp {
18    /// Calculate the saturating duration since an earlier timestamp.
19    pub fn duration_since(&self, earlier: Timestamp) -> Duration {
20        self.0
21            .checked_duration_since(earlier.0)
22            .unwrap_or_else(|| Duration::from_secs(0))
23    }
24
25    /// Create a new `Timestamp` from the current `Instant`.
26    pub fn now() -> Self {
27        Timestamp(Instant::now())
28    }
29}
30
31impl Add<Duration> for Timestamp {
32    type Output = Timestamp;
33
34    fn add(self, duration: Duration) -> Self::Output {
35        Timestamp(self.0 + duration)
36    }
37}
38
39impl Sub<Duration> for Timestamp {
40    type Output = Timestamp;
41
42    fn sub(self, duration: Duration) -> Self::Output {
43        Timestamp(self.0 - duration)
44    }
45}
46
47/// An abstraction over time. Provides the ability to create a timestamp.
48pub trait Time: Send + Sync {
49    /// The current time.
50    fn now(&self) -> Timestamp;
51}
52
53impl<T: Time> Time for Arc<T>
54where
55    T: Time,
56{
57    fn now(&self) -> Timestamp {
58        <T as Time>::now(self)
59    }
60}
61
62impl<T: Time> Time for Box<T>
63where
64    T: Time,
65{
66    fn now(&self) -> Timestamp {
67        <T as Time>::now(self)
68    }
69}
70
71impl<T: Time> Time for &T
72where
73    T: Time,
74{
75    fn now(&self) -> Timestamp {
76        <T as Time>::now(self)
77    }
78}
79
80/// An implementation of `Time` based on `tokio::Instant`.
81#[derive(Debug, Clone, Copy)]
82pub struct TokioTime {
83    base_instant: Instant,
84    base_timestamp: Timestamp,
85}
86
87impl TokioTime {
88    /// Creates a new `TokioTime`.
89    pub fn new() -> Self {
90        let base_instant = tokio::time::Instant::now();
91        let base_timestamp = Timestamp::now(); // Use the current timestamp
92
93        Self {
94            base_instant,
95            base_timestamp,
96        }
97    }
98}
99
100impl Default for TokioTime {
101    fn default() -> Self {
102        Self::new()
103    }
104}
105
106impl Time for TokioTime {
107    fn now(&self) -> Timestamp {
108        let now = Instant::now();
109        let elapsed = now.duration_since(self.base_instant);
110        self.base_timestamp + elapsed
111    }
112}