OGLplus  (0.59.0) a C++ wrapper for rendering APIs

invoker.hpp
Go to the documentation of this file.
1 
9 #ifndef EAGINE_MESSAGE_BUS_INVOKER_HPP
10 #define EAGINE_MESSAGE_BUS_INVOKER_HPP
11 
12 #include "../callable_ref.hpp"
13 #include "../serialize/block_sink.hpp"
14 #include "../serialize/block_source.hpp"
15 #include "endpoint.hpp"
16 #include "future.hpp"
17 #include "handler_map.hpp"
18 #include "serialize.hpp"
19 #include <array>
20 #include <tuple>
21 
22 namespace eagine::msgbus {
23 //------------------------------------------------------------------------------
24 class result_context {
25 public:
26  result_context(
27  const message_context& msg_ctx,
28  identifier_t src_id,
29  message_sequence_t invc_id) noexcept
30  : _msg_ctx{msg_ctx}
31  , _source_id{src_id}
32  , _invocation_id{invc_id} {}
33 
34  auto msg_context() const noexcept -> const message_context& {
35  return _msg_ctx;
36  }
37 
38  auto source_id() const noexcept {
39  return _source_id;
40  }
41 
42  auto invocation_id() const noexcept {
43  return _invocation_id;
44  }
45 
46 private:
47  const message_context& _msg_ctx;
48  identifier_t _source_id{0U};
49  message_sequence_t _invocation_id{0};
50 };
51 //------------------------------------------------------------------------------
52 template <typename Result, typename Deserializer, typename Source, bool NoExcept>
53 class callback_invoker_base {
54 
55 public:
56  auto fulfill_by(const message_context& msg_ctx, stored_message& response)
57  -> bool {
58  Result result{};
59 
60  _source.reset(response.content());
61  Deserializer read_backend(_source);
62 
63  if(response.has_serializer_id(read_backend.type_id())) {
64  const auto errors{deserialize(result, read_backend)};
65  if(!errors) {
66  const result_context res_ctx{
67  msg_ctx, response.source_id, response.sequence_no};
68  _callback(res_ctx, std::move(result));
69  }
70  }
71  return true;
72  }
73 
74 protected:
75  using _callback_t =
76  callable_ref<void(const result_context&, Result&&) noexcept(NoExcept)>;
77  _callback_t _callback{};
78 
79 private:
80  Source _source{};
81 };
82 //------------------------------------------------------------------------------
83 template <typename Deserializer, typename Source, bool NoExcept>
84 class callback_invoker_base<void, Deserializer, Source, NoExcept> {
85 
86 public:
87  auto fulfill_by(const message_context& msg_ctx, stored_message& response)
88  -> bool {
89  const result_context res_ctx{
90  msg_ctx, response.source_id, response.sequence_no};
91  _callback();
92  return true;
93  }
94 
95 protected:
96  using _callback_t = basic_callable_ref<void() noexcept(NoExcept), NoExcept>;
97  _callback_t _callback{};
98 };
99 //------------------------------------------------------------------------------
100 template <
101  typename Signature,
102  typename Serializer,
103  typename Deserializer,
104  typename Sink,
105  typename Source,
106  std::size_t MaxDataSize>
107 class callback_invoker
108  : public callback_invoker_base<
109  std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<Signature>>>,
110  Deserializer,
111  Source,
112  is_noexcept_function_v<Signature>> {
113 
114  using _result_t =
115  std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<Signature>>>;
116  using base = callback_invoker_base<
117  _result_t,
118  Deserializer,
119  Source,
120  is_noexcept_function_v<Signature>>;
121  using _callback_t = typename base::_callback_t;
122 
123 public:
124  using base::base;
125 
126  template <typename Class, typename MfcT, MfcT Mfc>
127  auto operator()(Class* that, member_function_constant<MfcT, Mfc> func)
128  -> callback_invoker& {
129  this->_callback = _callback_t{that, func};
130  return *this;
131  }
132 
133  template <typename Class, typename MfcT, MfcT Mfc>
134  auto operator()(const Class* that, member_function_constant<MfcT, Mfc> func)
135  -> callback_invoker& {
136  this->_callback = _callback_t{that, func};
137  return *this;
138  }
139 
140  template <typename... Args>
141  auto invoke_on(
142  endpoint& bus,
143  identifier_t target_id,
144  message_id msg_id,
145  memory::block buffer,
146  Args&&... args) -> bool {
147  auto tupl{std::tie(std::forward<Args>(args)...)};
148 
149  _sink.reset(buffer);
150  Serializer write_backend(_sink);
151 
152  const auto errors = serialize(tupl, write_backend);
153  if(!errors) {
154  message_view message{_sink.done()};
155  message.set_serializer_id(write_backend.type_id());
156  message.set_target_id(target_id);
157  bus.post(msg_id, message);
158 
159  return true;
160  }
161  return false;
162  }
163 
164  template <typename... Args>
165  auto invoke_on(
166  endpoint& bus,
167  identifier_t target_id,
168  message_id msg_id,
169  Args&&... args) -> bool {
170  std::array<byte, MaxDataSize> temp{};
171  return invoke_on(
172  bus, target_id, msg_id, cover(temp), std::forward<Args>(args)...);
173  }
174 
175  constexpr auto map_fulfill_by(message_id msg_id) noexcept {
176  return std::
177  tuple<base*, message_handler_map<EAGINE_MEM_FUNC_T(base, fulfill_by)>>(
178  this, msg_id);
179  }
180 
181  constexpr auto operator[](message_id msg_id) noexcept {
182  return map_fulfill_by(msg_id);
183  }
184 
185 private:
186  Sink _sink{};
187 };
188 //------------------------------------------------------------------------------
189 template <typename Result, typename Deserializer, typename Source>
190 class invoker_base {
191 public:
192  auto fulfill_by(const message_context&, stored_message& message) -> bool {
193  const auto invocation_id = message.sequence_no;
194  std::remove_cv_t<std::remove_reference_t<Result>> result{};
195 
196  _source.reset(message.content());
197  Deserializer read_backend(_source);
198 
199  if(message.has_serializer_id(read_backend.type_id())) {
200  const auto errors{deserialize(result, read_backend)};
201  if(!errors) {
202  _results.fulfill(invocation_id, result);
203  }
204  }
205  return true;
206  }
207 
208  constexpr auto map_fulfill_by(message_id msg_id) noexcept {
209  return std::tuple<
210  invoker_base*,
211  message_handler_map<EAGINE_MEM_FUNC_T(invoker_base, fulfill_by)>>(
212  this, msg_id);
213  }
214 
215  constexpr auto operator[](message_id msg_id) noexcept {
216  return map_fulfill_by(msg_id);
217  }
218 
219  auto has_pending() const noexcept -> bool {
220  return _results.has_some();
221  }
222 
223  auto is_done() const noexcept -> bool {
224  return _results.has_none();
225  }
226 
227 protected:
228  pending_promises<Result> _results{};
229 
230 private:
231  Source _source{};
232 };
233 //------------------------------------------------------------------------------
234 template <
235  typename Signature,
236  typename Serializer,
237  typename Deserializer,
238  typename Sink,
239  typename Source,
240  std::size_t MaxDataSize>
241 class invoker;
242 //------------------------------------------------------------------------------
243 template <
244  typename Result,
245  typename... Params,
246  typename Serializer,
247  typename Deserializer,
248  typename Sink,
249  typename Source,
250  std::size_t MaxDataSize>
251 class invoker<Result(Params...), Serializer, Deserializer, Sink, Source, MaxDataSize>
252  : public invoker_base<Result, Deserializer, Source> {
253 public:
254  auto invoke_on(
255  endpoint& bus,
256  identifier_t target_id,
257  message_id msg_id,
258  memory::block buffer,
259  std::add_lvalue_reference_t<std::add_const_t<Params>>... args)
260  -> future<Result> {
261  auto [invocation_id, result] = this->_results.make();
262 
263  auto tupl{std::tie(args...)};
264 
265  block_data_sink sink(buffer);
266  Serializer write_backend(sink);
267 
268  const auto errors = serialize(tupl, write_backend);
269  if(!errors) {
270  message_view message{sink.done()};
271  message.set_serializer_id(write_backend.type_id());
272  message.set_target_id(target_id);
273  message.set_sequence_no(invocation_id);
274  bus.post(msg_id, message);
275 
276  return result;
277  }
278  return nothing;
279  }
280 
281  auto invoke_on(
282  endpoint& bus,
283  identifier_t target_id,
284  message_id msg_id,
285  std::add_lvalue_reference_t<std::add_const_t<Params>>... args)
286  -> future<Result> {
287  std::array<byte, MaxDataSize> buffer{};
288  return invoke_on(bus, target_id, msg_id, cover(buffer), args...);
289  }
290 
291  auto invoke(
292  endpoint& bus,
293  message_id msg_id,
294  std::add_lvalue_reference_t<std::add_const_t<Params>>... args)
295  -> future<Result> {
296  return invoke_on(bus, broadcast_endpoint_id(), msg_id, args...);
297  }
298 };
299 //------------------------------------------------------------------------------
300 template <
301  typename Result,
302  typename Serializer,
303  typename Deserializer,
304  typename Sink,
305  typename Source,
306  std::size_t MaxDataSize>
307 class invoker<Result(), Serializer, Deserializer, Sink, Source, MaxDataSize>
308  : public invoker_base<Result, Deserializer, Source> {
309 public:
310  auto invoke_on(
311  endpoint& bus,
312  identifier_t target_id,
313  message_id msg_id,
314  memory::block) -> future<Result> {
315  auto [invocation_id, result] = this->_results.make();
316 
317  message_view message{};
318  message.set_target_id(target_id);
319  message.set_sequence_no(invocation_id);
320  bus.post(msg_id, message);
321 
322  return result;
323  }
324 
325  auto invoke_on(endpoint& bus, identifier_t target_id, message_id msg_id)
326  -> future<Result> {
327  return invoke_on(bus, target_id, msg_id, {});
328  }
329 
330  auto invoke(endpoint& bus, message_id msg_id) -> future<Result> {
331  return invoke_on(bus, broadcast_endpoint_id(), msg_id);
332  }
333 };
334 //------------------------------------------------------------------------------
335 } // namespace eagine::msgbus
336 
337 #endif // EAGINE_MESSAGE_BUS_INVOKER_HPP
static constexpr auto cover(T *addr, S size) noexcept -> span_if_mutable< T >
Creates a span starting at the specified pointer and specified length.
Definition: span.hpp:465
basic_callable_ref< Sig, is_noexcept_function_v< Sig > > callable_ref
Alias for callable object references.
Definition: callable_ref.hpp:191
basic_block< false > block
Alias for non-const byte memory span.
Definition: block.hpp:27
static constexpr auto broadcast_endpoint_id() noexcept -> identifier_t
Returns the special broadcase message bus endpoint id.
Definition: message.hpp:42
auto deserialize(T &value, Backend &backend) -> std::enable_if_t< std::is_base_of_v< deserializer_backend, Backend >, deserialization_errors >
Deserializes a value with the specified serialization backend.
Definition: read.hpp:475
std::uint32_t message_sequence_t
Alias for message sequence number type.
Definition: types.hpp:22
auto serialize(T &value, Backend &backend) -> std::enable_if_t< std::is_base_of_v< serializer_backend, Backend >, serialization_errors >
Serializes a value with the specified serialization backend.
Definition: write.hpp:480
@ source_id
The source has been verified.
Message bus code is placed in this namespace.
Definition: eagine.hpp:58
#define EAGINE_MEM_FUNC_T(CLASS, FUNC)
Macro for instantiating the member_function_constant template.
Definition: mem_func_const.hpp:179
std::uint64_t identifier_t
The underlying integer type for eagine::identifier.
Definition: identifier_t.hpp:19
static constexpr nothing_t nothing
Constant of nothing_t type.
Definition: nothing.hpp:30

Copyright © 2015-2021 Matúš Chochlík.
<chochlik -at -gmail.com>
Documentation generated on Tue Apr 13 2021 by Doxygen (version 1.8.17).