use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::RwLock;
use std::task;
pub(crate) struct WakerRegistration {
needs_wakeup: AtomicBool,
waker: RwLock<Option<task::Waker>>,
}
impl WakerRegistration {
pub(crate) const fn new() -> WakerRegistration {
WakerRegistration {
needs_wakeup: AtomicBool::new(false),
waker: RwLock::new(None),
}
}
pub(crate) fn register(&self, waker: &task::Waker) -> bool {
let stored_waker = self.waker.read().unwrap();
if let Some(stored_waker) = &*stored_waker {
if stored_waker.will_wake(waker) {
self.needs_wakeup.store(true, Ordering::SeqCst);
return false;
}
}
drop(stored_waker);
let mut stored_waker = self.waker.write().unwrap();
if let Some(stored_waker) = &*stored_waker {
if stored_waker.will_wake(waker) {
self.needs_wakeup.store(true, Ordering::SeqCst);
return false;
}
}
*stored_waker = Some(waker.clone());
drop(stored_waker);
self.needs_wakeup.store(true, Ordering::SeqCst);
true
}
pub(crate) fn wake(&self) {
if !self.needs_wakeup.load(Ordering::SeqCst) {
return;
}
if self.needs_wakeup.swap(false, Ordering::SeqCst) {
if let Some(waker) = &*self.waker.read().unwrap() {
waker.wake_by_ref();
}
}
}
}