use std::panic::{AssertUnwindSafe, catch_unwind};
use std::sync::{Arc, RwLock};
use super::{OxideChannelError, OxideChannelResult};
pub trait OxideEventDuplexChannel {
type Outgoing: Clone + Send + 'static;
type Incoming: Send + 'static;
}
pub struct IncomingHandler<Incoming> {
handler: RwLock<Option<Arc<dyn Fn(Incoming) + Send + Sync + 'static>>>,
}
impl<Incoming> IncomingHandler<Incoming>
where
Incoming: Send + 'static,
{
pub fn new() -> Self {
Self {
handler: RwLock::new(None),
}
}
pub fn register(&self, handler: impl Fn(Incoming) + Send + Sync + 'static) {
let mut guard = self.handler.write().unwrap_or_else(|e| e.into_inner());
*guard = Some(Arc::new(handler));
}
pub fn handle(&self, event: Incoming) -> OxideChannelResult<()> {
let guard = self.handler.read().unwrap_or_else(|e| e.into_inner());
let handler = guard.clone();
let Some(handler) = handler else {
return Err(OxideChannelError::Unavailable);
};
match catch_unwind(AssertUnwindSafe(|| (handler)(event))) {
Ok(()) => Ok(()),
Err(_) => Err(OxideChannelError::PlatformError(
"incoming handler panicked".to_string(),
)),
}
}
}