#[cfg(not(all(loom, feature = "loom-model")))]
use std::sync::Mutex;
use std::task::Context;
use std::task::Poll;
use std::task::Waker;
#[cfg(all(loom, feature = "loom-model"))]
use loom::sync::Mutex;
use super::std_timer_waiter_state::StdTimerWaiterState;
pub(crate) struct StdTimerWaiter {
state: Mutex<StdTimerWaiterState>,
}
impl StdTimerWaiter {
#[must_use]
#[inline]
pub(crate) fn new() -> Self {
Self {
state: Mutex::new(StdTimerWaiterState::new()),
}
}
pub(crate) fn poll(&self, context: &Context<'_>) -> Poll<Result<(), ()>> {
let replaced_waker = {
let mut state = self.state.lock().unwrap_or_else(std::sync::PoisonError::into_inner);
match &mut *state {
StdTimerWaiterState::Pending(waker)
if waker.as_ref().is_some_and(|value| value.will_wake(context.waker())) =>
{
None
}
StdTimerWaiterState::Pending(waker) => waker.replace(context.waker().clone()),
StdTimerWaiterState::Ready => return Poll::Ready(Ok(())),
StdTimerWaiterState::WorkerFailed => {
return Poll::Ready(Err(()));
}
}
};
drop(replaced_waker);
Poll::Pending
}
#[must_use = "the detached Waker must be invoked or safely discarded"]
#[inline(always)]
pub(crate) fn complete(&self) -> Option<Waker> {
self.transition_to(StdTimerWaiterState::Ready)
}
#[must_use = "the detached Waker must be invoked or safely discarded"]
#[inline(always)]
pub(crate) fn fail(&self) -> Option<Waker> {
self.transition_to(StdTimerWaiterState::WorkerFailed)
}
fn transition_to(&self, terminal: StdTimerWaiterState) -> Option<Waker> {
let mut state = self.state.lock().unwrap_or_else(std::sync::PoisonError::into_inner);
match &mut *state {
StdTimerWaiterState::Pending(waker) => {
let detached = waker.take();
*state = terminal;
detached
}
StdTimerWaiterState::Ready | StdTimerWaiterState::WorkerFailed => None,
}
}
}