#[cfg(any(test, feature = "test-clock"))]
use std::sync::Arc;
#[cfg(any(test, feature = "test-clock"))]
use std::sync::atomic::{AtomicI64, Ordering};
#[derive(Debug, Clone, Default)]
pub struct Clock(Source);
#[derive(Debug, Clone, Default)]
enum Source {
#[default]
System,
#[cfg(any(test, feature = "test-clock"))]
Manual(ManualClock),
}
impl Clock {
#[must_use]
pub fn system() -> Self {
Self(Source::System)
}
pub(crate) fn now(&self) -> i64 {
match &self.0 {
Source::System => jiff::Timestamp::now().as_second(),
#[cfg(any(test, feature = "test-clock"))]
Source::Manual(manual) => manual.now(),
}
}
}
#[cfg(any(test, feature = "test-clock"))]
#[derive(Debug, Clone)]
pub struct ManualClock(Arc<AtomicI64>);
#[cfg(any(test, feature = "test-clock"))]
impl ManualClock {
#[must_use]
pub fn new(start: i64) -> Self {
Self(Arc::new(AtomicI64::new(start)))
}
#[must_use]
pub fn clock(&self) -> Clock {
Clock(Source::Manual(self.clone()))
}
#[must_use]
pub fn now(&self) -> i64 {
self.0.load(Ordering::SeqCst)
}
pub fn set(&self, seconds: i64) {
self.0.store(seconds, Ordering::SeqCst);
}
pub fn advance(&self, seconds: i64) {
let mut now = self.now();
while let Err(seen) = self.0.compare_exchange_weak(
now,
now.saturating_add(seconds),
Ordering::SeqCst,
Ordering::SeqCst,
) {
now = seen;
}
}
}