rotor
Event loop friendly C++ actor micro-framework
 
Loading...
Searching...
No Matches
handler.h
1#pragma once
2
3//
4// Copyright (c) 2019-2022 Ivan Baidakou (basiliscos) (the dot dmol at gmail dot com)
5//
6// Distributed under the MIT Software License
7//
8
9#include "actor_base.h"
10#include "message.h"
11#include "forward.hpp"
12#include <functional>
13#include <memory>
14#include <typeindex>
15#include <typeinfo>
16#include <type_traits>
17
18#if defined(_MSC_VER)
19#pragma warning(push)
20#pragma warning(disable : 4251)
21#endif
22
23namespace rotor {
24
33template <typename M, typename F> struct lambda_holder_t {
35 F fn;
36
38 explicit lambda_holder_t(F &&fn_) : fn(std::forward<F>(fn_)) {}
39
41 using message_t = M;
42
44 using payload_t = typename M::payload_t;
45};
46
48template <typename M, typename F> constexpr lambda_holder_t<M, F> lambda(F &&fn) {
49 return lambda_holder_t<M, F>(std::forward<F>(fn));
50}
51
55template <typename T> struct handler_traits {};
56
60template <typename A, typename M> struct handler_traits<void (A::*)(M &)> {
62 using pointer_t = void (A::*)(M &);
63
65 static auto const constexpr has_noexcept =
66 noexcept((std::declval<A>().*std::declval<pointer_t>())(std::declval<M &>()));
67 static_assert(has_noexcept, "message handler should have 'noexcept' specification");
68};
69
73template <typename A, typename M> struct handler_traits<void (A::*)(M &) noexcept> {
74
76 static auto const constexpr has_valid_message = std::is_base_of_v<message_base_t, M>;
77
79 static auto const constexpr is_actor = std::is_base_of_v<actor_base_t, A>;
80
82 static auto const constexpr is_plugin = std::is_base_of_v<plugin::plugin_base_t, A>;
83
85 static auto const constexpr is_lambda = false;
86
88 using message_t = M;
89
91 using payload_t = typename M::payload_t;
92
94 using backend_t = A;
95 static_assert(is_actor || is_plugin, "message handler should be either actor or plugin");
96};
97
99template <typename M, typename H> struct handler_traits<lambda_holder_t<M, H>> {
101 static auto const constexpr has_valid_message = std::is_base_of_v<message_base_t, M>;
102
103 static_assert(has_valid_message, "lambda does not process valid message");
104
106 static auto const constexpr is_actor = false;
107
109 static auto const constexpr is_plugin = false;
110
112 static auto const constexpr is_lambda = true;
113};
114
121struct ROTOR_API handler_base_t : public arc_base_t<handler_base_t> {
123 const void *handler_type;
124
127
130
134 explicit handler_base_t(actor_base_t &actor, const void *handler_type_) noexcept;
135
137 inline bool operator==(const handler_base_t &rhs) const noexcept {
138 return handler_type == rhs.handler_type && actor_ptr == rhs.actor_ptr;
139 }
140
146 virtual void call(message_ptr_t &) noexcept = 0;
147
153 virtual handler_ptr_t upgrade(const void *tag) noexcept;
154
155 virtual ~handler_base_t();
156
158 virtual bool select(message_ptr_t &) noexcept = 0;
159
166 virtual void call_no_check(message_ptr_t &) noexcept = 0;
167
169 virtual const void *message_type() const noexcept = 0;
170};
171
176
178 virtual void operator()() const noexcept = 0;
179 virtual ~continuation_t() = default;
180};
181
187 handler_intercepted_t(handler_ptr_t backend_, const void *tag_) noexcept;
188
189 handler_ptr_t upgrade(const void *tag) noexcept override;
190 void call(message_ptr_t &) noexcept override;
191 bool select(message_ptr_t &message) noexcept override;
192 void call_no_check(message_ptr_t &message) noexcept override;
193 const void *message_type() const noexcept override;
194
195 private:
196 handler_ptr_t backend;
197 const void *tag;
198};
199
200namespace details {
201
202template <typename Handler>
203inline constexpr bool is_actor_handler_v =
206
207template <typename Handler> inline constexpr bool is_lambda_handler_v = handler_traits<Handler>::is_lambda;
208
209template <typename Handler>
210inline constexpr bool is_plugin_handler_v =
213
214namespace {
215namespace to {
216struct actor {};
217} // namespace to
218} // namespace
219} // namespace details
220
222template <> inline auto &plugin::plugin_base_t::access<details::to::actor>() noexcept { return actor; }
223
224template <typename Handler, typename Enable = void> struct handler_t;
225
230template <typename Handler>
231struct handler_t<Handler, std::enable_if_t<details::is_actor_handler_v<Handler>>> final : public handler_base_t {
232
234 static const void *handler_type;
235
237 Handler handler;
238
240 explicit handler_t(actor_base_t &actor, Handler &&handler_)
241 : handler_base_t{actor, handler_type}, handler{handler_} {}
242
243 void call(message_ptr_t &message) noexcept override {
244 if (message->type_index == final_message_t::message_type) {
245 auto final_message = static_cast<final_message_t *>(message.get());
246 auto &final_obj = static_cast<backend_t &>(*actor_ptr);
247 (final_obj.*handler)(*final_message);
248 }
249 }
250
251 bool select(message_ptr_t &message) noexcept override {
252 return message->type_index == final_message_t::message_type;
253 }
254
255 void call_no_check(message_ptr_t &message) noexcept override {
256 auto final_message = static_cast<final_message_t *>(message.get());
257 auto &final_obj = static_cast<backend_t &>(*actor_ptr);
258 (final_obj.*handler)(*final_message);
259 }
260
261 const void *message_type() const noexcept override { return final_message_t::message_type; }
262
263 private:
264 using traits = handler_traits<Handler>;
265 using backend_t = typename traits::backend_t;
266 using final_message_t = typename traits::message_t;
267};
268
269template <typename Handler>
270const void *handler_t<Handler, std::enable_if_t<details::is_actor_handler_v<Handler>>>::handler_type =
271 static_cast<const void *>(typeid(Handler).name());
272
276template <typename Handler>
277struct handler_t<Handler, std::enable_if_t<details::is_plugin_handler_v<Handler>>> final : public handler_base_t {
279 static const void *handler_type;
280
283
285 Handler handler;
286
288 explicit handler_t(plugin::plugin_base_t &plugin_, Handler &&handler_)
289 : handler_base_t{*plugin_.access<details::to::actor>(), handler_type}, plugin{plugin_}, handler{handler_} {}
290
291 void call(message_ptr_t &message) noexcept override {
292 if (message->type_index == final_message_t::message_type) {
293 auto final_message = static_cast<final_message_t *>(message.get());
294 auto &final_obj = static_cast<backend_t &>(plugin);
295 (final_obj.*handler)(*final_message);
296 }
297 }
298
299 bool select(message_ptr_t &message) noexcept override {
300 return message->type_index == final_message_t::message_type;
301 }
302
303 void call_no_check(message_ptr_t &message) noexcept override {
304 auto final_message = static_cast<final_message_t *>(message.get());
305 auto &final_obj = static_cast<backend_t &>(plugin);
306 (final_obj.*handler)(*final_message);
307 }
308
309 const void *message_type() const noexcept override { return final_message_t::message_type; }
310
311 private:
312 using traits = handler_traits<Handler>;
313 using backend_t = typename traits::backend_t;
314 using final_message_t = typename traits::message_t;
315};
316
317template <typename Handler>
318const void *handler_t<Handler, std::enable_if_t<details::is_plugin_handler_v<Handler>>>::handler_type =
319 static_cast<const void *>(typeid(Handler).name());
320
324template <typename Handler, typename M>
325struct handler_t<lambda_holder_t<Handler, M>,
326 std::enable_if_t<details::is_lambda_handler_v<lambda_holder_t<Handler, M>>>>
327 final : public handler_base_t {
330
333
335 static const void *handler_type;
336
338 explicit handler_t(actor_base_t &actor, handler_backend_t &&handler_)
339 : handler_base_t{actor, handler_type}, handler{std::forward<handler_backend_t>(handler_)} {}
340
341 void call(message_ptr_t &message) noexcept override {
342 if (message->type_index == final_message_t::message_type) {
343 auto final_message = static_cast<final_message_t *>(message.get());
344 handler.fn(*final_message);
345 }
346 }
347
348 bool select(message_ptr_t &message) noexcept override {
349 return message->type_index == final_message_t::message_type;
350 }
351
352 void call_no_check(message_ptr_t &message) noexcept override {
353 auto final_message = static_cast<final_message_t *>(message.get());
354 handler.fn(*final_message);
355 }
356
357 const void *message_type() const noexcept override { return final_message_t::message_type; }
358
359 private:
360 using final_message_t = typename handler_backend_t::message_t;
361};
362
363template <typename Handler, typename M>
364const void *handler_t<lambda_holder_t<Handler, M>,
365 std::enable_if_t<details::is_lambda_handler_v<lambda_holder_t<Handler, M>>>>::handler_type =
366 static_cast<const void *>(typeid(Handler).name());
367
368} // namespace rotor
369
370namespace std {
374template <> struct hash<rotor::handler_ptr_t> {
375
377 size_t operator()(const rotor::handler_ptr_t &handler) const noexcept { return handler->precalc_hash; }
378};
379} // namespace std
380
381#if defined(_MSC_VER)
382#pragma warning(pop)
383#endif
Basic namespace for all rotor functionalities.
Definition rotor.hpp:21
intrusive_ptr_t< message_base_t > message_ptr_t
intrusive pointer for message
Definition message.h:118
constexpr lambda_holder_t< M, F > lambda(F &&fn)
helper function for lambda holder constructing
Definition handler.h:48
boost::intrusive_ref_counter< T, counter_policy_t > arc_base_t
base class to inject ref-counter with the specified policy
Definition arc.hpp:24
intrusive_ptr_t< handler_base_t > handler_ptr_t
intrusive pointer for handler
Definition forward.hpp:26
universal primitive of concurrent computation
Definition actor_base.h:47
continue handler invocation (used for intercepting)
Definition handler.h:175
virtual void operator()() const noexcept=0
continue handler invocation
Base class for rotor handler, i.e concrete message type processing point on concrete actor.
Definition handler.h:121
virtual handler_ptr_t upgrade(const void *tag) noexcept
"upgrades" handler by tagging it
size_t precalc_hash
precalculated hash for the handler
Definition handler.h:129
handler_base_t(actor_base_t &actor, const void *handler_type_) noexcept
constructs handler_base_t from raw pointer to actor, raw pointer to message type and raw pointer to h...
virtual void call_no_check(message_ptr_t &) noexcept=0
unconditionally invokes the handler for the message
virtual const void * message_type() const noexcept=0
unique per-message-type pointer used for routing
bool operator==(const handler_base_t &rhs) const noexcept
compare two handler for equality
Definition handler.h:137
actor_base_t * actor_ptr
non-null pointer to actor_base_t the actor of the handler,
Definition handler.h:126
const void * handler_type
pointer to unique handler type ( typeid(Handler).name() )
Definition handler.h:123
virtual void call(message_ptr_t &) noexcept=0
attempt to delivery message to the handler
virtual bool select(message_ptr_t &) noexcept=0
returns true if the message can be handled by the handler
proxies call to the original hanlder, applying tag-specific actions
Definition handler.h:185
void call_no_check(message_ptr_t &message) noexcept override
unconditionally invokes the handler for the message
bool select(message_ptr_t &message) noexcept override
returns true if the message can be handled by the handler
handler_intercepted_t(handler_ptr_t backend_, const void *tag_) noexcept
constructs handler_intercepted_t by proxying original hander
handler_ptr_t upgrade(const void *tag) noexcept override
"upgrades" handler by tagging it
void call(message_ptr_t &) noexcept override
attempt to delivery message to the handler
const void * message_type() const noexcept override
unique per-message-type pointer used for routing
static const void * handler_type
static pointer to unique pointer-to-member function name ( typeid(Handler).name() )
Definition handler.h:234
void call_no_check(message_ptr_t &message) noexcept override
unconditionally invokes the handler for the message
Definition handler.h:255
const void * message_type() const noexcept override
unique per-message-type pointer used for routing
Definition handler.h:261
handler_t(actor_base_t &actor, Handler &&handler_)
constructs handler from actor & pointer-to-member function
Definition handler.h:240
Handler handler
pointer-to-member function instance
Definition handler.h:237
bool select(message_ptr_t &message) noexcept override
returns true if the message can be handled by the handler
Definition handler.h:251
void call(message_ptr_t &message) noexcept override
attempt to delivery message to the handler
Definition handler.h:243
void call(message_ptr_t &message) noexcept override
attempt to delivery message to the handler
Definition handler.h:291
void call_no_check(message_ptr_t &message) noexcept override
unconditionally invokes the handler for the message
Definition handler.h:303
const void * message_type() const noexcept override
unique per-message-type pointer used for routing
Definition handler.h:309
plugin::plugin_base_t & plugin
source plugin for handler
Definition handler.h:282
bool select(message_ptr_t &message) noexcept override
returns true if the message can be handled by the handler
Definition handler.h:299
handler_t(plugin::plugin_base_t &plugin_, Handler &&handler_)
ctor form plugin and plugin handler (pointer-to-member function of the plugin)
Definition handler.h:288
static const void * handler_type
typeid of Handler
Definition handler.h:279
static const void * handler_type
static pointer to unique pointer-to-member function name ( typeid(Handler).name() )
Definition handler.h:335
handler_backend_t handler
actually lambda function for message processing
Definition handler.h:332
bool select(message_ptr_t &message) noexcept override
returns true if the message can be handled by the handler
Definition handler.h:348
handler_t(actor_base_t &actor, handler_backend_t &&handler_)
constructs handler from actor & lambda wrapper
Definition handler.h:338
void call(message_ptr_t &message) noexcept override
attempt to delivery message to the handler
Definition handler.h:341
void call_no_check(message_ptr_t &message) noexcept override
unconditionally invokes the handler for the message
Definition handler.h:352
const void * message_type() const noexcept override
unique per-message-type pointer used for routing
Definition handler.h:357
Definition handler.h:224
M message_t
message type, processed by the handler
Definition handler.h:88
typename M::payload_t payload_t
alias for message type payload
Definition handler.h:91
A backend_t
alias for Actor or Plugin class
Definition handler.h:94
void(A::*)(M &) pointer_t
an alias for handler signature
Definition handler.h:62
Helper class to extract final actor class and message type from pointer-to-member function.
Definition handler.h:55
Helper struct which holds lambda function for processing particular message types.
Definition handler.h:33
typename M::payload_t payload_t
alias type for message payload
Definition handler.h:44
M message_t
alias type for message type for lambda
Definition handler.h:41
lambda_holder_t(F &&fn_)
constructs lambda by forwarding arguments
Definition handler.h:38
F fn
lambda function itself
Definition handler.h:35
base class for all actor plugins
Definition plugin_base.h:23