use core::task;
use s2n_quic_core::{ensure, state::is, task::waker::noop};
use std::sync::Mutex;
#[derive(Debug)]
pub struct Waker {
state: Mutex<State>,
}
#[derive(Debug)]
struct State {
waker: task::Waker,
status: Status,
}
impl Default for Waker {
#[inline]
fn default() -> Self {
Self {
state: Mutex::new(State {
waker: noop(),
status: Status::Sleeping,
}),
}
}
}
impl Waker {
#[inline]
pub fn update(&self, waker: &task::Waker) {
self.state.lock().unwrap().waker = waker.clone();
}
#[inline]
pub fn wake(&self) {
let state = self.state.lock().unwrap();
ensure!(matches!(state.status, Status::Sleeping));
let waker = state.waker.clone();
drop(state);
waker.wake();
}
#[inline]
pub fn wake_forced(&self) {
let waker = self.state.lock().unwrap().waker.clone();
waker.wake();
}
#[inline]
pub fn on_worker_wake(&self) {
self.swap_status(Status::Working);
}
#[inline]
pub fn on_worker_sleep(&self) -> Status {
self.swap_status(Status::Sleeping)
}
#[inline]
fn swap_status(&self, status: Status) -> Status {
let mut state = self.state.lock().unwrap();
core::mem::replace(&mut state.status, status)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Status {
Sleeping,
PendingWork,
Working,
}
impl Status {
is!(is_sleeping, Sleeping);
is!(is_pending_work, PendingWork);
is!(is_working, Working);
}