use std::time::{Instant, SystemTime, UNIX_EPOCH};
use super::error::ConsoleError;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct WallBase {
unix_ms: u64,
at: Instant,
}
impl WallBase {
pub fn now() -> Result<Self, ConsoleError> {
let at = Instant::now();
let since_epoch = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map_err(|error| ConsoleError::Clock {
reason: format!("the wall clock reads before the epoch: {error}"),
})?;
let unix_ms = u64::try_from(since_epoch.as_millis()).map_err(|_| ConsoleError::Clock {
reason: "the wall clock is past u64 milliseconds".to_owned(),
})?;
Ok(Self { unix_ms, at })
}
#[must_use]
pub const fn fixed(unix_ms: u64, at: Instant) -> Self {
Self { unix_ms, at }
}
pub fn unix_ms_at(&self, seen_at: Instant) -> Result<u64, ConsoleError> {
self.unix_ms_of(seen_at.max(self.at))
}
pub fn unix_ms_of(&self, at: Instant) -> Result<u64, ConsoleError> {
let wall = if at >= self.at {
u64::try_from(at.duration_since(self.at).as_millis())
.ok()
.and_then(|after| self.unix_ms.checked_add(after))
} else {
u64::try_from(self.at.duration_since(at).as_millis())
.ok()
.and_then(|before| self.unix_ms.checked_sub(before))
};
wall.ok_or_else(|| ConsoleError::Clock {
reason: "a time is outside u64 milliseconds since the epoch".to_owned(),
})
}
}