Hi,
I'm trying to implement an event bus where we can register handler to react to events.
For that I upcast a struct to a Box<Any>
to store it it the subscriptions list and then downcast_ref
to access the underlying trait object to dispatch the events.
The problem is that downcast_ref().unwrap()
panic and I don't understand why as I'm only trying to 'retrieve' the trait object I've stored earlier.
here is the code:
use std::any::{Any, TypeId};
use std::collections::HashMap;
#[derive(Debug)]
pub enum MyError {
A,
}
pub trait Subscription {
type Error;
type Message;
type Context;
fn handle(&self, ctx: &Self::Context, msg: &Self::Message) -> Result<(), Self::Error>;
}
struct CreateProfile;
struct AccountCreatedV1{
id: String,
}
#[derive(Debug)]
struct Context{}
impl Subscription for CreateProfile {
type Error = MyError;
type Message = AccountCreatedV1;
type Context = Context;
fn handle(&self, _ctx: &Self::Context, msg: &Self::Message) -> Result<(), Self::Error> {
println!("account created: {}", msg.id);
return Ok(());
}
}
type TypeMap<A> = HashMap<TypeId, A>;
struct Broker{
pub subscriptions: TypeMap<Vec<Box<Any>>>,
}
fn print_typeid<T: ?Sized + Any>(_s: &T) {
println!("{:?}", TypeId::of::<T>());
}
impl Broker {
fn new() -> Self {
return Broker{
subscriptions: HashMap::new(),
};
}
fn subscribe<S: Any, C, M: Any, E>(&mut self, subscription: S)
where S: Subscription<Context = C, Message = M, Error = E> {
let msg_id = TypeId::of::<M>();
let boxed = Box::new(subscription);
print_typeid(&boxed);
self.subscriptions.insert(msg_id, vec![boxed]);
}
fn publish<C: Any, M: Any, E: Any>(&mut self, ctx: &C, message: &M) -> Result<(), E> {
let msg_id = TypeId::of::<M>();
if let Some(subscriptions) = self.subscriptions.get_mut(&msg_id) {
for subscription in subscriptions {
// the line where it fails
let subscription: &Box<Subscription<Context = C, Message = M, Error = E>> = subscription.downcast_ref().expect("error downcasting");
subscription.handle(ctx, message)?;
}
}
return Ok(());
}
}
static mut EVENT_BUS: Option<Broker> = None;
fn event_bus() -> &'static mut Broker {
unsafe {
if EVENT_BUS.is_none() {
EVENT_BUS = Some(Broker::new());
}
return EVENT_BUS.as_mut().unwrap();
}
}
fn subscribe<S: Any, C: Any, M: Any, E>(subscription: S)
where S: Subscription<Context = C, Message = M, Error = E> {
event_bus().subscribe(subscription);
}
fn publish<C: Any, M: Any, E: Any>(ctx: &C, message: &M) -> Result<(), E> {
return event_bus().publish(ctx, message);
}
fn main() {
let ctx = Context{};
subscribe::<_, _, AccountCreatedV1, _>(CreateProfile{});
publish::<_, _, MyError>(&ctx, &AccountCreatedV1{
id: "123".to_string(),
}).unwrap();
println!("{:?}", ctx);
}
Best regards,
Sylvain