use super::std_timer_registration::StdTimerRegistration;
use super::std_timer_waiter::StdTimerWaiter;
use qubit_collections::map::OrderedIndexMap;
use std::sync::Arc;
use std::time::Instant;
pub(super) struct StdTimerSchedulerState {
next_waiter_id: u64,
registrations: OrderedIndexMap<u64, Instant, StdTimerRegistration>,
worker_running: bool,
worker_generation: u64,
}
impl StdTimerSchedulerState {
#[must_use]
#[inline]
pub(super) fn new() -> Self {
Self {
next_waiter_id: 1,
registrations: OrderedIndexMap::new(),
worker_running: false,
worker_generation: 0,
}
}
#[must_use = "the registration identifier is required for cancellation"]
pub(super) fn register(
&mut self,
deadline: Instant,
waiter: Arc<StdTimerWaiter>,
) -> u64 {
let waiter_id = self.allocate_waiter_id();
let inserted = self.registrations.try_insert(
waiter_id,
deadline,
StdTimerRegistration::new(deadline, waiter),
);
assert!(
inserted.is_ok(),
"standard Timer waiter identifier must be unique",
);
waiter_id
}
pub(super) fn cancel(
&mut self,
waiter_id: u64,
) -> Option<Arc<StdTimerWaiter>> {
let entry = self.registrations.remove(&waiter_id)?;
debug_assert_eq!(*entry.order(), entry.value().deadline());
let registration = entry.into_value();
Some(registration.into_waiter())
}
pub(super) fn take_due(
&mut self,
now: Instant,
) -> Vec<Arc<StdTimerWaiter>> {
self.registrations
.extract_range(..=now)
.map(|entry| {
debug_assert_eq!(*entry.order(), entry.value().deadline());
entry.into_value().into_waiter()
})
.collect()
}
#[must_use]
#[inline(always)]
pub(super) fn next_deadline(&self) -> Option<Instant> {
self.registrations.first().map(|entry| *entry.order())
}
#[must_use]
#[inline(always)]
pub(super) fn is_empty(&self) -> bool {
debug_assert_eq!(
self.registrations.len(),
self.registrations.attached_len()
);
self.registrations.is_empty()
}
#[must_use]
#[inline(always)]
pub(super) const fn worker_running(&self) -> bool {
self.worker_running
}
#[must_use]
#[inline]
pub(super) fn mark_worker_started(&mut self) -> u64 {
self.worker_generation = self.worker_generation.wrapping_add(1);
assert_ne!(
self.worker_generation, 0,
"standard Timer worker generations exhausted",
);
self.worker_running = true;
self.worker_generation
}
#[inline]
pub(super) fn mark_worker_stopped(&mut self, generation: u64) {
if self.worker_generation == generation {
self.worker_running = false;
}
}
#[must_use]
pub(super) fn stop_worker_and_take_waiters(
&mut self,
generation: u64,
) -> Vec<Arc<StdTimerWaiter>> {
if generation == 0 || self.worker_generation != generation {
return Vec::new();
}
self.worker_running = false;
let mut waiters = Vec::with_capacity(self.registrations.len());
while let Some(entry) = self.registrations.pop_first() {
waiters.push(entry.into_value().into_waiter());
}
waiters
}
#[must_use]
#[inline]
fn allocate_waiter_id(&mut self) -> u64 {
let waiter_id = self.next_waiter_id;
assert_ne!(waiter_id, 0, "standard Timer waiter identifiers exhausted");
self.next_waiter_id = waiter_id.wrapping_add(1);
waiter_id
}
}