fix up the event system, no more unsafe!

This commit is contained in:
lumi 2017-05-27 16:56:44 +02:00
commit c326d5b07e
8 changed files with 110 additions and 150 deletions

View file

@ -3,20 +3,41 @@ use std::any::{TypeId, Any};
use std::fmt::Debug;
use std::collections::BTreeMap;
use std::cmp::Ordering;
use std::sync::Arc;
use std::mem;
use std::ptr;
use std::raw::TraitObject;
use minidom::Element;
/// A marker trait which marks all events.
pub trait Event: Any + Debug {}
/// A trait which can be implemented when something can handle a specific kind of event.
pub trait EventHandler<E: Event>: Any {
/// A trait which is implemented for all event handlers.
trait EventHandler: Any {
/// Handle an event, returns whether to propagate the event to the remaining handlers.
fn handle(&self, event: &E) -> Propagation;
fn handle(&self, event: &AbstractEvent) -> Propagation;
}
/// An abstract event.
pub struct AbstractEvent {
inner: Box<Any>,
}
impl AbstractEvent {
/// Creates an abstract event from a concrete event.
pub fn new<E: Event>(event: E) -> AbstractEvent {
AbstractEvent {
inner: Box::new(event),
}
}
/// Downcasts this abstract event into a concrete event.
pub fn downcast<E: Event + 'static>(&self) -> Option<&E> {
self.inner.downcast_ref::<E>()
}
/// Checks whether this abstract event is a specific concrete event.
pub fn is<E: Event + 'static>(&self) -> bool {
self.inner.is::<E>()
}
}
struct Record<P, T>(P, T);
@ -49,21 +70,10 @@ pub enum Propagation {
Continue,
}
#[derive(Debug)]
struct GarbageEvent;
impl Event for GarbageEvent {}
impl<E, F> EventHandler<E> for Box<F> where E: Event, F: 'static + Fn(&E) -> Propagation {
fn handle(&self, evt: &E) -> Propagation {
self(evt)
}
}
/// An event dispatcher, this takes care of dispatching events to their respective handlers.
pub struct Dispatcher {
handlers: BTreeMap<TypeId, Vec<Record<Priority, Box<Any>>>>,
queue: Vec<(TypeId, Box<Any>)>,
handlers: BTreeMap<TypeId, Vec<Record<Priority, Box<EventHandler>>>>,
queue: Vec<(TypeId, AbstractEvent)>,
}
impl Dispatcher {
@ -76,17 +86,39 @@ impl Dispatcher {
}
/// Register an event handler.
pub fn register<E, H>(&mut self, priority: Priority, handler: H) where E: Event + 'static, H: EventHandler<E> {
let handler: Box<EventHandler<E>> = Box::new(handler) as Box<EventHandler<E>>;
pub fn register<E, F>(&mut self, priority: Priority, func: F)
where
E: Event,
F: Fn(&E) -> Propagation + 'static {
struct Handler<E, F> where E: Event, F: Fn(&E) -> Propagation {
func: F,
_marker: PhantomData<E>,
}
impl<E: Event, F: Fn(&E) -> Propagation + 'static> EventHandler for Handler<E, F> {
fn handle(&self, evt: &AbstractEvent) -> Propagation {
if let Some(e) = evt.downcast::<E>() {
(self.func)(e)
}
else {
Propagation::Continue
}
}
}
let handler: Box<EventHandler> = Box::new(Handler {
func: func,
_marker: PhantomData,
}) as Box<EventHandler>;
let ent = self.handlers.entry(TypeId::of::<E>())
.or_insert_with(|| Vec::new());
ent.push(Record(priority, Box::new(handler) as Box<Any>));
ent.push(Record(priority, handler));
ent.sort();
}
/// Append an event to the queue.
pub fn dispatch<E>(&mut self, event: E) where E: Event {
self.queue.push((TypeId::of::<E>(), Box::new(event) as Box<Any>));
self.queue.push((TypeId::of::<E>(), AbstractEvent::new(event)));
}
/// Flush all events in the queue so they can be handled by their respective handlers.
@ -97,19 +129,7 @@ impl Dispatcher {
'evts: for (t, evt) in q {
if let Some(handlers) = self.handlers.get_mut(&t) {
for &mut Record(_, ref mut handler) in handlers {
// GarbageEvent is a garbage type.
// The actual passed type is NEVER of this type.
let h: &mut EventHandler<GarbageEvent> = unsafe {
let handler_obj: &mut TraitObject = mem::transmute(handler);
let handler_inner: *mut TraitObject = mem::transmute(handler_obj.data);
mem::transmute(*handler_inner)
};
let e: &&GarbageEvent = unsafe {
let evt_ref: &Any = &evt;
let evt_obj: TraitObject = mem::transmute(evt_ref);
mem::transmute(evt_obj.data)
};
match h.handle(e) {
match handler.handle(&evt) {
Propagation::Stop => { continue 'evts; },
Propagation::Continue => (),
}
@ -124,53 +144,6 @@ impl Dispatcher {
pub fn flush_all(&mut self) {
while self.flush() {}
}
/// Dispatch an event to the handlers right now, without going through the queue.
pub fn dispatch_now<E>(&mut self, event: E) where E: Event {
if let Some(handlers) = self.handlers.get_mut(&TypeId::of::<E>()) {
for &mut Record(_, ref mut handler) in handlers {
let h = handler.downcast_mut::<Box<EventHandler<E>>>().unwrap();
match h.handle(&event) {
Propagation::Stop => { return; },
Propagation::Continue => (),
}
}
}
}
}
pub struct EventProxy<T: ?Sized, E: Event> {
inner: Arc<Box<T>>,
vtable: *mut (),
_event_type: PhantomData<E>,
}
impl<T: ?Sized, E: Event> EventProxy<T, E> {
/// Unsafe because T is assumed to be a TraitObject or at least have its shape.
/// If it is not, things will break. In a fascinatingly horrible manner.
/// Some people, such as myself, find it hilarious. Most people do not.
/// T is also assumed to actually support EventHandler<E>, if it does not, refer to above
/// statement.
pub unsafe fn new<H: EventHandler<E>>(inner: Arc<Box<T>>) -> EventProxy<T, E> {
let box_with_vtable = &*ptr::null::<H>() as &EventHandler<E>;
let obj: TraitObject = mem::transmute(box_with_vtable);
EventProxy {
inner: inner,
vtable: obj.vtable,
_event_type: PhantomData,
}
}
}
impl<T: ?Sized, E: Event> EventHandler<E> for EventProxy<T, E> where Box<T>: 'static {
fn handle(&self, evt: &E) -> Propagation {
let inner = Arc::into_raw(self.inner.clone());
let obj = TraitObject { data: unsafe { mem::transmute(inner) }, vtable: self.vtable };
let handler: &EventHandler<E> = unsafe { mem::transmute(obj) };
let prop = handler.handle(evt);
unsafe { Arc::<Box<T>>::from_raw(mem::transmute(inner)); }
prop
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
@ -205,10 +178,6 @@ mod tests {
fn test() {
let mut disp = Dispatcher::new();
struct MyHandler;
struct EvilHandler;
struct EventFilter;
#[derive(Debug)]
struct MyEvent {
should_be_42: u32,
@ -216,38 +185,31 @@ mod tests {
impl Event for MyEvent {}
impl EventHandler<MyEvent> for MyHandler {
fn handle(&self, evt: &MyEvent) -> Propagation {
if evt.should_be_42 == 42 {
panic!("success");
}
else {
panic!("not 42");
}
disp.register(Priority::Max, |evt: &MyEvent| {
if evt.should_be_42 == 42 {
Propagation::Continue
}
}
impl EventHandler<MyEvent> for EvilHandler {
fn handle(&self, _: &MyEvent) -> Propagation {
panic!("should not be called");
else {
Propagation::Stop
}
}
});
impl EventHandler<MyEvent> for EventFilter {
fn handle(&self, evt: &MyEvent) -> Propagation {
if evt.should_be_42 == 42 {
Propagation::Continue
}
else {
Propagation::Stop
}
disp.register(Priority::Min, |_: &MyEvent| {
panic!("should not be called");
});
disp.register(Priority::Default, |evt: &MyEvent| {
if evt.should_be_42 == 42 {
panic!("success");
}
}
else {
panic!("not 42");
}
});
disp.register(Priority::Max, EventFilter);
disp.register(Priority::Min, EvilHandler);
disp.register(Priority::Default, MyHandler);
disp.register(Priority::Min, EvilHandler);
disp.register(Priority::Min, |_: &MyEvent| {
panic!("should not be called");
});
disp.dispatch(MyEvent {
should_be_42: 39,