moonpool_core/
time.rs

1//! Time provider abstraction for simulation and real time.
2//!
3//! This module provides a unified interface for time operations that works
4//! seamlessly with both simulation time and real wall-clock time.
5
6use async_trait::async_trait;
7use std::time::Duration;
8
9use crate::SimulationResult;
10
11/// Provider trait for time operations.
12///
13/// This trait allows code to work with both simulation time and real wall-clock time
14/// in a unified way. Implementations handle sleeping and getting current time
15/// appropriate for their environment.
16///
17/// ## Time Semantics
18///
19/// - `now()`: Returns the exact, canonical time. Use this for scheduling and precise comparisons.
20/// - `timer()`: Returns a potentially drifted time that can be slightly ahead of `now()`.
21///   In simulation, this simulates real-world clock drift. In production, this equals `now()`.
22///
23/// FDB ref: sim2.actor.cpp:1056-1064
24#[async_trait(?Send)]
25pub trait TimeProvider: Clone {
26    /// Sleep for the specified duration.
27    ///
28    /// In simulation, this advances simulation time. In real time,
29    /// this uses actual wall-clock delays.
30    async fn sleep(&self, duration: Duration) -> SimulationResult<()>;
31
32    /// Get exact current time.
33    ///
34    /// In simulation, this returns the canonical simulation time.
35    /// In real time, this returns wall-clock elapsed time since provider creation.
36    ///
37    /// Use this for precise time comparisons and event scheduling.
38    fn now(&self) -> Duration;
39
40    /// Get drifted timer time.
41    ///
42    /// In simulation, this can be up to `clock_drift_max` (default 100ms) ahead of `now()`.
43    /// This simulates real-world clock drift between processes.
44    /// In real time, this equals `now()`.
45    ///
46    /// Use this for time-sensitive application logic like timeouts, leases, and heartbeats
47    /// to test how code handles clock drift.
48    ///
49    /// FDB ref: sim2.actor.cpp:1058-1064
50    fn timer(&self) -> Duration;
51
52    /// Run a future with a timeout.
53    ///
54    /// Returns `Ok(result)` if the future completes within the timeout,
55    /// or `Err(())` if it times out.
56    async fn timeout<F, T>(&self, duration: Duration, future: F) -> SimulationResult<Result<T, ()>>
57    where
58        F: std::future::Future<Output = T>;
59}
60
61/// Real time provider using Tokio's time facilities.
62#[derive(Debug, Clone)]
63pub struct TokioTimeProvider {
64    /// Start time for calculating elapsed duration
65    start_time: std::time::Instant,
66}
67
68impl TokioTimeProvider {
69    /// Create a new Tokio time provider.
70    pub fn new() -> Self {
71        Self {
72            start_time: std::time::Instant::now(),
73        }
74    }
75}
76
77impl Default for TokioTimeProvider {
78    fn default() -> Self {
79        Self::new()
80    }
81}
82
83#[async_trait(?Send)]
84impl TimeProvider for TokioTimeProvider {
85    async fn sleep(&self, duration: Duration) -> SimulationResult<()> {
86        tokio::time::sleep(duration).await;
87        Ok(())
88    }
89
90    fn now(&self) -> Duration {
91        // Return elapsed time since provider creation
92        self.start_time.elapsed()
93    }
94
95    fn timer(&self) -> Duration {
96        // In real time, there's no simulated drift - timer equals now
97        self.now()
98    }
99
100    async fn timeout<F, T>(&self, duration: Duration, future: F) -> SimulationResult<Result<T, ()>>
101    where
102        F: std::future::Future<Output = T>,
103    {
104        match tokio::time::timeout(duration, future).await {
105            Ok(result) => Ok(Ok(result)),
106            Err(_) => Ok(Err(())),
107        }
108    }
109}