Last active
May 16, 2023 15:28
-
-
Save sum-catnip/fb05c59ae2930c9c9b0a6a311c4d0c14 to your computer and use it in GitHub Desktop.
rust event system type erasure
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// [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