use std::any::TypeId;
use flume::Sender;
use crate::{
bus::error::{CallEvent, CallTrace}, core::dyn_var::DynVar, util::dyn_debug::DynDebug, EventDef,
};
#[derive(Debug)]
pub enum BusInterfaceEvent {
Fire {
def: TypeId,
args: DynVar,
responder: Sender<Result<DynVar, CallTrace>>,
trace_data: CallEvent,
},
FwdBusError {
error: CallTrace,
blocker: Sender<()>,
},
}
#[derive(Debug)]
#[allow(clippy::module_name_repetitions)]
pub struct BusInterface {
pub(crate) channel: Sender<BusInterfaceEvent>,
}
impl BusInterface {
pub(crate) const fn new(sender: Sender<BusInterfaceEvent>) -> Self {
Self { channel: sender }
}
pub async fn fire<
Tag: unique_type::Unique,
At: DynDebug + Sync + Send + 'static,
Rt: DynDebug + Sync + Send + 'static,
>(
&mut self,
def: &'static EventDef<Tag, At, Rt>,
args: At,
) -> Result<Rt, CallTrace> {
let trace_data = CallEvent::from_event_def(def, &args);
let _ = def;
let def = TypeId::of::<Tag>();
let args = DynVar::new(args);
let (responder, response) = flume::bounded::<Result<DynVar, CallTrace>>(1);
self.channel
.send(BusInterfaceEvent::Fire {
def,
args,
responder,
trace_data,
})
.unwrap();
Ok(response
.into_recv_async()
.await
.unwrap()?
.try_to::<Rt>()
.unwrap())
}
pub async fn fwd_bus_err(
&self,
error: CallTrace,
) -> ! {
let (blocker, blocks) = flume::bounded::<()>(1);
self.channel
.send(BusInterfaceEvent::FwdBusError { error, blocker })
.unwrap();
blocks.recv_async().await.unwrap();
unreachable!()
}
}
#[async_trait]
pub trait BusErrorUtil<T> {
async fn unwrap_or_fwd(self, bus: &BusInterface) -> T;
}
#[async_trait]
impl<T: Send> BusErrorUtil<T> for Result<T, CallTrace> {
async fn unwrap_or_fwd(self, bus: &BusInterface) -> T {
match self {
Ok(x) => x,
Err(err) => bus.fwd_bus_err(err).await,
}
}
}