Skip to main content

gpui_rhai/
clock.rs

1use std::cell::Cell;
2use std::fmt;
3use std::rc::Rc;
4use std::time::{Duration, Instant};
5
6pub trait RuntimeClockSource {
7    fn now(&self) -> Instant;
8
9    fn advance(&self, _duration: Duration) -> bool {
10        false
11    }
12}
13
14#[derive(Clone)]
15pub struct RuntimeClock {
16    source: Rc<dyn RuntimeClockSource>,
17    origin: Instant,
18}
19
20impl RuntimeClock {
21    #[must_use]
22    pub fn system() -> Self {
23        Self::from_source(SystemRuntimeClock)
24    }
25
26    #[must_use]
27    pub fn from_source(source: impl RuntimeClockSource + 'static) -> Self {
28        let source: Rc<dyn RuntimeClockSource> = Rc::new(source);
29        let origin = source.now();
30        Self { source, origin }
31    }
32
33    #[must_use]
34    pub fn now(&self) -> Instant {
35        self.source.now()
36    }
37
38    #[must_use]
39    pub fn elapsed(&self) -> Duration {
40        self.now().saturating_duration_since(self.origin)
41    }
42
43    #[must_use]
44    pub fn advance(&self, duration: Duration) -> bool {
45        self.source.advance(duration)
46    }
47}
48
49impl Default for RuntimeClock {
50    fn default() -> Self {
51        Self::system()
52    }
53}
54
55impl fmt::Debug for RuntimeClock {
56    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
57        formatter.write_str("RuntimeClock(..)")
58    }
59}
60
61#[derive(Clone, Copy, Debug)]
62struct SystemRuntimeClock;
63
64impl RuntimeClockSource for SystemRuntimeClock {
65    fn now(&self) -> Instant {
66        Instant::now()
67    }
68}
69
70#[derive(Clone, Debug)]
71pub struct ManualRuntimeClock {
72    now: Rc<Cell<Instant>>,
73}
74
75impl ManualRuntimeClock {
76    #[must_use]
77    pub fn new(now: Instant) -> Self {
78        Self {
79            now: Rc::new(Cell::new(now)),
80        }
81    }
82
83    #[must_use]
84    pub fn clock(&self) -> RuntimeClock {
85        RuntimeClock::from_source(self.clone())
86    }
87
88    pub fn advance(&self, duration: Duration) {
89        self.now.set(self.now.get() + duration);
90    }
91
92    pub fn set(&self, now: Instant) {
93        self.now.set(now);
94    }
95}
96
97impl RuntimeClockSource for ManualRuntimeClock {
98    fn now(&self) -> Instant {
99        self.now.get()
100    }
101
102    fn advance(&self, duration: Duration) -> bool {
103        self.advance(duration);
104        true
105    }
106}
107
108#[cfg(test)]
109mod tests {
110    use super::*;
111
112    #[test]
113    fn manual_clock_is_shared_and_monotonic_by_host_policy() {
114        let start = Instant::now();
115        let manual = ManualRuntimeClock::new(start);
116        let clock = manual.clock();
117        manual.advance(Duration::from_millis(16));
118        assert_eq!(clock.now(), start + Duration::from_millis(16));
119        assert_eq!(clock.elapsed(), Duration::from_millis(16));
120    }
121}