klauthed_core/time/
clock.rs1use std::sync::Mutex;
4
5use time::{Duration, OffsetDateTime};
6
7use super::Timestamp;
8
9pub trait Clock: Send + Sync {
14 fn now(&self) -> Timestamp;
16
17 fn now_datetime(&self) -> OffsetDateTime {
19 self.now().into_offset_datetime()
20 }
21}
22
23#[derive(Debug, Clone, Copy, Default)]
25pub struct SystemClock;
26
27impl Clock for SystemClock {
28 fn now(&self) -> Timestamp {
29 Timestamp::now()
30 }
31}
32
33#[derive(Debug)]
36pub struct FixedClock {
37 now: Mutex<Timestamp>,
38}
39
40impl FixedClock {
41 pub fn new(at: Timestamp) -> Self {
43 Self { now: Mutex::new(at) }
44 }
45
46 pub fn at_unix_millis(millis: i64) -> Self {
48 Self::new(Timestamp::from_unix_millis(millis))
49 }
50
51 pub fn set(&self, at: Timestamp) {
53 *self.now.lock().unwrap_or_else(std::sync::PoisonError::into_inner) = at;
54 }
55
56 #[allow(
58 clippy::expect_used,
59 reason = "advancing this fixed test clock past the representable range is a caller error"
60 )]
61 pub fn advance(&self, delta: Duration) {
62 let mut guard = self.now.lock().unwrap_or_else(std::sync::PoisonError::into_inner);
63 *guard =
64 guard.checked_add(delta).expect("clock advance overflowed the representable range");
65 }
66}
67
68impl Clock for FixedClock {
69 fn now(&self) -> Timestamp {
70 *self.now.lock().unwrap_or_else(std::sync::PoisonError::into_inner)
71 }
72}