Aria 2.0.0
C++23 MVVM framework (C++20 minimum) — reactive, coroutine-first, ABI-layered
Loading...
Searching...
No Matches
event_bus.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "aria/abi/export.hpp"
4#include "aria/detail/typed_signal.hpp"
7
8#include <any>
9#include <atomic>
10#include <functional>
11#include <memory>
12#include <typeindex>
13
14namespace aria::runtime {
15
20public:
23
24 EventBus(const EventBus&) = delete;
25 EventBus& operator=(const EventBus&) = delete;
26 EventBus(EventBus&&) = delete;
28
30 static EventBus& global() noexcept;
31
32 template<typename T>
33 void publish(const T& event) {
34 std::shared_ptr<::aria::detail::TypedSignal<T>> sig;
35 auto found = do_find_signal_(typeid(T));
36 if (!found.has_value()) return;
37 sig = std::any_cast<std::shared_ptr<::aria::detail::TypedSignal<T>>>(found);
38 sig->emit(event);
39 }
40
41 template<typename T>
42 [[nodiscard]] ::aria::Subscription subscribe(std::function<void(const T&)> handler) {
43 std::shared_ptr<::aria::detail::TypedSignal<T>> sig;
44 auto found = do_find_signal_(typeid(T));
45 if (found.has_value()) {
46 sig = std::any_cast<std::shared_ptr<::aria::detail::TypedSignal<T>>>(found);
47 } else {
48 sig = std::make_shared<::aria::detail::TypedSignal<T>>();
49 auto existing = do_try_emplace_signal_(typeid(T), std::any(sig));
50 if (existing.has_value()) {
51 sig = std::any_cast<std::shared_ptr<::aria::detail::TypedSignal<T>>>(existing);
52 }
53 }
54 return sig->connect(std::move(handler));
55 }
56
63 template<typename T>
65 IDispatcher& dispatcher,
66 std::function<void(const T&)> handler)
67 {
68 struct Delivery {
69 std::atomic<bool> active{true};
70 std::function<void(const T&)> handler;
71 explicit Delivery(std::function<void(const T&)> fn) : handler(std::move(fn)) {}
72 };
73 auto state = std::make_shared<Delivery>(std::move(handler));
74 auto connection = subscribe<T>([&dispatcher, state](const T& event) {
75 if (!state->active.load(std::memory_order_acquire)) return;
76 auto keep = std::make_shared<T>(event);
77 dispatcher.post([weak = std::weak_ptr{state}, keep = std::move(keep)] {
78 if (auto delivery = weak.lock();
79 delivery && delivery->active.load(std::memory_order_acquire)) {
80 delivery->handler(*keep);
81 }
82 });
83 });
84 try {
85 return ::aria::Subscription{
86 [weak = std::weak_ptr{state}, connection = std::move(connection)]() mutable {
87 if (auto delivery = weak.lock())
88 delivery->active.store(false, std::memory_order_release);
89 connection.release();
90 }};
91 } catch (...) {
92 state->active.store(false, std::memory_order_release);
93 throw;
94 }
95 }
96
97 void clear();
98
99private:
100 std::any do_find_signal_(std::type_index ti);
101 std::any do_try_emplace_signal_(std::type_index ti, std::any sig);
102
103 struct Impl;
104 // RAII pImpl. MSVC would emit C4251 for a std::unique_ptr member of a
105 // dll-exported class (the unique_ptr template is not itself exported),
106 // but the pointee is an *incomplete* opaque type consumed only through
107 // this module's non-template API, so the warning is a false positive —
108 // suppress it locally rather than hand-managing a raw pointer.
109#ifdef _MSC_VER
110# pragma warning(push)
111# pragma warning(disable: 4251)
112#endif
113 std::unique_ptr<Impl> impl_;
114#ifdef _MSC_VER
115# pragma warning(pop)
116#endif
117};
118
119} // namespace aria::runtime
RAII handle to a single subscription.
Definition subscription.hpp:44
static EventBus & global() noexcept
Process-wide global event bus.
EventBus & operator=(EventBus &&)=delete
EventBus(EventBus &&)=delete
void publish(const T &event)
Definition event_bus.hpp:33
EventBus & operator=(const EventBus &)=delete
::aria::Subscription subscribe(std::function< void(const T &)> handler)
Definition event_bus.hpp:42
::aria::Subscription subscribe_on(IDispatcher &dispatcher, std::function< void(const T &)> handler)
Subscribe with a dispatcher — incoming events are marshalled to the dispatcher's thread (e....
Definition event_bus.hpp:64
EventBus(const EventBus &)=delete
Abstract main-thread dispatcher.
Definition dispatcher.hpp:26
virtual void post(std::function< void()> fn)=0
Schedule the callable to run on the main thread (asynchronously).
#define ARIA_RUNTIME_API
Definition export.hpp:30
Definition container.hpp:11