use anyhow::Result;
use std::sync::{Arc, LazyLock};
use crate::events::handle::EventHandle;
use crate::events::slot::EventAwaiter;
static DROP_POISON_REASON: LazyLock<Arc<str>> =
LazyLock::new(|| Arc::from("event dropped without being triggered"));
pub trait EventBackend: Send + Sync {
fn trigger(&self, handle: EventHandle) -> Result<()>;
fn poison(&self, handle: EventHandle, reason: Arc<str>) -> Result<()>;
fn awaiter(&self, handle: EventHandle) -> Result<EventAwaiter>;
}
pub struct Event {
inner: Option<EventInner>,
}
struct EventInner {
handle: EventHandle,
backend: Arc<dyn EventBackend>,
}
impl Event {
pub(crate) fn new(handle: EventHandle, backend: Arc<dyn EventBackend>) -> Self {
Self {
inner: Some(EventInner { handle, backend }),
}
}
fn take_inner(&mut self) -> EventInner {
self.inner.take().expect("event already consumed")
}
pub fn handle(&self) -> EventHandle {
self.inner.as_ref().expect("event already consumed").handle
}
pub fn trigger(mut self) -> Result<()> {
let inner = self.take_inner();
inner.backend.trigger(inner.handle)
}
pub fn poison(mut self, reason: impl Into<Arc<str>>) -> Result<()> {
let inner = self.take_inner();
inner.backend.poison(inner.handle, reason.into())
}
pub fn awaiter(&self) -> Result<EventAwaiter> {
let inner = self.inner.as_ref().expect("event already consumed");
inner.backend.awaiter(inner.handle)
}
pub fn into_handle(mut self) -> EventHandle {
self.take_inner().handle
}
}
impl Drop for Event {
fn drop(&mut self) {
if let Some(inner) = self.inner.take() {
let _ = inner
.backend
.poison(inner.handle, Arc::clone(&*DROP_POISON_REASON));
}
}
}