use core::cell::UnsafeCell;
use core::sync::atomic::AtomicU8;
use core::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release};
use core::task::Poll;
use core::task::Waker;
pub type AtomicWaker = UnsafeCell<Option<Waker>>;
pub type AtomicWakerState = AtomicU8;
const IDLING: u8 = 0;
const REGISTERING: u8 = 0b001;
const WAKING: u8 = 0b010;
const AWOKEN: u8 = 0b100;
pub fn poll_const(atomic_waker: &AtomicWaker, state: &AtomicWakerState, waker: &Waker) -> Poll<()> {
match state.fetch_or(REGISTERING, Acquire) {
IDLING => {
match unsafe { &mut *atomic_waker.get() } {
Some(old_waker) if old_waker.will_wake(waker) => (),
new_waker => *new_waker = Some(waker.clone()),
}
let prev = state.swap(IDLING, AcqRel);
if prev & WAKING != 0 {
Poll::Ready(())
} else {
Poll::Pending
}
}
prev if prev & REGISTERING != 0 => {
Poll::Pending
}
prev if prev & AWOKEN != 0 => {
debug_assert!(prev == AWOKEN || prev == WAKING | AWOKEN);
state.store(IDLING, Release);
Poll::Ready(())
}
prev => {
debug_assert!(prev == WAKING);
while state.load(Relaxed) & AWOKEN != 0 {
core::hint::spin_loop();
}
Poll::Ready(())
}
}
}
pub fn wake(atomic_waker: &AtomicWaker, state: &AtomicWakerState) {
match state.fetch_or(WAKING, AcqRel) {
IDLING => {
let waker = unsafe { (*atomic_waker.get()).take() };
state.store(AWOKEN, Release);
if let Some(waker) = waker {
waker.wake();
}
}
_ => {
}
}
}