use core::future::poll_fn;
use core::task::{Context, Poll};
use embassy_sync::blocking_mutex::raw::RawMutex;
use embassy_sync::waitqueue::WakerRegistration;
use crate::utils::cell::RefCell;
use crate::utils::init::{init, Init};
use super::blocking::raw::MatterRawMutex;
use super::blocking::Mutex;
struct State<S> {
state: S,
waker: WakerRegistration,
}
impl<S> State<S> {
const fn new(state: S) -> Self {
Self {
state,
waker: WakerRegistration::new(),
}
}
fn init<I: Init<S>>(state: I) -> impl Init<Self> {
init!(Self {
state <- state,
waker: WakerRegistration::new(),
})
}
}
pub struct Signal<S, M = MatterRawMutex> {
inner: Mutex<RefCell<State<S>>, M>,
}
impl<S, M> Signal<S, M>
where
M: RawMutex,
{
pub const fn new(state: S) -> Self {
Self {
inner: Mutex::new(RefCell::new(State::new(state))),
}
}
pub fn init<I: Init<S>>(state: I) -> impl Init<Self> {
init!(Self {
inner <- Mutex::init(RefCell::init(State::init(state))),
})
}
pub fn modify<F, R>(&self, f: F) -> R
where
F: FnOnce(&mut S) -> (bool, R),
{
self.inner.lock(|s| {
let mut s = s.borrow_mut();
let (wake, result) = f(&mut s.state);
if wake {
s.waker.wake();
}
result
})
}
pub async fn wait<F, R>(&self, mut f: F) -> R
where
F: FnMut(&mut S) -> Option<R>,
{
poll_fn(move |ctx| self.poll_wait(ctx, &mut f)).await
}
pub fn poll_wait<F, R>(&self, ctx: &mut Context, f: F) -> Poll<R>
where
F: FnOnce(&mut S) -> Option<R>,
{
self.inner.lock(|s| {
let mut s = s.borrow_mut();
if let Some(result) = f(&mut s.state) {
Poll::Ready(result)
} else {
s.waker.register(ctx.waker());
Poll::Pending
}
})
}
}
impl<T, M> Signal<Option<T>, M>
where
M: RawMutex,
{
pub fn signal(&self, value: T) {
self.modify(|state| {
*state = Some(value);
(true, ())
});
}
pub async fn wait_signalled(&self) -> T {
self.wait(|state| state.take()).await
}
}