use crate::rand::{GlobalRng, Rng};
use futures_util::{select_biased, FutureExt};
use naive_timer::Timer;
use spin::Mutex;
#[doc(no_inline)]
pub use std::time::{Duration, Instant};
use std::{future::Future, sync::Arc, time::SystemTime};
pub mod error;
mod interval;
mod sleep;
mod system_time;
pub use self::interval::{interval, interval_at, Interval, MissedTickBehavior};
pub use self::sleep::{sleep, sleep_until, Sleep};
pub(crate) struct TimeRuntime {
handle: TimeHandle,
}
impl TimeRuntime {
pub fn new(rand: &GlobalRng) -> Self {
let base_time = SystemTime::UNIX_EPOCH
+ Duration::from_secs(
60 * 60 * 24 * 365 * (2022 - 1970)
+ rand.with(|rng| rng.gen_range(0..60 * 60 * 24 * 365)),
);
let handle = TimeHandle {
timer: Arc::new(Mutex::new(Timer::default())),
clock: Arc::new(Clock::new(base_time)),
};
TimeRuntime { handle }
}
pub fn handle(&self) -> &TimeHandle {
&self.handle
}
pub fn advance_to_next_event(&self) -> bool {
let mut timer = self.handle.timer.lock();
if let Some(mut time) = timer.next() {
time += Duration::from_nanos(50);
timer.expire(time);
self.handle.clock.set_elapsed(time);
true
} else {
false
}
}
#[allow(dead_code)]
pub fn now_instant(&self) -> Instant {
self.handle.now_instant()
}
}
#[derive(Clone)]
pub struct TimeHandle {
timer: Arc<Mutex<Timer>>,
clock: Arc<Clock>,
}
impl TimeHandle {
pub fn current() -> Self {
crate::context::current(|h| h.time.clone())
}
pub fn try_current() -> Option<Self> {
crate::context::try_current(|h| h.time.clone())
}
pub fn now_instant(&self) -> Instant {
self.clock.now_instant()
}
pub fn now_time(&self) -> SystemTime {
self.clock.now_time()
}
pub fn elapsed(&self) -> Duration {
self.clock.elapsed()
}
pub fn advance(&self, duration: Duration) {
let time = self.clock.advance(duration);
self.timer.lock().expire(time);
}
pub fn sleep(&self, duration: Duration) -> Sleep {
self.sleep_until(self.clock.now_instant() + duration)
}
pub fn sleep_until(&self, deadline: Instant) -> Sleep {
let min_deadline = self.clock.now_instant() + Duration::from_millis(1);
Sleep {
handle: self.clone(),
deadline: deadline.max(min_deadline),
}
}
pub fn timeout<T: Future>(
&self,
duration: Duration,
future: T,
) -> impl Future<Output = Result<T::Output, error::Elapsed>> {
let timeout = self.sleep(duration);
async move {
select_biased! {
res = future.fuse() => Ok(res),
_ = timeout.fuse() => Err(error::Elapsed),
}
}
}
pub(crate) fn add_timer_at(
&self,
deadline: Instant,
callback: impl FnOnce() + Send + Sync + 'static,
) {
let mut timer = self.timer.lock();
timer.add(deadline - self.clock.base_instant(), |_| callback());
}
pub(crate) fn add_timer(&self, dur: Duration, callback: impl FnOnce() + Send + Sync + 'static) {
self.add_timer_at(self.clock.now_instant() + dur, callback);
}
}
pub fn timeout<T: Future>(
duration: Duration,
future: T,
) -> impl Future<Output = Result<T::Output, error::Elapsed>> {
let handle = TimeHandle::current();
handle.timeout(duration, future)
}
#[cfg_attr(docsrs, doc(cfg(madsim)))]
pub fn advance(duration: Duration) {
let handle = TimeHandle::current();
handle.advance(duration);
}
struct Clock {
inner: Mutex<ClockInner>,
}
#[derive(Debug)]
struct ClockInner {
base_time: std::time::SystemTime,
base_instant: std::time::Instant,
advance: Duration,
}
impl Clock {
fn new(base_time: SystemTime) -> Self {
let clock = ClockInner {
base_time,
base_instant: unsafe { std::mem::zeroed() },
advance: Duration::default(),
};
Clock {
inner: Mutex::new(clock),
}
}
fn set_elapsed(&self, time: Duration) {
let mut inner = self.inner.lock();
inner.advance = time;
}
fn elapsed(&self) -> Duration {
let inner = self.inner.lock();
inner.advance
}
fn advance(&self, duration: Duration) -> Duration {
let mut inner = self.inner.lock();
inner.advance += duration;
inner.advance
}
fn base_instant(&self) -> Instant {
let inner = self.inner.lock();
inner.base_instant
}
fn now_instant(&self) -> Instant {
let inner = self.inner.lock();
inner.base_instant + inner.advance
}
fn now_time(&self) -> SystemTime {
let inner = self.inner.lock();
inner.base_time + inner.advance
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::runtime::Runtime;
#[test]
fn time() {
let runtime = Runtime::new();
runtime.block_on(async {
let t0 = Instant::now();
sleep(Duration::default()).await;
assert!(t0.elapsed() >= Duration::from_millis(1));
let t0 = Instant::now();
sleep_until(t0).await;
assert!(t0.elapsed() >= Duration::from_millis(1));
let t0 = Instant::now();
sleep(Duration::from_secs(1)).await;
assert!(t0.elapsed() >= Duration::from_secs(1));
sleep_until(t0 + Duration::from_secs(2)).await;
assert!(t0.elapsed() >= Duration::from_secs(2));
assert!(
timeout(Duration::from_secs(2), sleep(Duration::from_secs(1)))
.await
.is_ok()
);
assert!(
timeout(Duration::from_secs(1), sleep(Duration::from_secs(2)))
.await
.is_err()
);
});
}
#[test]
fn test_advance() {
let runtime = Runtime::new();
runtime.block_on(async {
let t0 = Instant::now();
advance(Duration::from_secs(1));
assert!(t0.elapsed() >= Duration::from_secs(1));
});
}
}