Skip to main content

coven_database/
stored_millis.rs

1//! Waits and times as coven's tables store them: whole milliseconds, a time
2//! counted from the Unix epoch.
3
4use crate::DbError;
5use std::time::{Duration, SystemTime};
6
7/// Which way a stored value rounds a part of a millisecond.
8#[derive(Clone, Copy)]
9pub(crate) enum Round {
10    /// Up, so a stored wait or end never comes before the one it stores.
11    Up,
12    /// Down, so a stored moment never comes after the one it stores.
13    Down,
14}
15
16/// `duration` in whole milliseconds, rounded `round`; none past SQLite's
17/// integers.
18pub(crate) fn millis(duration: Duration, round: Round) -> Option<i64> {
19    let millis = match round {
20        Round::Up => duration.as_nanos().div_ceil(1_000_000),
21        Round::Down => duration.as_millis(),
22    };
23    i64::try_from(millis).ok()
24}
25
26/// `time` in milliseconds since the Unix epoch, rounded `round`; none
27/// before the epoch or past SQLite's integers.
28pub(crate) fn since_epoch(time: SystemTime, round: Round) -> Option<i64> {
29    millis(time.duration_since(SystemTime::UNIX_EPOCH).ok()?, round)
30}
31
32/// The wait a stored count of milliseconds names. A negative one is a
33/// stored fact that doesn't decode: `DamagedDatabase` (§19.3).
34pub(crate) fn stored_wait(millis: i64) -> Result<Duration, DbError> {
35    Ok(Duration::from_millis(u64::try_from(millis).map_err(|_negative| DbError::DamagedDatabase)?))
36}
37
38/// The time a stored count of milliseconds since the Unix epoch names, as
39/// `coven_retry_effect.cooling_until` and `coven_sync_status.last_synced`
40/// hold it. One the clock can't name is `DamagedDatabase` (§19.3).
41pub fn stored_time(millis: i64) -> Result<SystemTime, DbError> {
42    SystemTime::UNIX_EPOCH.checked_add(stored_wait(millis)?).ok_or(DbError::DamagedDatabase)
43}