use crate::interrupt::Interrupt;
use crate::local_only::LocalOnly;
use crate::slim_event::SlimEvent;
use mesh::MeshPayload;
use pal_async::driver::Driver;
use pal_async::wait::PolledWait;
use pal_event::Event;
use parking_lot::Mutex;
use std::future::poll_fn;
use std::future::Future;
use std::sync::Arc;
use std::task::Context;
use std::task::Poll;
#[derive(Debug, Clone, MeshPayload)]
pub struct Notify(Inner);
impl Notify {
pub fn from_event(event: Event) -> Self {
Self(Inner::Event(event))
}
pub fn from_slim_event(event: Arc<SlimEvent>) -> Self {
Self(Inner::SlimEvent(LocalOnly(event)))
}
pub fn pollable(self, driver: &(impl Driver + ?Sized)) -> std::io::Result<PolledNotify> {
Ok(PolledNotify(match self.0 {
Inner::Event(e) => PolledInner::Event(Mutex::new(PolledWait::new(driver, e)?)),
Inner::SlimEvent(LocalOnly(e)) => PolledInner::SlimEvent(e),
}))
}
pub fn event(&self) -> Option<&Event> {
match &self.0 {
Inner::Event(e) => Some(e),
Inner::SlimEvent(_) => None,
}
}
pub fn interrupt(self) -> Interrupt {
match self.0 {
Inner::Event(e) => Interrupt::from_event(e),
Inner::SlimEvent(LocalOnly(e)) => Interrupt::from_fn(move || e.signal()),
}
}
}
pub struct PolledNotify(PolledInner);
#[derive(Debug, MeshPayload)]
enum Inner {
Event(Event),
SlimEvent(LocalOnly<Arc<SlimEvent>>),
}
impl Clone for Inner {
fn clone(&self) -> Self {
match self {
Self::Event(event) => Self::Event(event.clone()),
Self::SlimEvent(event) => Self::SlimEvent(event.clone()),
}
}
}
enum PolledInner {
Event(Mutex<PolledWait<Event>>),
SlimEvent(Arc<SlimEvent>),
}
impl PolledNotify {
pub fn poll_wait(&self, cx: &mut Context<'_>) -> Poll<()> {
match &self.0 {
PolledInner::Event(e) => e
.lock()
.poll_wait(cx)
.map(|r| r.expect("waits on Event cannot fail")),
PolledInner::SlimEvent(e) => e.poll_wait(cx),
}
}
pub fn wait(&mut self) -> impl '_ + Unpin + Future<Output = ()> {
poll_fn(move |cx| match &mut self.0 {
PolledInner::Event(e) => e
.get_mut()
.poll_wait(cx)
.map(|r| r.expect("waits on Event cannot fail")),
PolledInner::SlimEvent(e) => e.poll_wait(cx),
})
}
pub fn into_inner(self) -> Notify {
Notify(match self.0 {
PolledInner::Event(e) => Inner::Event(e.into_inner().into_inner()),
PolledInner::SlimEvent(e) => Inner::SlimEvent(LocalOnly(e)),
})
}
}