From 5b7b4f1e12c0c9d8e2c555822d91d3301a4366ff Mon Sep 17 00:00:00 2001 From: Daniel Griffen Date: Sun, 28 Oct 2018 19:32:00 -0700 Subject: [PATCH 1/3] make cancellation a type property --- src/lib.rs | 55 ++++++++++++++++++++++++++++++++------- tests/dyn_events.rs | 63 +++++++++++++++++++++++++-------------------- 2 files changed, 80 insertions(+), 38 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 105b7ef..58d854c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,14 +56,6 @@ macro_rules! post_event { // 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); - // 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; @@ -79,11 +71,50 @@ macro_rules! post_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) { + } + } + } + } +} + +/// 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, $t:ty, $e:expr) => { + { + // hygiene + let bus: &$crate::EventBus = $b; + // event setup, this may evaluate to any type. + let event: &mut _ = $e; + { + fn test(e: &C) { + + } + + test(event); + // 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 handlers = $crate::get_post_targets::<$t>(bus, event, id); + for (_pri, fun) in handlers.iter() { + fun(event as &mut $t); + if event.cancelled() { break; } } - cancellable && <$t as $crate::Event>::cancelled(event) + event.cancelled() } } } @@ -101,6 +132,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/dyn_events.rs b/tests/dyn_events.rs index 0407f7f..8ea4599 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); + 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, 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); + post_event_cancellable!(&event_bus, dyn MyExtraEvent, &mut extraEvent); } -- 2.34.1 From 3c3e8754ad61aa31f8c93e6edd22d4000426fa02 Mon Sep 17 00:00:00 2001 From: Daniel Griffen Date: Sun, 28 Oct 2018 19:43:48 -0700 Subject: [PATCH 2/3] add multi-parenting --- src/lib.rs | 72 +++++++++++++++++++++++--------------------- tests/basic_usage.rs | 6 ++-- tests/dyn_events.rs | 4 +-- 3 files changed, 43 insertions(+), 39 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 58d854c..93825c1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,29 +49,30 @@ 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; { - // 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 _ = ($({ + // 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() { + fun(event); + } + },)+); // big tuple of (Handlers, Handlers, Handlers, Handlers, ...) - // 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); - } } } } @@ -84,7 +85,7 @@ macro_rules! post_event { 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, $t:ty, $e:expr) => { + ($b:expr, $e:expr, $($t:ty),+) => { { // hygiene let bus: &$crate::EventBus = $b; @@ -96,25 +97,28 @@ macro_rules! post_event_cancellable { } test(event); - // 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 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); - // handler retrieval and invokation - let handlers = $crate::get_post_targets::<$t>(bus, event, id); - for (_pri, fun) in handlers.iter() { - fun(event as &mut $t); - if event.cancelled() { - break; + for (_pri, fun) in handlers.iter() { + fun(event as &mut $t); + if Cancellable::cancelled(event) { + break; + } } - } - event.cancelled() + + event.cancelled() + },)+); // big tuple of (Handlers, Handlers, Handlers, Handlers, ...) + } } } 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 8ea4599..0707cb1 100644 --- a/tests/dyn_events.rs +++ b/tests/dyn_events.rs @@ -55,6 +55,6 @@ fn test_dyn_usage() { //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, dyn MyEvent, &mut event); - post_event_cancellable!(&event_bus, dyn MyExtraEvent, &mut extraEvent); + post_event!(&event_bus, &mut event, dyn MyEvent); + post_event_cancellable!(&event_bus, &mut extraEvent, dyn MyExtraEvent, dyn MyEvent); } -- 2.34.1 From fedb32d24292e46b652b937fbbf78ec44280b659 Mon Sep 17 00:00:00 2001 From: Daniel Griffen Date: Sun, 28 Oct 2018 19:55:37 -0700 Subject: [PATCH 3/3] collate cancelled --- src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 93825c1..4662abd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,7 +72,6 @@ macro_rules! post_event { fun(event); } },)+); // big tuple of (Handlers, Handlers, Handlers, Handlers, ...) - } } } @@ -97,7 +96,7 @@ macro_rules! post_event_cancellable { } test(event); - let cancelled = ($({ + 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; @@ -110,15 +109,16 @@ macro_rules! post_event_cancellable { let handlers = $crate::get_post_targets::<$t>(bus, event, id); for (_pri, fun) in handlers.iter() { - fun(event as &mut $t); if Cancellable::cancelled(event) { break; } + fun(event as &mut $t); } event.cancelled() - },)+); // big tuple of (Handlers, Handlers, Handlers, Handlers, ...) + },)+]; // big tuple of (Handlers, Handlers, Handlers, Handlers, ...) + cancelled.iter().fold(false, |n, i| n || *i) } } } -- 2.34.1