use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Mutex;
#[cfg(not(target_arch = "wasm32"))]
use std::time::{SystemTime, UNIX_EPOCH};
#[cfg(target_arch = "wasm32")]
use wasmtimer::std::{SystemTime, UNIX_EPOCH};
use super::{u16_u64_to_versionstamp, u64_to_versionstamp, u64_u16_to_versionstamp, Versionstamp};
#[allow(unused)]
pub enum Oracle {
SysTimeCounter(SysTimeCounter),
EpochCounter(EpochCounter),
}
impl Oracle {
#[allow(unused)]
pub fn systime_counter() -> Self {
Oracle::SysTimeCounter(SysTimeCounter {
state: Mutex::new((0, 0)),
stale: (0, 0),
})
}
#[allow(unused)]
pub fn epoch_counter() -> Self {
Oracle::EpochCounter(EpochCounter {
epoch: 0,
counter: AtomicU64::new(0),
})
}
#[allow(unused)]
pub fn now(&mut self) -> Versionstamp {
match self {
Oracle::SysTimeCounter(sys) => sys.now(),
Oracle::EpochCounter(epoch) => epoch.now(),
}
}
}
pub struct SysTimeCounter {
state: Mutex<(u64, u16)>,
stale: (u64, u16),
}
impl SysTimeCounter {
pub fn now(&mut self) -> Versionstamp {
let state = self.state.lock();
if let Ok(mut state) = state {
let (last_physical_time, counter) = *state;
let current_physical_time = secs_since_unix_epoch();
let current_logical_time = if last_physical_time == current_physical_time {
counter
} else {
state.1 = 0;
0
};
state.0 = current_physical_time;
state.1 += 1;
self.stale = (current_physical_time, current_logical_time);
u64_u16_to_versionstamp(current_physical_time, current_logical_time)
} else {
u64_u16_to_versionstamp(self.stale.0, self.stale.1)
}
}
}
pub struct EpochCounter {
epoch: u16,
counter: AtomicU64,
}
impl EpochCounter {
#[allow(unused)]
pub fn now(&mut self) -> Versionstamp {
let counter = self.counter.fetch_add(1, Ordering::SeqCst);
u16_u64_to_versionstamp(self.epoch, counter)
}
}
#[allow(unused)]
fn now() -> Versionstamp {
let secs = secs_since_unix_epoch();
u64_to_versionstamp(secs)
}
#[allow(unused)]
fn secs_since_unix_epoch() -> u64 {
match SystemTime::now().duration_since(UNIX_EPOCH) {
Ok(duration) => duration.as_secs(),
Err(error) => panic!("Clock may have gone backwards: {:?}", error.duration()),
}
}
mod tests {
#[allow(unused)]
use super::*;
#[allow(unused)]
use crate::vs::to_u128_be;
#[test]
fn systime_counter() {
let mut o = Oracle::systime_counter();
let a = to_u128_be(o.now());
let b = to_u128_be(o.now());
assert!(a < b, "a = {}, b = {}", a, b);
}
#[test]
fn epoch_counter() {
let mut o1 = Oracle::epoch_counter();
let a = to_u128_be(o1.now());
let b = to_u128_be(o1.now());
assert!(a < b, "a = {}, b = {}", a, b);
let mut o2 = Oracle::EpochCounter(EpochCounter {
epoch: 1,
counter: AtomicU64::new(0),
});
let c = to_u128_be(o2.now());
assert!(b < c, "b = {}, c = {}", b, c);
}
}