use std::ffi::OsString;
use std::time::{SystemTime, UNIX_EPOCH};
use crate::StoreError;
pub const EPOCH_ENV: &str = "SOURCE_DATE_EPOCH";
pub trait Clock {
fn now(&self) -> Result<u64, StoreError>;
}
#[derive(Debug, Clone, Default)]
pub struct SystemClock {
epoch: Option<OsString>,
}
impl SystemClock {
#[must_use]
pub fn from_env() -> Self {
Self::with_epoch(std::env::var_os(EPOCH_ENV))
}
#[must_use]
pub fn with_epoch(epoch: Option<impl Into<OsString>>) -> Self {
Self {
epoch: epoch.map(Into::into),
}
}
}
impl Clock for SystemClock {
fn now(&self) -> Result<u64, StoreError> {
match &self.epoch {
Some(epoch) => epoch
.to_str()
.filter(|text| !text.is_empty() && text.bytes().all(|byte| byte.is_ascii_digit()))
.and_then(|text| text.parse().ok())
.ok_or_else(|| StoreError::Epoch(epoch.to_string_lossy().into_owned())),
None => Ok(SystemTime::now()
.duration_since(UNIX_EPOCH)
.map_err(|_| StoreError::Epoch("a system time before 1970".to_owned()))?
.as_secs()),
}
}
}