use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex, PoisonError};
use std::task::{Wake, Waker};
#[derive(Default)]
pub(crate) struct Signal {
landed: AtomicBool,
elapsed: Mutex<Option<f64>>,
transparent: AtomicBool,
lent: AtomicBool,
waker: Mutex<Option<Waker>>,
}
impl Signal {
pub(crate) fn landed(&self) -> bool {
self.landed.load(Ordering::Acquire)
}
pub(crate) fn clear(&self) {
self.landed.store(false, Ordering::Release);
}
pub(crate) fn set_waker(&self, waker: Waker) {
*self.waker.lock().unwrap_or_else(PoisonError::into_inner) = Some(waker);
}
pub(crate) fn lend(&self, waker: Waker, elapsed: Option<f64>, transparent: bool) -> Option<Waker> {
*self.elapsed.lock().unwrap_or_else(PoisonError::into_inner) = elapsed;
self.transparent.store(transparent, Ordering::Release);
self.lent.store(true, Ordering::Release);
self.waker.lock().unwrap_or_else(PoisonError::into_inner).replace(waker)
}
pub(crate) fn give_back(&self, waker: Option<Waker>) {
*self.waker.lock().unwrap_or_else(PoisonError::into_inner) = waker;
*self.elapsed.lock().unwrap_or_else(PoisonError::into_inner) = None;
self.transparent.store(false, Ordering::Release);
self.lent.store(false, Ordering::Release);
self.landed.store(true, Ordering::Release);
self.ask();
}
pub(crate) fn elapsed(&self) -> Option<f64> {
*self.elapsed.lock().unwrap_or_else(PoisonError::into_inner)
}
pub(crate) fn transparent(&self) -> bool {
self.transparent.load(Ordering::Acquire)
}
pub(crate) fn lent(&self) -> bool {
self.lent.load(Ordering::Acquire)
}
pub(crate) fn ask(&self) {
if let Some(waker) = self.waker.lock().unwrap_or_else(PoisonError::into_inner).as_ref() {
waker.wake_by_ref();
}
}
}
impl Wake for Signal {
fn wake(self: Arc<Self>) {
self.wake_by_ref();
}
fn wake_by_ref(self: &Arc<Self>) {
self.landed.store(true, Ordering::Release);
self.ask();
}
}