handler.h 13 KB

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