1use std::prelude::v1::*;
23use crate::clock::{Clock, ReasonablyRealtime, Reference};
4use crate::nanos::Nanos;
5use std::ops::Add;
6use std::sync::Arc;
7use std::time::Duration;
89/// A clock using the default [`quanta::Clock`] structure.
10///
11/// This clock uses [`quanta::Clock.now`], which does retrieve the time synchronously. To use a
12/// clock that uses a quanta background upkeep thread (which allows retrieving the time with an
13/// atomic read, but requires a background thread that wakes up continually),
14/// see [`QuantaUpkeepClock`].
15#[derive(Debug, Clone)]
16pub struct QuantaClock {
17 clock: quanta::Clock,
18}
1920impl Default for QuantaClock {
21fn default() -> Self {
22let clock = quanta::Clock::default();
23Self { clock }
24 }
25}
2627impl Clock for QuantaClock {
28type Instant = QuantaInstant;
2930fn now(&self) -> Self::Instant {
31let nowish = self.clock.raw();
32 QuantaInstant(Nanos::new(self.clock.delta_as_nanos(0, nowish)))
33 }
34}
3536/// A nanosecond-scale opaque instant (already scaled to reference time) returned from a
37/// [`QuantaClock`].
38#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
39pub struct QuantaInstant(Nanos);
4041impl Add<Nanos> for QuantaInstant {
42type Output = QuantaInstant;
4344fn add(self, other: Nanos) -> QuantaInstant {
45 QuantaInstant(self.0 + other)
46 }
47}
4849impl Reference for QuantaInstant {
50fn duration_since(&self, earlier: Self) -> Nanos {
51self.0.duration_since(earlier.0)
52 }
5354fn saturating_sub(&self, duration: Nanos) -> Self {
55 QuantaInstant(self.0.saturating_sub(duration))
56 }
57}
5859/// A clock using the default [`quanta::Clock`] structure and an upkeep thread.
60///
61/// This clock relies on an upkeep thread that wakes up in regular (user defined) intervals to
62/// retrieve the current time and update an atomic U64; the clock then can retrieve that time
63/// (and is as behind as, at most, that interval).
64///
65/// The background thread is stopped as soon as the last clone of the clock is
66/// dropped.
67///
68/// Whether this is faster than a [`QuantaClock`] depends on the utilization of the rate limiter
69/// and the upkeep interval that you pick; you should measure and compare performance before
70/// picking one or the other.
71#[derive(Debug, Clone)]
72pub struct QuantaUpkeepClock {
73 clock: quanta::Clock,
74 _handle: Arc<quanta::Handle>,
75 reference: quanta::Instant,
76}
7778impl QuantaUpkeepClock {
79/// Returns a new `QuantaUpkeepClock` with an upkeep thread that wakes up once in `interval`.
80pub fn from_interval(interval: Duration) -> Result<QuantaUpkeepClock, quanta::Error> {
81let builder = quanta::Upkeep::new(interval);
82Self::from_builder(builder)
83 }
8485/// Returns a new `QuantaUpkeepClock` with an upkeep thread as specified by the given builder.
86pub fn from_builder(builder: quanta::Upkeep) -> Result<QuantaUpkeepClock, quanta::Error> {
87let handle = Arc::new(builder.start()?);
88let clock = quanta::Clock::default();
89let reference = clock.recent();
90Ok(QuantaUpkeepClock {
91 clock,
92 _handle: handle,
93 reference,
94 })
95 }
96}
9798impl Clock for QuantaUpkeepClock {
99type Instant = QuantaInstant;
100101fn now(&self) -> Self::Instant {
102 QuantaInstant(Nanos::from(
103self.clock
104 .recent()
105 .saturating_duration_since(self.reference),
106 ))
107 }
108}
109110impl ReasonablyRealtime for QuantaClock {}
111112/// Some tests to ensure that the code above gets exercised. We don't
113/// rely on them in tests (being nastily tainted by realism), so we
114/// have to get creative.
115#[cfg(test)]
116mod test {
117use super::*;
118use crate::clock::{Clock, QuantaClock, QuantaUpkeepClock, Reference};
119use crate::nanos::Nanos;
120use std::thread;
121use std::time::Duration;
122123#[test]
124fn quanta_impls_coverage() {
125let one_ns = Nanos::new(1);
126let c = QuantaClock::default();
127let now = c.now();
128assert_ne!(now + one_ns, now);
129assert_eq!(one_ns, Reference::duration_since(&(now + one_ns), now));
130assert_eq!(Nanos::new(0), Reference::duration_since(&now, now + one_ns));
131assert_eq!(
132 Reference::saturating_sub(&(now + Duration::from_nanos(1).into()), one_ns),
133 now
134 );
135 }
136137#[test]
138fn quanta_upkeep_impls_coverage_and_advances() {
139let one_ns = Nanos::new(1);
140// let _c1 =
141 // QuantaUpkeepClock::from_builder(quanta::Upkeep::new(Duration::from_secs(1))).unwrap();
142let c = QuantaUpkeepClock::from_interval(Duration::from_millis(50)).unwrap();
143let now = c.now();
144assert_ne!(now + one_ns, now);
145assert_eq!(one_ns, Reference::duration_since(&(now + one_ns), now));
146assert_eq!(Nanos::new(0), Reference::duration_since(&now, now + one_ns));
147assert_eq!(
148 Reference::saturating_sub(&(now + Duration::from_nanos(1).into()), one_ns),
149 now
150 );
151152// Test clock advances over time.
153 // (included in one test as only one QuantaUpkeepClock thread can be run at a time)
154let start = c.now();
155for i in 0..5 {
156 thread::sleep(Duration::from_millis(250));
157let now = c.now();
158assert!(
159 now > start,
160"now={:?} not after start={:?} on iteration={}",
161 now,
162 start,
163 i
164 );
165 }
166 }
167}