1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::{Duration, Instant as StdInstant};
const NANOSECONDS_PER_BASIC_BLOCK: u64 = 10;
#[derive(Debug)]
pub struct Instant {
kind: InstantKind,
}
#[derive(Debug)]
enum InstantKind {
Host(StdInstant),
Virtual { nanoseconds: u64 },
}
impl Instant {
pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
match self.kind {
InstantKind::Host(instant) =>
instant.checked_add(duration).map(|i| Instant { kind: InstantKind::Host(i) }),
InstantKind::Virtual { nanoseconds } =>
u128::from(nanoseconds)
.checked_add(duration.as_nanos())
.and_then(|n| u64::try_from(n).ok())
.map(|nanoseconds| Instant { kind: InstantKind::Virtual { nanoseconds } }),
}
}
pub fn duration_since(&self, earlier: Instant) -> Duration {
match (&self.kind, earlier.kind) {
(InstantKind::Host(instant), InstantKind::Host(earlier)) =>
instant.duration_since(earlier),
(
InstantKind::Virtual { nanoseconds },
InstantKind::Virtual { nanoseconds: earlier },
) => Duration::from_nanos(nanoseconds.saturating_sub(earlier)),
_ => panic!("all `Instant` must be of the same kind"),
}
}
}
#[derive(Debug)]
pub struct Clock {
kind: ClockKind,
}
#[derive(Debug)]
enum ClockKind {
Host {
time_anchor: StdInstant,
},
Virtual {
nanoseconds: AtomicU64,
},
}
impl Clock {
pub fn new(communicate: bool) -> Self {
let kind = if communicate {
ClockKind::Host { time_anchor: StdInstant::now() }
} else {
ClockKind::Virtual { nanoseconds: 0.into() }
};
Self { kind }
}
pub fn tick(&self) {
match &self.kind {
ClockKind::Host { .. } => {
}
ClockKind::Virtual { nanoseconds } => {
nanoseconds.fetch_add(NANOSECONDS_PER_BASIC_BLOCK, Ordering::SeqCst);
}
}
}
pub fn sleep(&self, duration: Duration) {
match &self.kind {
ClockKind::Host { .. } => std::thread::sleep(duration),
ClockKind::Virtual { nanoseconds } => {
nanoseconds.fetch_add(duration.as_nanos().try_into().unwrap(), Ordering::SeqCst);
}
}
}
pub fn anchor(&self) -> Instant {
match &self.kind {
ClockKind::Host { time_anchor } => Instant { kind: InstantKind::Host(*time_anchor) },
ClockKind::Virtual { .. } => Instant { kind: InstantKind::Virtual { nanoseconds: 0 } },
}
}
pub fn now(&self) -> Instant {
match &self.kind {
ClockKind::Host { .. } => Instant { kind: InstantKind::Host(StdInstant::now()) },
ClockKind::Virtual { nanoseconds } =>
Instant {
kind: InstantKind::Virtual { nanoseconds: nanoseconds.load(Ordering::SeqCst) },
},
}
}
}