use std::sync::Arc;
use std::time::Instant;
use qubit_collections::map::OrderedIndexMap;
use super::std_timer_registration::StdTimerRegistration;
use super::std_timer_waiter::StdTimerWaiter;
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
}
}