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 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
//! Interface to measure time.
use std::time::Instant;
/// The BSEC algorithem needs a clock capable of providing timestamps.
/// Implement this trait according to your hardware platform.
///
/// # Example
///
/// A possible implementation based on [`std::time`] could look like this:
///
/// ```
/// use bsec::clock::Clock;
/// use std::time::{Duration, Instant};
///
/// pub struct TimePassed {
/// start: Instant,
/// }
///
/// impl TimePassed {
/// fn new() -> Self {
/// Self { start: Instant::now() }
/// }
/// }
///
/// impl Clock for TimePassed {
/// fn timestamp_ns(&self) -> i64 {
/// self.start.elapsed().as_nanos() as i64
/// }
/// }
/// ```
pub trait Clock {
/// Return a monotonically increasing timestamp with nanosecond resolution.
///
/// The reference point may be arbitrary.
fn timestamp_ns(&self) -> i64;
}
/// Measures time since the creation of an instance.
pub struct TimePassed {
start: Instant,
}
impl TimePassed {
/// Create a new instance starting time measurement at instant of
/// instantiation.
pub fn new() -> Self {
Self {
start: Instant::now(),
}
}
}
impl Default for TimePassed {
fn default() -> Self {
Self {
start: Instant::now(),
}
}
}
impl Clock for TimePassed {
fn timestamp_ns(&self) -> i64 {
self.start.elapsed().as_nanos() as i64
}
}
#[cfg(test)]
pub mod tests {
use super::{Clock, TimePassed};
#[test]
fn time_passed_smoke_test() {
assert!(TimePassed::default().timestamp_ns() >= 0);
}
}
/// Provides a fake [`Clock`] implementation to be used in unit tests.
///
/// This module is only available if the **test-support** feature is enabled.
#[cfg(any(test, feature = "test-support"))]
pub mod test_support {
use std::{
sync::atomic::{AtomicI64, Ordering},
time::Duration,
};
use super::*;
/// A fake [`Clock`] for unit tests that can be advanced manually.
///
/// Each call to [`FakeClock::timestamp_ns`] will advance by one nanosecond.
///
/// # Example
///
/// ```
/// # use bsec::clock::{Clock, test_support::FakeClock};
/// let clock = FakeClock::new();
/// assert_eq!(clock.timestamp_ns(), 0);
/// assert_eq!(clock.timestamp_ns(), 1);
/// assert_eq!(clock.timestamp_ns(), 2);
/// clock.advance_by(std::time::Duration::from_nanos(5));
/// assert_eq!(clock.timestamp_ns(), 8);
/// ```
#[derive(Default)]
pub struct FakeClock {
timestamp_ns: AtomicI64,
}
impl FakeClock {
/// Create a new [`FakeClock`] initialized with a zero timestamp.
pub fn new() -> Self {
Self::default()
}
}
impl Clock for FakeClock {
/// Returns the current timestamp and advances it by one.
fn timestamp_ns(&self) -> i64 {
self.timestamp_ns.fetch_add(1, Ordering::Relaxed)
}
}
impl FakeClock {
/// Advance the clock's internal time by `duration`.
pub fn advance_by(&self, duration: Duration) {
self.timestamp_ns
.fetch_add(duration.as_nanos() as i64, Ordering::Relaxed);
}
}
}