Move cancellable to the type system and implement multi-parenting #1

Closed
dgriffen wants to merge 3 commits from dgriffen/rust.eventbus:dev/dgriffen/type-cancel into master
3 changed files with 104 additions and 58 deletions

View File

@ -49,21 +49,14 @@ macro_rules! register_hook {
macro_rules! post_event { macro_rules! post_event {
// TODO allow multiple $t:ty at once and re-#[doc(hidden)] the low-level get_post_targets and // TODO allow multiple $t:ty at once and re-#[doc(hidden)] the low-level get_post_targets and
// get_event_id // get_event_id
($b:expr, $t:ty, $e:expr) => { ($b:expr, $e:expr, $($t:ty),+) => {
{ {
// hygiene // hygiene
let bus: &$crate::EventBus = $b; let bus: &$crate::EventBus = $b;
// event setup, this may evaluate to any type. // event setup, this may evaluate to any type.
let event: &mut _ = $e; let event: &mut _ = $e;
{ {
// it is a logic error for an event's cancellability to change based on its value. let _ = ($({
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);
// event type setup // event type setup
static EVENT_ID: ::std::sync::atomic::AtomicUsize = ::std::sync::atomic::ATOMIC_USIZE_INIT; static EVENT_ID: ::std::sync::atomic::AtomicUsize = ::std::sync::atomic::ATOMIC_USIZE_INIT;
static EVENT_ID_INIT: ::std::sync::Once = ::std::sync::ONCE_INIT; static EVENT_ID_INIT: ::std::sync::Once = ::std::sync::ONCE_INIT;
@ -73,17 +66,59 @@ macro_rules! post_event {
EVENT_ID.store($crate::get_event_id::<$t>(), std::sync::atomic::Ordering::Relaxed); EVENT_ID.store($crate::get_event_id::<$t>(), std::sync::atomic::Ordering::Relaxed);
}); });
let id = EVENT_ID.load(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); let handlers = $crate::get_post_targets::<$t>(bus, event, id);
for (_pri, fun) in handlers.iter() { for (_pri, fun) in handlers.iter() {
fun(event); fun(event);
if cancellable && <$t as $crate::Event>::cancelled(event) { }
},)+); // big tuple of (Handlers<type>, Handlers<type>, Handlers<type>, Handlers<type>, ...)
}
}
}
}
/// 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<C: Cancellable>(e: &C) {
}
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<dyn Fn(&mut $t) + Send + Sync> = ::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; break;
} }
fun(event as &mut $t);
} }
cancellable && <$t as $crate::Event>::cancelled(event)
event.cancelled()
},)+]; // big tuple of (Handlers<type>, Handlers<type>, Handlers<type>, Handlers<type>, ...)
cancelled.iter().fold(false, |n, i| n || *i)
} }
} }
} }
@ -101,6 +136,10 @@ pub trait Event: 'static {
fn cancellable(&self) -> bool { fn cancellable(&self) -> bool {
false false
} }
}
/// Basic trait for defining an event.
pub trait Cancellable: 'static {
/// Returns whether this event has been cancelled. /// Returns whether this event has been cancelled.
fn cancelled(&self) -> bool { fn cancelled(&self) -> bool {

View File

@ -27,12 +27,12 @@ fn test_basic_usage() {
register_hook!(&event_bus, 0, MyEvent, add_handler); register_hook!(&event_bus, 0, MyEvent, add_handler);
let mut event = MyEvent { i: 3 }; let mut event = MyEvent { i: 3 };
assert_eq!(event.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); assert_eq!(event.i, 4);
register_hook!(&event_bus, 1, MyEvent, no_handler); 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); assert_eq!(event.i, 5);
//event_bus.unregister(handler_id); //event_bus.unregister(handler_id);
post_event!(&event_bus, MyEvent, &mut event); post_event!(&event_bus, &mut event, MyEvent);
//assert_eq!(event.i, 5); //assert_eq!(event.i, 5);
} }

View File

@ -1,53 +1,60 @@
#[macro_use] #[macro_use]
extern crate eventbus; extern crate eventbus;
use eventbus::{Event, EventBus}; use std::fmt::Debug;
use eventbus::{Event, EventBus, Cancellable};
trait MyEvent : Event { trait MyEvent : Event + Debug {
fn get_i(&self) -> i32;
fn set_i(&mut self, i32);
} }
trait MyExtraEvent : MyEvent + Cancellable {
}
#[derive(Debug)]
struct MyEventImpl { struct MyEventImpl {
i: i32 i: i32
} }
#[derive(Debug)]
struct MyExtraEventImpl {
i: i32
}
impl Event for MyEventImpl { impl Event for MyEventImpl {
} }
impl MyEvent 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) { impl Event for MyExtraEventImpl {
/* adds 1 */
let i = e.get_i();
e.set_i(i+1);
} }
fn no_handler(e: &mut MyEvent) { impl MyEvent for MyExtraEventImpl {
/* does nothing */ }
let i = e.get_i();
e.set_i(i); 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] #[test]
fn test_dyn_usage() { fn test_dyn_usage() {
let event_bus = EventBus::new(); 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 }; let mut event = MyEventImpl { i: 3 };
assert_eq!(event.i, 3); let mut extraEvent = MyExtraEventImpl { i: 4 };
post_event!(&event_bus, dyn MyEvent, &mut event); //let handler_id = event_bus.register(add_handler, 0);
assert_eq!(event.i, 4); register_hook!(&event_bus, 0, dyn MyEvent, on_myevent);
register_hook!(&event_bus, 1, dyn MyEvent, no_handler); register_hook!(&event_bus, 1, dyn MyExtraEvent, on_myextraevent);
post_event!(&event_bus, dyn MyEvent, &mut event); post_event!(&event_bus, &mut event, dyn MyEvent);
assert_eq!(event.i, 5); post_event_cancellable!(&event_bus, &mut extraEvent, dyn MyExtraEvent, dyn MyEvent);
//event_bus.unregister(handler_id);
post_event!(&event_bus, dyn MyEvent, &mut event);
//assert_eq!(event.i, 5);
} }