]> git.tdb.fi Git - libs/game.git/blobdiff - source/game/eventsource.h
Add an event bus for delivering events
[libs/game.git] / source / game / eventsource.h
diff --git a/source/game/eventsource.h b/source/game/eventsource.h
new file mode 100644 (file)
index 0000000..5dacbee
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef MSP_GAME_EVENTSOURCE_H_
+#define MSP_GAME_EVENTSOURCE_H_
+
+#include "eventbus.h"
+#include "eventobserver.h"
+
+namespace Msp::Game {
+
+class EventObserver;
+
+class EventSourceBase
+{
+protected:
+       EventBus &bus;
+
+public:
+       EventSourceBase(EventBus &b): bus(b) { }
+
+       virtual void remove_observer(EventObserver &) = 0;
+};
+
+
+template<typename... E>
+class EventSource: public EventSourceBase, private EventDispatcher<E>...
+{
+public:
+       EventSource(EventBus &b): EventSourceBase(b) { }
+       ~EventSource() { (cancel_observation<E>(), ...); }
+
+       template<typename T>
+       void add_observer(EventObserver &obs, std::function<void(const T &)> cb)
+       { static_cast<EventDispatcher<T> &>(*this).add_observer(obs, std::move(cb)); }
+
+       void remove_observer(EventObserver &obs) override
+       { (static_cast<EventDispatcher<E> &>(*this).remove_observer(&obs), ...); }
+
+private:
+       template<typename T>
+       void cancel_observation();
+
+public:
+       template<typename T, typename... Args>
+       void emit(Args &&...) const;
+};
+
+
+template<typename... E>
+template<typename T, typename... Args>
+inline void EventSource<E...>::emit(Args &&... args) const
+{
+       T event(std::forward<Args>(args)...);
+       static_cast<const EventDispatcher<T> &>(*this).dispatch(event);
+       bus.dispatch(event);
+}
+
+template<typename... E>
+template<typename T>
+inline void EventSource<E...>::cancel_observation()
+{
+       for(const auto &h: static_cast<EventDispatcher<T> &>(*this).handlers)
+               h.observer->remove_source(*this);
+}
+
+} // namespace Msp::Game
+
+#endif