use std::{
any::{Any, TypeId},
fmt::Debug,
ops::Deref,
};
use crate::network::{Network, Socket};
pub trait Message: Any + Send + Sync + Debug + 'static {}
impl<T> Message for T where T: Send + Sync + Any + Debug + 'static {}
pub trait Envelope: Send + Sync + Debug + 'static {
fn type_id(&self) -> TypeId;
fn wrap<M: Message>(message: M) -> Self;
fn downcast<M: Message>(&self) -> Option<impl Deref<Target = M> + '_>;
}
pub trait Handler<M> {
type Reply: Message;
fn handle(&mut self, message: &M) -> Option<Self::Reply>;
}
#[allow(type_alias_bounds)]
pub(crate) type MessageHandlerFn<N: Network> = Box<
dyn Fn(&mut dyn Any, &<N::Socket as Socket>::Envelope) -> Option<<N::Socket as Socket>::Envelope>
+ Send
+ Sync,
>;
pub(crate) fn create_handler<M, L, N>() -> MessageHandlerFn<N>
where
L: Handler<M> + 'static,
M: Message,
N: Network, {
Box::new(move |agent: &mut dyn Any, envelope: &<N::Socket as Socket>::Envelope| {
let Some(typed_agent) = agent.downcast_mut::<L>() else {
unreachable!("type mismatch: agent is not the expected Handler type");
};
let Some(message) = envelope.downcast::<M>() else {
tracing::error!(type_id = ?TypeId::of::<M>(), "failed to downcast message");
return None;
};
typed_agent.handle(&*message).map(<N::Socket as Socket>::Envelope::wrap)
})
}