handler.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. #pragma once
  2. //
  3. // Copyright (c) 2019-2022 Ivan Baidakou (basiliscos) (the dot dmol at gmail dot com)
  4. //
  5. // Distributed under the MIT Software License
  6. //
  7. #include "actor_base.h"
  8. #include "message.h"
  9. #include "forward.hpp"
  10. #include <functional>
  11. #include <memory>
  12. #include <typeindex>
  13. #include <typeinfo>
  14. #include <type_traits>
  15. #if defined(_MSC_VER)
  16. #pragma warning(push)
  17. #pragma warning(disable : 4251)
  18. #endif
  19. namespace rotor {
  20. /** \struct lambda_holder_t
  21. *
  22. * \brief Helper struct which holds lambda function for processing particular message types
  23. *
  24. * The whole purpose of the structure is to allow to deduce the lambda argument, i.e.
  25. * message type.
  26. *
  27. */
  28. template <typename M, typename F> struct lambda_holder_t {
  29. /** \brief lambda function itself */
  30. F fn;
  31. /** \brief constructs lambda by forwarding arguments */
  32. explicit lambda_holder_t(F &&fn_) : fn(std::forward<F>(fn_)) {}
  33. /** \brief alias type for message type for lambda */
  34. using message_t = M;
  35. /** \brief alias type for message payload */
  36. using payload_t = typename M::payload_t;
  37. };
  38. /** \brief helper function for lambda holder constructing */
  39. template <typename M, typename F> constexpr lambda_holder_t<M, F> lambda(F &&fn) {
  40. return lambda_holder_t<M, F>(std::forward<F>(fn));
  41. }
  42. /** \struct handler_traits
  43. * \brief Helper class to extract final actor class and message type from pointer-to-member function
  44. */
  45. template <typename T> struct handler_traits {};
  46. /** \struct handler_traits<void (A::*)(M &) >
  47. * \brief Helper class to catch wrong message handler
  48. */
  49. template <typename A, typename M> struct handler_traits<void (A::*)(M &)> {
  50. /** \brief an alias for handler signature */
  51. using pointer_t = void (A::*)(M &);
  52. /** \brief checks whether handler has `noexcept` specification */
  53. static auto const constexpr has_noexcept =
  54. noexcept((std::declval<A>().*std::declval<pointer_t>())(std::declval<M &>()));
  55. static_assert(has_noexcept, "message handler should have 'noexcept' specification");
  56. };
  57. /** \struct handler_traits<void (A::*)(M &) noexcept>
  58. * \brief Helper class to extract final actor class and message type from pointer-to-member function
  59. */
  60. template <typename A, typename M> struct handler_traits<void (A::*)(M &) noexcept> {
  61. /** \brief returns true if message is valid */
  62. static auto const constexpr has_valid_message = std::is_base_of_v<message_base_t, M>;
  63. /** \brief returns true if handler belongs to actor */
  64. static auto const constexpr is_actor = std::is_base_of_v<actor_base_t, A>;
  65. /** \brief returns true if handler belongs to plugin */
  66. static auto const constexpr is_plugin = std::is_base_of_v<plugin::plugin_base_t, A>;
  67. /** \brief returns true if it is lambda-handler */
  68. static auto const constexpr is_lambda = false;
  69. /** \brief message type, processed by the handler */
  70. using message_t = M;
  71. /** \brief alias for message type payload */
  72. using payload_t = typename M::payload_t;
  73. /** \brief alias for Actor or Plugin class */
  74. using backend_t = A;
  75. static_assert(is_actor || is_plugin, "message handler should be either actor or plugin");
  76. };
  77. /** \brief handler decomposer for lambda-based handler */
  78. template <typename M, typename H> struct handler_traits<lambda_holder_t<M, H>> {
  79. /** \brief returns true if message is valid */
  80. static auto const constexpr has_valid_message = std::is_base_of_v<message_base_t, M>;
  81. static_assert(has_valid_message, "lambda does not process valid message");
  82. /** \brief not an actor handler */
  83. static auto const constexpr is_actor = false;
  84. /** \brief not a plugin handler */
  85. static auto const constexpr is_plugin = false;
  86. /** \brief yes, it is lambda handler */
  87. static auto const constexpr is_lambda = true;
  88. };
  89. /** \struct handler_base_t
  90. * \brief Base class for `rotor` handler, i.e concrete message type processing point
  91. * on concrete actor.
  92. *
  93. * It holds reference to {@link actor_base_t}.
  94. */
  95. struct ROTOR_API handler_base_t : public arc_base_t<handler_base_t> {
  96. /** \brief pointer to unique handler type ( `typeid(Handler).name()` ) */
  97. const void *handler_type;
  98. /** \brief non-null pointer to {@link actor_base_t} the actor of the handler, */
  99. actor_base_t *actor_ptr;
  100. /** \brief precalculated hash for the handler */
  101. size_t precalc_hash;
  102. /** \brief constructs `handler_base_t` from raw pointer to actor, raw
  103. * pointer to message type and raw pointer to handler type
  104. */
  105. explicit handler_base_t(actor_base_t &actor, const void *handler_type_) noexcept;
  106. /** \brief compare two handler for equality */
  107. inline bool operator==(const handler_base_t &rhs) const noexcept {
  108. return handler_type == rhs.handler_type && actor_ptr == rhs.actor_ptr;
  109. }
  110. /** \brief attempt to delivery message to the handler
  111. *
  112. * The message is delivered only if its type matches to the handler message type,
  113. * otherwise it is silently ignored
  114. */
  115. virtual void call(message_ptr_t &) noexcept = 0;
  116. /** \brief "upgrades" handler by tagging it
  117. *
  118. * Conceptually it intercepts handler call and does tag-specific actions
  119. *
  120. */
  121. virtual handler_ptr_t upgrade(const void *tag) noexcept;
  122. virtual ~handler_base_t();
  123. /** \brief returns `true` if the message can be handled by the handler */
  124. virtual bool select(message_ptr_t &) noexcept = 0;
  125. /** \brief unconditionally invokes the handler for the message
  126. *
  127. * It assumes that the handler is able to handle the message. See
  128. * `select` method.
  129. *
  130. */
  131. virtual void call_no_check(message_ptr_t &) noexcept = 0;
  132. /** \brief unique per-message-type pointer used for routing */
  133. virtual const void *message_type() const noexcept = 0;
  134. };
  135. /** \struct continuation_t
  136. * \brief continue handler invocation (used for intercepting)
  137. */
  138. struct continuation_t {
  139. /** \brief continue handler invocation */
  140. virtual void operator()() const noexcept = 0;
  141. virtual ~continuation_t() = default;
  142. };
  143. /** \struct handler_intercepted_t
  144. * \brief proxies call to the original hanlder, applying tag-specific actions
  145. */
  146. struct handler_intercepted_t : public handler_base_t {
  147. /** \brief constructs `handler_intercepted_t` by proxying original hander */
  148. handler_intercepted_t(handler_ptr_t backend_, const void *tag_) noexcept;
  149. handler_ptr_t upgrade(const void *tag) noexcept override;
  150. void call(message_ptr_t &) noexcept override;
  151. bool select(message_ptr_t &message) noexcept override;
  152. void call_no_check(message_ptr_t &message) noexcept override;
  153. const void *message_type() const noexcept override;
  154. private:
  155. handler_ptr_t backend;
  156. const void *tag;
  157. };
  158. namespace details {
  159. template <typename Handler>
  160. inline constexpr bool is_actor_handler_v =
  161. handler_traits<Handler>::is_actor && !handler_traits<Handler>::is_plugin &&
  162. handler_traits<Handler>::has_valid_message && !handler_traits<Handler>::is_lambda;
  163. template <typename Handler> inline constexpr bool is_lambda_handler_v = handler_traits<Handler>::is_lambda;
  164. template <typename Handler>
  165. inline constexpr bool is_plugin_handler_v =
  166. handler_traits<Handler>::has_valid_message && handler_traits<Handler>::is_plugin &&
  167. !handler_traits<Handler>::is_actor && !handler_traits<Handler>::is_lambda;
  168. namespace {
  169. namespace to {
  170. struct actor {};
  171. } // namespace to
  172. } // namespace
  173. } // namespace details
  174. /** \brief access to actor via plugin */
  175. template <> inline auto &plugin::plugin_base_t::access<details::to::actor>() noexcept { return actor; }
  176. template <typename Handler, typename Enable = void> struct handler_t;
  177. /**
  178. * \brief the actor handler meant to hold user-specific pointer-to-member function
  179. * \tparam Handler pointer-to-member function type
  180. */
  181. template <typename Handler>
  182. struct handler_t<Handler, std::enable_if_t<details::is_actor_handler_v<Handler>>> final : public handler_base_t {
  183. /** \brief static pointer to unique pointer-to-member function name ( `typeid(Handler).name()` ) */
  184. static const void *handler_type;
  185. /** \brief pointer-to-member function instance */
  186. Handler handler;
  187. /** \brief constructs handler from actor & pointer-to-member function */
  188. explicit handler_t(actor_base_t &actor, Handler &&handler_)
  189. : handler_base_t{actor, handler_type}, handler{handler_} {}
  190. void call(message_ptr_t &message) noexcept override {
  191. if (message->type_index == final_message_t::message_type) {
  192. auto final_message = static_cast<final_message_t *>(message.get());
  193. auto &final_obj = static_cast<backend_t &>(*actor_ptr);
  194. (final_obj.*handler)(*final_message);
  195. }
  196. }
  197. bool select(message_ptr_t &message) noexcept override {
  198. return message->type_index == final_message_t::message_type;
  199. }
  200. void call_no_check(message_ptr_t &message) noexcept override {
  201. auto final_message = static_cast<final_message_t *>(message.get());
  202. auto &final_obj = static_cast<backend_t &>(*actor_ptr);
  203. (final_obj.*handler)(*final_message);
  204. }
  205. const void *message_type() const noexcept override { return final_message_t::message_type; }
  206. private:
  207. using traits = handler_traits<Handler>;
  208. using backend_t = typename traits::backend_t;
  209. using final_message_t = typename traits::message_t;
  210. };
  211. template <typename Handler>
  212. const void *handler_t<Handler, std::enable_if_t<details::is_actor_handler_v<Handler>>>::handler_type =
  213. static_cast<const void *>(typeid(Handler).name());
  214. /**
  215. * \brief handler specialization for plugin
  216. */
  217. template <typename Handler>
  218. struct handler_t<Handler, std::enable_if_t<details::is_plugin_handler_v<Handler>>> final : public handler_base_t {
  219. /** \brief typeid of Handler */
  220. static const void *handler_type;
  221. /** \brief source plugin for handler */
  222. plugin::plugin_base_t &plugin;
  223. /** \brief handler itself */
  224. Handler handler;
  225. /** \brief ctor form plugin and plugin handler (pointer-to-member function of the plugin) */
  226. explicit handler_t(plugin::plugin_base_t &plugin_, Handler &&handler_)
  227. : handler_base_t{*plugin_.access<details::to::actor>(), handler_type}, plugin{plugin_}, handler{handler_} {}
  228. void call(message_ptr_t &message) noexcept override {
  229. if (message->type_index == final_message_t::message_type) {
  230. auto final_message = static_cast<final_message_t *>(message.get());
  231. auto &final_obj = static_cast<backend_t &>(plugin);
  232. (final_obj.*handler)(*final_message);
  233. }
  234. }
  235. bool select(message_ptr_t &message) noexcept override {
  236. return message->type_index == final_message_t::message_type;
  237. }
  238. void call_no_check(message_ptr_t &message) noexcept override {
  239. auto final_message = static_cast<final_message_t *>(message.get());
  240. auto &final_obj = static_cast<backend_t &>(plugin);
  241. (final_obj.*handler)(*final_message);
  242. }
  243. const void *message_type() const noexcept override { return final_message_t::message_type; }
  244. private:
  245. using traits = handler_traits<Handler>;
  246. using backend_t = typename traits::backend_t;
  247. using final_message_t = typename traits::message_t;
  248. };
  249. template <typename Handler>
  250. const void *handler_t<Handler, std::enable_if_t<details::is_plugin_handler_v<Handler>>>::handler_type =
  251. static_cast<const void *>(typeid(Handler).name());
  252. /**
  253. * \brief handler specialization for lambda handler
  254. */
  255. template <typename Handler, typename M>
  256. struct handler_t<lambda_holder_t<Handler, M>,
  257. std::enable_if_t<details::is_lambda_handler_v<lambda_holder_t<Handler, M>>>>
  258. final : public handler_base_t {
  259. /** \brief alias type for lambda, which will actually process messages */
  260. using handler_backend_t = lambda_holder_t<Handler, M>;
  261. /** \brief actually lambda function for message processing */
  262. handler_backend_t handler;
  263. /** \brief static pointer to unique pointer-to-member function name ( `typeid(Handler).name()` ) */
  264. static const void *handler_type;
  265. /** \brief constructs handler from actor & lambda wrapper */
  266. explicit handler_t(actor_base_t &actor, handler_backend_t &&handler_)
  267. : handler_base_t{actor, handler_type}, handler{std::forward<handler_backend_t>(handler_)} {}
  268. void call(message_ptr_t &message) noexcept override {
  269. if (message->type_index == final_message_t::message_type) {
  270. auto final_message = static_cast<final_message_t *>(message.get());
  271. handler.fn(*final_message);
  272. }
  273. }
  274. bool select(message_ptr_t &message) noexcept override {
  275. return message->type_index == final_message_t::message_type;
  276. }
  277. void call_no_check(message_ptr_t &message) noexcept override {
  278. auto final_message = static_cast<final_message_t *>(message.get());
  279. handler.fn(*final_message);
  280. }
  281. const void *message_type() const noexcept override { return final_message_t::message_type; }
  282. private:
  283. using final_message_t = typename handler_backend_t::message_t;
  284. };
  285. template <typename Handler, typename M>
  286. const void *handler_t<lambda_holder_t<Handler, M>,
  287. std::enable_if_t<details::is_lambda_handler_v<lambda_holder_t<Handler, M>>>>::handler_type =
  288. static_cast<const void *>(typeid(Handler).name());
  289. } // namespace rotor
  290. namespace std {
  291. /** \struct hash<rotor::handler_ptr_t>
  292. * \brief Hash calculator for handler
  293. */
  294. template <> struct hash<rotor::handler_ptr_t> {
  295. /** \brief Returns the precalculated hash for the hanlder */
  296. size_t operator()(const rotor::handler_ptr_t &handler) const noexcept { return handler->precalc_hash; }
  297. };
  298. } // namespace std
  299. #if defined(_MSC_VER)
  300. #pragma warning(pop)
  301. #endif