use core::task::Waker;
use core::time::Duration;
use std::sync::Mutex;
use std::vec::Vec;
use crate::time::{Driver, Instant};
pub static DRIVER: MockDriver = MockDriver::new();
pub struct MockDriver {
state: Mutex<MockState>,
}
struct MockState {
now: Duration,
pending: Vec<(Instant, Waker)>,
}
impl MockDriver {
#[must_use]
pub const fn new() -> Self {
Self {
state: Mutex::new(MockState {
now: Duration::ZERO,
pending: Vec::new(),
}),
}
}
pub fn advance(&self, delta: Duration) {
let to_wake = {
let mut state = self.state.lock().unwrap_or_else(|err| err.into_inner());
state.now = state.now.saturating_add(delta);
let cutoff = Instant::from_monotonic(state.now);
let mut still_pending = Vec::with_capacity(state.pending.len());
let mut fired = Vec::new();
for entry in state.pending.drain(..) {
if entry.0 <= cutoff {
fired.push(entry.1);
} else {
still_pending.push(entry);
}
}
state.pending = still_pending;
fired
};
for waker in to_wake {
waker.wake();
}
}
pub fn reset(&self) {
let mut state = self.state.lock().unwrap_or_else(|err| err.into_inner());
state.now = Duration::ZERO;
state.pending.clear();
}
}
impl Default for MockDriver {
fn default() -> Self {
Self::new()
}
}
impl Driver for MockDriver {
fn now(&self) -> Instant {
let state = self.state.lock().unwrap_or_else(|err| err.into_inner());
Instant::from_monotonic(state.now)
}
fn schedule_wake(&self, deadline: Instant, waker: Waker) {
let mut state = self.state.lock().unwrap_or_else(|err| err.into_inner());
let now = Instant::from_monotonic(state.now);
if deadline <= now {
drop(state);
waker.wake();
} else {
state.pending.push((deadline, waker));
}
}
}