handler.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. #pragma once
  2. //
  3. // Copyright (c) 2019-2020 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. /** \brief intrusive pointer for supervisor */
  39. using supervisor_ptr_t = intrusive_ptr_t<supervisor_t>;
  40. /** \struct handler_traits
  41. * \brief Helper class to extract final actor class and message type from pointer-to-member function
  42. */
  43. template <typename T> struct handler_traits {};
  44. /** \struct handler_traits<void (A::*)(M &) noexcept>
  45. * \brief Helper class to extract final actor class and message type from pointer-to-member function
  46. */
  47. template <typename A, typename M> struct handler_traits<void (A::*)(M &) noexcept> {
  48. /** \brief returns true if message is valid */
  49. static auto const constexpr has_valid_message = std::is_base_of_v<message_base_t, M>;
  50. /** \brief returns true if handler belongs to actor */
  51. static auto const constexpr is_actor = std::is_base_of_v<actor_base_t, A>;
  52. /** \brief returns true if handler belongs to plugin */
  53. static auto const constexpr is_plugin = std::is_base_of_v<plugin::plugin_base_t, A>;
  54. /** \brief returns true if it is lambda-handler */
  55. static auto const constexpr is_lambda = false;
  56. /** \brief message type, processed by the handler */
  57. using message_t = M;
  58. /** \brief alias for message type payload */
  59. using payload_t = typename M::payload_t;
  60. /** \brief alias for Actor or Plugin class */
  61. using backend_t = A;
  62. static_assert(is_actor || is_plugin, "message handler should be either actor or plugin");
  63. };
  64. /** \brief handler decomposer for lambda-based handler */
  65. template <typename M, typename H> struct handler_traits<lambda_holder_t<M, H>> {
  66. /** \brief returns true if message is valid */
  67. static auto const constexpr has_valid_message = std::is_base_of_v<message_base_t, M>;
  68. static_assert(has_valid_message, "lambda does not process valid message");
  69. /** \brief not an actor handler */
  70. static auto const constexpr is_actor = false;
  71. /** \brief not a plugin handler */
  72. static auto const constexpr is_plugin = false;
  73. /** \brief yes, it is lambda handler */
  74. static auto const constexpr is_lambda = true;
  75. };
  76. /** \struct handler_base_t
  77. * \brief Base class for `rotor` handler, i.e concrete message type processing point
  78. * on concrete actor
  79. */
  80. struct handler_base_t : public arc_base_t<handler_base_t> {
  81. /** \brief pointer to unique message type ( `typeid(Message).name()` ) */
  82. const void *message_type;
  83. /** \brief pointer to unique handler type ( `typeid(Handler).name()` ) */
  84. const void *handler_type;
  85. /** \brief intrusive poiter to {@link actor_base_t} the actor of the handler */
  86. // actor_base_t* actor_ptr;
  87. actor_ptr_t actor_ptr;
  88. /** \brief non-owning raw poiter to actor */
  89. const void *raw_actor_ptr;
  90. /** \brief precalculated hash for the handler */
  91. size_t precalc_hash;
  92. /** \brief constructs `handler_base_t` from raw pointer to actor, raw
  93. * pointer to message type and raw pointer to handler type
  94. */
  95. explicit handler_base_t(actor_base_t &actor, const void *message_type_, const void *handler_type_)
  96. : message_type{message_type_}, handler_type{handler_type_}, actor_ptr{&actor}, raw_actor_ptr{&actor} {
  97. auto h1 = reinterpret_cast<std::size_t>(handler_type);
  98. auto h2 = reinterpret_cast<std::size_t>(&actor);
  99. precalc_hash = h1 ^ (h2 << 1);
  100. }
  101. /** \brief compare two handler for equality */
  102. inline bool operator==(const handler_base_t &rhs) const noexcept {
  103. return handler_type == rhs.handler_type && raw_actor_ptr == rhs.raw_actor_ptr;
  104. }
  105. /** \brief attempt to delivery message to the handler
  106. *
  107. * The message is delivered only if its type matches to the handler message type,
  108. * otherwise it is silently ignored
  109. */
  110. virtual void call(message_ptr_t &) noexcept = 0;
  111. virtual inline ~handler_base_t() {}
  112. };
  113. using handler_ptr_t = intrusive_ptr_t<handler_base_t>;
  114. namespace details {
  115. template <typename Handler>
  116. inline constexpr bool is_actor_handler_v =
  117. handler_traits<Handler>::is_actor && !handler_traits<Handler>::is_plugin &&
  118. handler_traits<Handler>::has_valid_message && !handler_traits<Handler>::is_lambda;
  119. template <typename Handler> inline constexpr bool is_lambda_handler_v = handler_traits<Handler>::is_lambda;
  120. template <typename Handler>
  121. inline constexpr bool is_plugin_handler_v =
  122. handler_traits<Handler>::has_valid_message &&handler_traits<Handler>::is_plugin &&
  123. !handler_traits<Handler>::is_actor && !handler_traits<Handler>::is_lambda;
  124. namespace {
  125. namespace to {
  126. struct actor {};
  127. } // namespace to
  128. } // namespace
  129. } // namespace details
  130. /** \brief access to actor via plugin */
  131. template <> inline auto &plugin::plugin_base_t::access<details::to::actor>() noexcept { return actor; }
  132. template <typename Handler, typename Enable = void> struct handler_t;
  133. /**
  134. * \brief the actor handler meant to hold user-specific pointer-to-member function
  135. * \tparam Handler pointer-to-member function type
  136. */
  137. template <typename Handler>
  138. struct handler_t<Handler, std::enable_if_t<details::is_actor_handler_v<Handler>>> : public handler_base_t {
  139. /** \brief static pointer to unique pointer-to-member function name ( `typeid(Handler).name()` ) */
  140. static const void *handler_type;
  141. /** \brief pointer-to-member function instance */
  142. Handler handler;
  143. /** \brief constructs handler from actor & pointer-to-member function */
  144. explicit handler_t(actor_base_t &actor, Handler &&handler_)
  145. : handler_base_t{actor, final_message_t::message_type, handler_type}, handler{handler_} {}
  146. void call(message_ptr_t &message) noexcept override {
  147. using backend_t = typename traits::backend_t;
  148. if (message->type_index == final_message_t::message_type) {
  149. auto final_message = static_cast<final_message_t *>(message.get());
  150. auto &final_obj = static_cast<backend_t &>(*actor_ptr);
  151. (final_obj.*handler)(*final_message);
  152. }
  153. }
  154. private:
  155. using traits = handler_traits<Handler>;
  156. using final_message_t = typename traits::message_t;
  157. };
  158. template <typename Handler>
  159. const void *handler_t<Handler, std::enable_if_t<details::is_actor_handler_v<Handler>>>::handler_type =
  160. static_cast<const void *>(typeid(Handler).name());
  161. /**
  162. * \brief handler specialization for plugin
  163. */
  164. template <typename Handler>
  165. struct handler_t<Handler, std::enable_if_t<details::is_plugin_handler_v<Handler>>> : public handler_base_t {
  166. /** \brief typeid of Handler */
  167. static const void *handler_type;
  168. /** \brief source plugin for handler */
  169. plugin::plugin_base_t &plugin;
  170. /** \brief handler itself */
  171. Handler handler;
  172. /** \brief ctor form plugin and plugin handler (pointer-to-member function of the plugin) */
  173. explicit handler_t(plugin::plugin_base_t &plugin_, Handler &&handler_)
  174. : handler_base_t{*plugin_.access<details::to::actor>(), final_message_t::message_type, handler_type},
  175. plugin{plugin_}, handler{handler_} {}
  176. void call(message_ptr_t &message) noexcept override {
  177. using backend_t = typename traits::backend_t;
  178. if (message->type_index == final_message_t::message_type) {
  179. auto final_message = static_cast<final_message_t *>(message.get());
  180. auto &final_obj = static_cast<backend_t &>(plugin);
  181. (final_obj.*handler)(*final_message);
  182. }
  183. }
  184. private:
  185. using traits = handler_traits<Handler>;
  186. using final_message_t = typename traits::message_t;
  187. };
  188. template <typename Handler>
  189. const void *handler_t<Handler, std::enable_if_t<details::is_plugin_handler_v<Handler>>>::handler_type =
  190. static_cast<const void *>(typeid(Handler).name());
  191. /**
  192. * \brief handler specialization for lambda handler
  193. */
  194. template <typename Handler, typename M>
  195. struct handler_t<lambda_holder_t<Handler, M>,
  196. std::enable_if_t<details::is_lambda_handler_v<lambda_holder_t<Handler, M>>>> : public handler_base_t {
  197. /** \brief alias type for lambda, which will actually process messages */
  198. using handler_backend_t = lambda_holder_t<Handler, M>;
  199. /** \brief actuall lambda function for message processing */
  200. handler_backend_t handler;
  201. /** \brief static pointer to unique pointer-to-member function name ( `typeid(Handler).name()` ) */
  202. static const void *handler_type;
  203. /** \brief constructs handler from actor & lambda wrapper */
  204. explicit handler_t(actor_base_t &actor, handler_backend_t &&handler_)
  205. : handler_base_t{actor, final_message_t::message_type, handler_type}, handler{std::forward<handler_backend_t>(
  206. handler_)} {}
  207. void call(message_ptr_t &message) noexcept override {
  208. if (message->type_index == final_message_t::message_type) {
  209. auto final_message = static_cast<final_message_t *>(message.get());
  210. handler.fn(*final_message);
  211. }
  212. }
  213. private:
  214. using final_message_t = typename handler_backend_t::message_t;
  215. };
  216. template <typename Handler, typename M>
  217. const void *handler_t<lambda_holder_t<Handler, M>,
  218. std::enable_if_t<details::is_lambda_handler_v<lambda_holder_t<Handler, M>>>>::handler_type =
  219. static_cast<const void *>(typeid(Handler).name());
  220. } // namespace rotor
  221. namespace std {
  222. /** \struct hash<rotor::handler_ptr_t>
  223. * \brief Hash calculator for handler
  224. */
  225. template <> struct hash<rotor::handler_ptr_t> {
  226. /** \brief Returns the precalculated hash for the hanlder */
  227. size_t operator()(const rotor::handler_ptr_t &handler) const noexcept { return handler->precalc_hash; }
  228. };
  229. } // namespace std