1 use std::sync::atomic::{AtomicU64, Ordering};
2 use std::time::{Duration, Instant as StdInstant};
4 /// When using a virtual clock, this defines how many nanoseconds we pretend are passing for each
6 const NANOSECONDS_PER_BASIC_BLOCK: u64 = 10;
16 Virtual { nanoseconds: u64 },
20 pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
22 InstantKind::Host(instant) =>
23 instant.checked_add(duration).map(|i| Instant { kind: InstantKind::Host(i) }),
24 InstantKind::Virtual { nanoseconds } =>
25 u128::from(nanoseconds)
26 .checked_add(duration.as_nanos())
27 .and_then(|n| u64::try_from(n).ok())
28 .map(|nanoseconds| Instant { kind: InstantKind::Virtual { nanoseconds } }),
32 pub fn duration_since(&self, earlier: Instant) -> Duration {
33 match (&self.kind, earlier.kind) {
34 (InstantKind::Host(instant), InstantKind::Host(earlier)) =>
35 instant.duration_since(earlier),
37 InstantKind::Virtual { nanoseconds },
38 InstantKind::Virtual { nanoseconds: earlier },
39 ) => Duration::from_nanos(nanoseconds.saturating_sub(earlier)),
40 _ => panic!("all `Instant` must be of the same kind"),
45 /// A monotone clock used for `Instant` simulation.
54 /// The "time anchor" for this machine's monotone clock.
55 time_anchor: StdInstant,
58 /// The "current virtual time".
59 nanoseconds: AtomicU64,
64 /// Create a new clock based on the availability of communication with the host.
65 pub fn new(communicate: bool) -> Self {
66 let kind = if communicate {
67 ClockKind::Host { time_anchor: StdInstant::now() }
69 ClockKind::Virtual { nanoseconds: 0.into() }
75 /// Let the time pass for a small interval.
78 ClockKind::Host { .. } => {
79 // Time will pass without us doing anything.
81 ClockKind::Virtual { nanoseconds } => {
82 nanoseconds.fetch_add(NANOSECONDS_PER_BASIC_BLOCK, Ordering::SeqCst);
87 /// Sleep for the desired duration.
88 pub fn sleep(&self, duration: Duration) {
90 ClockKind::Host { .. } => std::thread::sleep(duration),
91 ClockKind::Virtual { nanoseconds } => {
92 // Just pretend that we have slept for some time.
93 nanoseconds.fetch_add(duration.as_nanos().try_into().unwrap(), Ordering::SeqCst);
98 /// Return the `anchor` instant, to convert between monotone instants and durations relative to the anchor.
99 pub fn anchor(&self) -> Instant {
101 ClockKind::Host { time_anchor } => Instant { kind: InstantKind::Host(*time_anchor) },
102 ClockKind::Virtual { .. } => Instant { kind: InstantKind::Virtual { nanoseconds: 0 } },
106 pub fn now(&self) -> Instant {
108 ClockKind::Host { .. } => Instant { kind: InstantKind::Host(StdInstant::now()) },
109 ClockKind::Virtual { nanoseconds } =>
111 kind: InstantKind::Virtual { nanoseconds: nanoseconds.load(Ordering::SeqCst) },