Skip to content

Instantly share code, notes, and snippets.

@sum-catnip
Last active May 16, 2023 15:28
Show Gist options
  • Save sum-catnip/fb05c59ae2930c9c9b0a6a311c4d0c14 to your computer and use it in GitHub Desktop.
Save sum-catnip/fb05c59ae2930c9c9b0a6a311c4d0c14 to your computer and use it in GitHub Desktop.
rust event system type erasure
/// [dependencies]
/// calloop = "0.10.5"
///
/// TODO: in the current implementation when you add a new handler
/// inside another handler
/// and then emit an event before all handlers have been called
/// the new handler will be called twice
/// gotta think about how to fix that
use std::cell::{ RefCell, RefMut };
use std::time::Duration;
use std::any::{ Any, TypeId };
use std::collections::HashMap;
use std::rc::Rc;
use calloop::LoopHandle;
use calloop::ping::Ping;
use calloop::{ EventLoop, EventSource };
trait MeowHandler {
type Event;
fn handle(&mut self, state: &mut MeowLoop, e: &Self::Event);
}
struct TestHandler {
c1: usize,
ping: Ping
}
impl MeowHandler for TestHandler {
type Event = ();
fn handle(&mut self, state: &mut MeowLoop, _e: &Self::Event) {
println!("c1: {}", self.c1);
if self.c1 == 69 {
state.attach_handler(TestHandler { c1: 6969, ping: self.ping.clone() });
self.c1 = 0;
self.ping.ping();
}
}
}
struct MeowLoop {
handle: LoopHandle<'static, Self>,
events: HashMap<TypeId, Vec<Rc<RefCell<dyn Any>>>>
}
struct HandlerWrapper<E>(Box<dyn MeowHandler<Event = E>>);
impl MeowLoop {
pub fn new(handle: LoopHandle<'static, Self>) -> Self {
Self {
handle,
events: HashMap::new()
}
}
pub fn register_source<S, E>(&mut self, source: S)
where S: EventSource<Ret = (), Event = E> + 'static, E: 'static {
let id = TypeId::of::<E>();
self.events.entry(id.clone()).or_default();
let _ = self.handle.insert_source(source, move |e, _, state| {
let mut i = 0;
let handlers_current: Vec<_> = state
.events[&id]
.iter()
.map(|e| e.clone())
.collect();
for handler in handlers_current {
let mut refcell: RefMut<dyn Any> = handler.borrow_mut();
let handler = refcell.downcast_mut::<HandlerWrapper<E>>().unwrap();
handler.0.handle(state, &e);
}
});
}
pub fn attach_handler<E, H>(&mut self, handler: H)
where H: MeowHandler<Event = E> + 'static, E: 'static {
let id = TypeId::of::<E>();
let handlers = self.events.entry(id.clone()).or_default();
handlers.push(Rc::new(RefCell::new(HandlerWrapper(Box::new(handler)))));
}
}
fn main() {
let mut loop_ = EventLoop::try_new_high_precision().unwrap();
let mut ml: MeowLoop = MeowLoop::new(loop_.handle());
// register events and stuff
let (ping, ping_source) = calloop::ping::make_ping().unwrap();
ml.register_source(ping_source);
ml.attach_handler(TestHandler { c1: 69, ping: ping.clone() });
ml.attach_handler(TestHandler { c1: 420, ping: ping.clone() });
//ml.connect(ping_source, TestHandler {c1: 0});
ping.ping();
loop_.run(
Duration::from_secs(5),
&mut ml,
|_: &mut MeowLoop| println!("still alive!"))
.unwrap();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment