use std::{
future::Future,
sync::{Arc, Mutex, RwLock},
task::{Poll, Waker},
};
#[derive(Debug)]
pub struct Event {
state: RwLock<bool>,
waiters: Mutex<Vec<Waiter<()>>>,
}
impl Event {
pub fn new() -> Self {
Self {
state: RwLock::new(false),
waiters: Mutex::new(vec![]),
}
}
pub async fn wait(&self) -> bool {
let state = *self.state.read().unwrap();
if !state {
let fut = Waiter::new();
{
let mut waiters = self.waiters.lock().unwrap();
waiters.push(fut.clone());
}
fut.await;
}
true
}
pub fn set(&self) {
{
let mut state = self.state.write().unwrap();
*state = true;
}
for i in self.waiters.lock().unwrap().iter() {
i.wake(());
}
}
pub fn clear(&self) {
*self.state.write().unwrap() = false;
}
pub fn is_set(&self) -> bool {
*self.state.read().unwrap()
}
}
impl Default for Event {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug)]
pub struct Waiter<T>(
#[allow(clippy::type_complexity)] Arc<Mutex<(bool, Option<Waker>, Option<T>)>>,
);
impl<T> Waiter<T> {
pub fn new() -> Self {
Self(Arc::new(Mutex::new((false, None, None))))
}
pub fn wake(&self, v: T) {
let mut state = self.0.lock().unwrap();
state.0 = true;
state.2 = Some(v);
if let Some(waker) = state.1.take() {
waker.wake();
}
}
}
impl<T> Default for Waiter<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> Future for Waiter<T> {
type Output = T;
fn poll(
self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Self::Output> {
let mut state = self.0.lock().unwrap();
if state.0 {
Poll::Ready(state.2.take().unwrap())
} else {
state.1 = Some(cx.waker().clone());
Poll::Pending
}
}
}