extern crate alloc;
use alloc::boxed::Box;
use alloc::sync::Arc;
use core::sync::atomic::{AtomicU64, Ordering};
pub trait TimeSource: Send + Sync {
fn now(&self) -> u64;
}
impl<T: TimeSource + ?Sized> TimeSource for Box<T> {
fn now(&self) -> u64 {
(**self).now()
}
}
#[derive(Debug, Default)]
pub struct TickCounter {
counter: AtomicU64,
}
impl TickCounter {
#[must_use]
pub const fn new() -> Self {
Self {
counter: AtomicU64::new(0),
}
}
}
impl TimeSource for TickCounter {
fn now(&self) -> u64 {
self.counter.fetch_add(1, Ordering::SeqCst)
}
}
#[derive(Debug, Clone, Default)]
pub struct VirtualTimeSource {
current: Arc<AtomicU64>,
}
impl VirtualTimeSource {
#[must_use]
pub fn new(physical: u64) -> Self {
Self {
current: Arc::new(AtomicU64::new(physical)),
}
}
pub fn set(&self, physical: u64) {
self.current.store(physical, Ordering::SeqCst);
}
pub fn advance(&self, delta: u64) {
let mut current = self.current.load(Ordering::SeqCst);
loop {
let next = current.saturating_add(delta);
match self.current.compare_exchange_weak(
current,
next,
Ordering::SeqCst,
Ordering::SeqCst,
) {
Ok(_) => return,
Err(observed) => current = observed,
}
}
}
}
impl TimeSource for VirtualTimeSource {
fn now(&self) -> u64 {
self.current.load(Ordering::SeqCst)
}
}