use core::{
cell::RefCell,
future::Future,
pin::Pin,
task::{
Context,
Poll,
Waker,
},
};
use cortex_m::interrupt::{
self,
Mutex,
};
struct FlagInner {
waker: Option<Waker>,
woken: bool,
}
pub struct Flag {
inner: Mutex<RefCell<FlagInner>>,
}
impl Flag {
pub const fn new() -> Flag {
Flag {
inner: Mutex::new(RefCell::new(FlagInner {
waker: None,
woken: false,
})),
}
}
fn modify<R>(&self, f: impl FnOnce(&mut FlagInner) -> R) -> R {
interrupt::free(move |cs| {
let mut lock = self.inner.borrow(cs).borrow_mut();
f(&mut *lock)
})
}
pub fn check(&self, waker: &Waker) -> bool {
self.modify(|inner| {
let woken = inner.woken;
inner.woken = false;
if !woken {
inner.waker = Some(waker.clone());
}
woken
})
}
pub fn wake(&self) {
self.modify(|timer_waker| {
timer_waker.woken = true;
if let Some(waker) = timer_waker.waker.take() {
waker.wake();
}
})
}
pub fn wait(&self) -> FlagWait<'_> {
FlagWait { inner: self }
}
}
pub struct FlagWait<'f> {
inner: &'f Flag,
}
impl<'f> Future for FlagWait<'f> {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
if self.inner.check(cx.waker()) {
Poll::Ready(())
} else {
Poll::Pending
}
}
}