diff --git a/src/lib.rs b/src/lib.rs index 105b7ef..4662abd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,41 +49,76 @@ macro_rules! register_hook { macro_rules! post_event { // TODO allow multiple $t:ty at once and re-#[doc(hidden)] the low-level get_post_targets and // get_event_id - ($b:expr, $t:ty, $e:expr) => { + ($b:expr, $e:expr, $($t:ty),+) => { { // hygiene let bus: &$crate::EventBus = $b; // event setup, this may evaluate to any type. let event: &mut _ = $e; { - // it is a logic error for an event's cancellability to change based on its value. - static CANCELLABLE: ::std::sync::atomic::AtomicBool = ::std::sync::atomic::ATOMIC_BOOL_INIT; - static CANCELLABLE_INIT: ::std::sync::Once = ::std::sync::ONCE_INIT; - CANCELLABLE_INIT.call_once(|| { - CANCELLABLE.store(<$crate::Event>::cancellable(event), std::sync::atomic::Ordering::Relaxed); - }); - let cancellable = CANCELLABLE.load(std::sync::atomic::Ordering::Relaxed); + let _ = ($({ + // event type setup + static EVENT_ID: ::std::sync::atomic::AtomicUsize = ::std::sync::atomic::ATOMIC_USIZE_INIT; + static EVENT_ID_INIT: ::std::sync::Once = ::std::sync::ONCE_INIT; + // no generics allowed. + static DUMMY: ::std::marker::PhantomData = ::std::marker::PhantomData; + EVENT_ID_INIT.call_once(|| { + EVENT_ID.store($crate::get_event_id::<$t>(), std::sync::atomic::Ordering::Relaxed); + }); + let id = EVENT_ID.load(std::sync::atomic::Ordering::Relaxed); + let handlers = $crate::get_post_targets::<$t>(bus, event, id); - // event type setup - static EVENT_ID: ::std::sync::atomic::AtomicUsize = ::std::sync::atomic::ATOMIC_USIZE_INIT; - static EVENT_ID_INIT: ::std::sync::Once = ::std::sync::ONCE_INIT; - // no generics allowed. - static DUMMY: ::std::marker::PhantomData = ::std::marker::PhantomData; - EVENT_ID_INIT.call_once(|| { - EVENT_ID.store($crate::get_event_id::<$t>(), std::sync::atomic::Ordering::Relaxed); - }); - let id = EVENT_ID.load(std::sync::atomic::Ordering::Relaxed); - - // handler retrieval and invokation - let event: &mut $t = event; - let handlers = $crate::get_post_targets::<$t>(bus, event, id); - for (_pri, fun) in handlers.iter() { - fun(event); - if cancellable && <$t as $crate::Event>::cancelled(event) { - break; + for (_pri, fun) in handlers.iter() { + fun(event); } + },)+); // big tuple of (Handlers, Handlers, Handlers, Handlers, ...) + } + } + } +} + +/// Posts an event. +/// +/// Usage: `post_event!(bus, type, event)` +#[macro_export] +macro_rules! post_event_cancellable { + // TODO allow multiple $t:ty at once and re-#[doc(hidden)] the low-level get_post_targets and + // get_event_id + ($b:expr, $e:expr, $($t:ty),+) => { + { + // hygiene + let bus: &$crate::EventBus = $b; + // event setup, this may evaluate to any type. + let event: &mut _ = $e; + { + fn test(e: &C) { + } - cancellable && <$t as $crate::Event>::cancelled(event) + + test(event); + let cancelled = [$({ + // event type setup + static EVENT_ID: ::std::sync::atomic::AtomicUsize = ::std::sync::atomic::ATOMIC_USIZE_INIT; + static EVENT_ID_INIT: ::std::sync::Once = ::std::sync::ONCE_INIT; + // no generics allowed. + static DUMMY: ::std::marker::PhantomData = ::std::marker::PhantomData; + EVENT_ID_INIT.call_once(|| { + EVENT_ID.store($crate::get_event_id::<$t>(), std::sync::atomic::Ordering::Relaxed); + }); + let id = EVENT_ID.load(std::sync::atomic::Ordering::Relaxed); + let handlers = $crate::get_post_targets::<$t>(bus, event, id); + + for (_pri, fun) in handlers.iter() { + if Cancellable::cancelled(event) { + break; + } + fun(event as &mut $t); + } + + event.cancelled() + },)+]; // big tuple of (Handlers, Handlers, Handlers, Handlers, ...) + + cancelled.iter().fold(false, |n, i| n || *i) } } } @@ -101,6 +136,10 @@ pub trait Event: 'static { fn cancellable(&self) -> bool { false } +} + +/// Basic trait for defining an event. +pub trait Cancellable: 'static { /// Returns whether this event has been cancelled. fn cancelled(&self) -> bool { diff --git a/tests/basic_usage.rs b/tests/basic_usage.rs index a5ce0e2..c491b5b 100644 --- a/tests/basic_usage.rs +++ b/tests/basic_usage.rs @@ -27,12 +27,12 @@ fn test_basic_usage() { register_hook!(&event_bus, 0, MyEvent, add_handler); let mut event = MyEvent { i: 3 }; assert_eq!(event.i, 3); - post_event!(&event_bus, MyEvent, &mut event); + post_event!(&event_bus, &mut event, MyEvent); assert_eq!(event.i, 4); register_hook!(&event_bus, 1, MyEvent, no_handler); - post_event!(&event_bus, MyEvent, &mut event); + post_event!(&event_bus, &mut event, MyEvent); assert_eq!(event.i, 5); //event_bus.unregister(handler_id); - post_event!(&event_bus, MyEvent, &mut event); + post_event!(&event_bus, &mut event, MyEvent); //assert_eq!(event.i, 5); } diff --git a/tests/dyn_events.rs b/tests/dyn_events.rs index 0407f7f..0707cb1 100644 --- a/tests/dyn_events.rs +++ b/tests/dyn_events.rs @@ -1,53 +1,60 @@ #[macro_use] extern crate eventbus; -use eventbus::{Event, EventBus}; +use std::fmt::Debug; +use eventbus::{Event, EventBus, Cancellable}; -trait MyEvent : Event { - fn get_i(&self) -> i32; - fn set_i(&mut self, i32); +trait MyEvent : Event + Debug { } +trait MyExtraEvent : MyEvent + Cancellable { +} + +#[derive(Debug)] struct MyEventImpl { i: i32 } +#[derive(Debug)] +struct MyExtraEventImpl { + i: i32 +} + impl Event for MyEventImpl { } + impl MyEvent for MyEventImpl { - fn get_i(&self) -> i32 { - self.i - } - fn set_i(&mut self, i: i32) { - self.i = i; - } } -fn add_handler(e: &mut MyEvent) { - /* adds 1 */ - let i = e.get_i(); - e.set_i(i+1); +impl Event for MyExtraEventImpl { } -fn no_handler(e: &mut MyEvent) { - /* does nothing */ - let i = e.get_i(); - e.set_i(i); +impl MyEvent for MyExtraEventImpl { +} + +impl MyExtraEvent for MyExtraEventImpl { +} + +impl Cancellable for MyExtraEventImpl { + +} + +fn on_myevent(evt: &mut dyn MyEvent) { + println!("Got event for inspection and manipulation: {:?}", evt); +} + +fn on_myextraevent(evt: &mut dyn MyExtraEvent) { + println!("Got event for inspection, manipulation, and cancellation: {:?}", evt); } #[test] fn test_dyn_usage() { let event_bus = EventBus::new(); - //let handler_id = event_bus.register(add_handler, 0); - register_hook!(&event_bus, 0, dyn MyEvent, add_handler); let mut event = MyEventImpl { i: 3 }; - assert_eq!(event.i, 3); - post_event!(&event_bus, dyn MyEvent, &mut event); - assert_eq!(event.i, 4); - register_hook!(&event_bus, 1, dyn MyEvent, no_handler); - post_event!(&event_bus, dyn MyEvent, &mut event); - assert_eq!(event.i, 5); - //event_bus.unregister(handler_id); - post_event!(&event_bus, dyn MyEvent, &mut event); - //assert_eq!(event.i, 5); + let mut extraEvent = MyExtraEventImpl { i: 4 }; + //let handler_id = event_bus.register(add_handler, 0); + register_hook!(&event_bus, 0, dyn MyEvent, on_myevent); + register_hook!(&event_bus, 1, dyn MyExtraEvent, on_myextraevent); + post_event!(&event_bus, &mut event, dyn MyEvent); + post_event_cancellable!(&event_bus, &mut extraEvent, dyn MyExtraEvent, dyn MyEvent); }