use log::error;
use std::sync::Arc;
use std::sync::atomic::AtomicU32;
use std::time::{SystemTime, UNIX_EPOCH};
pub trait TimeProvider: Send + Sync {
fn now_seconds(&self) -> u32;
fn set_time(&self, next: u32);
}
#[derive(Default, Clone)]
pub struct SystemTimeProvider;
impl TimeProvider for SystemTimeProvider {
fn now_seconds(&self) -> u32 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_secs() as u32)
.unwrap_or(0)
}
fn set_time(&self, _next: u32) {
error!("Cannot set time on SystemTimeProvider");
}
}
pub struct ManualTimeProvider {
watermark: AtomicU32,
}
impl ManualTimeProvider {
pub fn new(initial: u32) -> Self {
Self {
watermark: AtomicU32::new(initial),
}
}
pub fn set_time(&self, next: u32) {
self.watermark
.fetch_update(
std::sync::atomic::Ordering::Relaxed,
std::sync::atomic::Ordering::Relaxed,
|current| Some(current.max(next)),
)
.ok();
}
}
impl Default for ManualTimeProvider {
fn default() -> Self {
Self::new(0)
}
}
impl TimeProvider for ManualTimeProvider {
fn now_seconds(&self) -> u32 {
self.watermark.load(std::sync::atomic::Ordering::Relaxed)
}
fn set_time(&self, next: u32) {
self.set_time(next);
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "snake_case")]
pub enum TimeProviderKind {
#[default]
System,
Manual,
}
impl TimeProviderKind {
pub fn create(&self) -> Arc<dyn TimeProvider> {
match self {
TimeProviderKind::System => Arc::new(SystemTimeProvider),
TimeProviderKind::Manual => Arc::new(ManualTimeProvider::default()),
}
}
}