use core::cell::Cell;
use core::future::{Future, poll_fn};
use core::task::{Context, Poll, Waker};
use crate::blocking_mutex::Mutex;
use crate::blocking_mutex::raw::RawMutex;
pub struct Signal<M, T>
where
M: RawMutex,
{
state: Mutex<M, Cell<State<T>>>,
}
#[derive(Debug)]
enum State<T> {
None,
Waiting(Waker),
Signaled(T),
}
impl<M, T> Signal<M, T>
where
M: RawMutex,
{
pub const fn new() -> Self {
Self {
state: Mutex::new(Cell::new(State::None)),
}
}
}
impl<M, T> Default for Signal<M, T>
where
M: RawMutex,
{
fn default() -> Self {
Self::new()
}
}
impl<M, T> Signal<M, T>
where
M: RawMutex,
{
pub fn signal(&self, val: T) {
self.state.lock(|cell| {
let state = cell.replace(State::Signaled(val));
if let State::Waiting(waker) = state {
waker.wake();
}
})
}
pub fn reset(&self) {
self.try_take();
}
fn poll_wait(&self, cx: &mut Context<'_>) -> Poll<T> {
self.state.lock(|cell| {
let state = cell.replace(State::None);
match state {
State::None => {
cell.set(State::Waiting(cx.waker().clone()));
Poll::Pending
}
State::Waiting(w) if w.will_wake(cx.waker()) => {
cell.set(State::Waiting(w));
Poll::Pending
}
State::Waiting(w) => {
cell.set(State::Waiting(cx.waker().clone()));
w.wake();
Poll::Pending
}
State::Signaled(res) => Poll::Ready(res),
}
})
}
pub fn wait(&self) -> impl Future<Output = T> + '_ {
poll_fn(move |cx| self.poll_wait(cx))
}
pub fn try_take(&self) -> Option<T> {
self.state.lock(|cell| {
let state = cell.replace(State::None);
match state {
State::Signaled(res) => Some(res),
state => {
cell.set(state);
None
}
}
})
}
pub fn signaled(&self) -> bool {
self.state.lock(|cell| {
let state = cell.replace(State::None);
let res = matches!(state, State::Signaled(_));
cell.set(state);
res
})
}
}