Brenta Engine 1.2
Loading...
Searching...
No Matches
signal.hpp
1// SPDX-License-Identifier: MIT
2// Author: Giovanni Santini
3// Mail: giovanni.santini@proton.me
4// Github: @San7o
5
6#pragma once
7
8#include <string>
9#include <unordered_map>
10#include <utility>
11
12#include <tenno/vector.hpp>
13
14namespace brenta
15{
16
17//
18// Signals
19// -------
20//
21// A signal is a simple communication mechanism that uses the observer
22// pattern. You can subscribe to an event / signal by registering a
23// callback which will be called if that signal is emitted. Signals
24// are identified by a name (string).
25//
26// When a signal is emitted, it does not immediately call all
27// callbacks. Instead it stored a buffer of pending events which can
28// be consimed with the `update()` function. This makes sure that the
29// user of the API decides when to spend time processing the events.
30//
32{
33public:
34
35 using SignalId = std::string;
36 using Message = std::string;
37 using ConnectionId = int;
38 using Callback = std::function<void(Message)>;
39
40 struct Event;
41 class Subscription;
42
43 SignalManager() = delete;
44 ~SignalManager() = delete;
45
46 static void emit(const Event& event);
47
48 // A subscription keeps the connection alive using RAII
49 static Subscription subscribe(const SignalId& id, Callback callback);
50 static void unsubscribe(const Subscription &sub);
51
52 // Consumes all pending events
53 static void update();
54
55 // Resets everything
56 static void clear();
57
58private:
59
60 static tenno::vector<Event> pending_events;
61 static std::unordered_map<SignalId,
62 tenno::vector<std::pair<ConnectionId,
63 Callback>>> registry;
64
65};
66
68{
69 SignalId id;
70 Message message;
71};
72
73//
74// Subscription
75// ------------
76//
77// When you subscribe to an event, you get a subscription object. This
78// uses RAII to keep the connection alive and automatically clean
79// its resources when it goes out of scope.
80//
82{
83public:
84
85 friend class SignalManager;
86
87 Subscription() = delete;
88
90 {
91 if (this == &other) return;
92
93 if (this->connection_id != 0)
94 SignalManager::unsubscribe(*this);
95
96 this->signal_id = tenno::move(other.signal_id);
97 this->connection_id = other.connection_id;
98 other.signal_id = SignalId{};
99 other.connection_id = ConnectionId{};
100 }
101 Subscription &operator=(Subscription&& other)
102 {
103 if (this == &other) return *this;
104
105 if (this->connection_id != 0)
106 SignalManager::unsubscribe(*this);
107
108 this->signal_id = tenno::move(other.signal_id);
109 this->connection_id = other.connection_id;
110 other.signal_id = SignalId{};
111 other.connection_id = ConnectionId{};
112 return *this;
113 }
114
115 // Copy is not allowed
116 Subscription(const Subscription&) = delete;
117 Subscription &operator=(const Subscription&) = delete;
118
120
121private:
122
123 Subscription(SignalId signal_id, ConnectionId connection_id)
124 : signal_id(signal_id), connection_id(connection_id) {}
125
126 SignalId signal_id;
127 ConnectionId connection_id; // 0 = uninitialized
128
129};
130
131} // namespace brenta