use std::error::Error;
use std::fmt;
use std::sync::{Arc, Mutex, PoisonError};
use std::time::{Duration, SystemTime};
use oxide_batch::Clock;
#[derive(Clone, Debug)]
pub struct ManualClock {
current: Arc<Mutex<SystemTime>>,
}
impl ManualClock {
#[must_use]
pub fn new(initial: SystemTime) -> Self {
Self {
current: Arc::new(Mutex::new(initial)),
}
}
#[must_use]
pub fn now(&self) -> SystemTime {
*self.current.lock().unwrap_or_else(PoisonError::into_inner)
}
pub fn set(&self, instant: SystemTime) {
*self.current.lock().unwrap_or_else(PoisonError::into_inner) = instant;
}
pub fn advance(&self, duration: Duration) -> Result<SystemTime, ManualClockError> {
let mut current = self.current.lock().unwrap_or_else(PoisonError::into_inner);
let advanced = current
.checked_add(duration)
.ok_or(ManualClockError::Overflow)?;
*current = advanced;
Ok(advanced)
}
}
impl Clock for ManualClock {
fn now(&self) -> SystemTime {
Self::now(self)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ManualClockError {
Overflow,
}
impl fmt::Display for ManualClockError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("manual clock advance overflowed")
}
}
impl Error for ManualClockError {}