SObjectizer-5 Extra
send_functions.hpp
Go to the documentation of this file.
1 /*!
2  * \file
3  * \brief Variuos send functions for simplification of sending
4  * enveloped messages.
5  *
6  * \since
7  * v.1.2.0
8  */
9 
10 #pragma once
11 
12 #include <so_5_extra/enveloped_msg/errors.hpp>
13 
14 #include <so_5/rt/h/send_functions.hpp>
15 
16 #include <so_5/h/optional.hpp>
17 
18 namespace so_5 {
19 
20 namespace extra {
21 
22 namespace enveloped_msg {
23 
24 namespace details {
25 
26 /*!
27  * \brief Internal type that holds a message before it will be enveloped.
28  *
29  * This type provides such methods as:
30  * - envelope() for creation of new envelope;
31  * - send_to for sending of ordinary message to the specified mbox (mchain);
32  * - send_delayed_to for sending of delayed message;
33  * - send_periodic_to for sending of periodic message.
34  *
35  * \note
36  * Object of type payload_holder_t can be in two states: full and empty.
37  * When object is full then envelope() creates an envelope and switches
38  * the object to empty state. If envelope() is called in empty state
39  * an exeception is thrown.
40  *
41  * \since
42  * v.1.2.0
43  */
44 class payload_holder_t final
45  {
46  struct data_t final
47  {
49  // Can be null pointer in the case of error.
51  };
52 
54 
55  void
57  const char * context_name ) const
58  {
59  if( !m_data )
60  SO_5_THROW_EXCEPTION(
61  errors::rc_empty_payload_holder,
62  std::string( "empty payload_holder can't be used for: " ) +
63  context_name );
64  }
65 
66  public :
68  std::type_index msg_type,
69  message_ref_t message )
70  : m_data{ data_t{ msg_type, message } }
71  {}
72 
73  payload_holder_t( const payload_holder_t & ) = delete;
74 
75  payload_holder_t( payload_holder_t && ) = default;
76  payload_holder_t & operator=( payload_holder_t && ) = default;
77 
78  template< typename Envelope, typename... Args >
81  envelope( Args && ...args )
82  {
83  ensure_not_empty_object( "envelope()" );
84 
88  std::forward<Args>(args)... )
89  };
90 
93  std::move(envelope)
94  };
95 
96  // Now data can be dropped. Payload holder becomes empty.
97  m_data.reset();
98 
99  return result;
100  }
101 
102  template< typename Target >
103  void
105  {
106  ensure_not_empty_object( "send_to()" );
107 
108  // NOTE: there is no need to check mutability of a message.
109  // This check should be performed by the target mbox itself.
113  m_data->m_message,
114  1u );
115  }
116 
117  void
120  const so_5::mbox_t & to,
122  {
123  ensure_not_empty_object( "send_delayed_to()" );
124 
127  m_data->m_message,
128  to,
129  pause );
130  }
131 
132  template< typename Target >
133  void
135  Target && to,
137  {
138  return this->send_delayed_to(
141  pause );
142  }
143 
145  auto
148  const so_5::mbox_t & to,
151  {
152  ensure_not_empty_object( "send_periodic_to()" );
153 
154  return env.schedule_timer(
156  m_data->m_message,
157  to,
158  pause,
159  period );
160  }
161 
162  template< typename Target >
164  auto
166  Target && to,
169  {
170  return this->send_periodic_to(
173  pause,
174  period );
175  }
176  };
177 
178 } /* namespace details */
179 
180 /*!
181  * \brief A special message builder that allows to wrap a message into an
182  * envelope.
183  *
184  * This function creates an instance of a specified message type and creates
185  * a chain of builders that envelope this instance into an envelope and send
186  * the enveloped message as ordinary or delayed/periodic message.
187  *
188  * Usage examples:
189  * \code
190  * namespace msg_ns = so_5::extra::enveloped_msg;
191  *
192  * // Create message of type my_message, envelop it into my_envelope
193  * // and then send it to the mbox mb1.
194  * so_5::mbox_t mb1 = ...;
195  * msg_ns::make<my_message>(...)
196  * .envelope<my_envelope>(...)
197  * .send_to(mb1);
198  *
199  * // Create message of type my_message, envelop it into my_envelope
200  * // and then send it to the mchain ch1.
201  * so_5::mchain_t ch1 = ...;
202  * msg_ns::make<my_message>(...)
203  * .envelope<my_envelope>(...)
204  * .send_to(ch1);
205  *
206  * // Create message of type my_message, envelop it into my_envelope
207  * // and then send it to the direct mbox of the agent a1.
208  * so_5::agent_t & a1 = ...;
209  * msg_ns::make<my_message>(...)
210  * .envelope<my_envelope>(...)
211  * .send_to(a1);
212  *
213  * // Create message of type my_message, envelop it into my_envelope
214  * // and then send it to the mbox mb1 as delayed message.
215  * // Note that the reference to SObjectizer Environment is necessary.
216  * so_5::environment_t & env = ...;
217  * so_5::mbox_t mb1 = ...;
218  * msg_ns::make<my_message>(...)
219  * .envelope<my_envelope>(...)
220  * .send_delayed_to(env, mb1, 10s);
221  *
222  * // Create message of type my_message, envelop it into my_envelope
223  * // and then send it to the mchain ch1 as delayed message.
224  * so_5::mchain_t ch1 = ...;
225  * msg_ns::make<my_message>(...)
226  * .envelope<my_envelope>(...)
227  * .send_delayed_to(ch1, 10s);
228  *
229  * // Create message of type my_message, envelop it into my_envelope
230  * // and then send it to the direct mbox of the agent a1 as delayed message.
231  * so_5::agent_t & a1 = ...;
232  * msg_ns::make<my_message>(...)
233  * .envelope<my_envelope>(...)
234  * .send_delayed_to(a1, 10s);
235  *
236  * // Create message of type my_message, envelop it into my_envelope
237  * // and then send it to the mbox mb1 as periodic message.
238  * // Note that the reference to SObjectizer Environment is necessary.
239  * so_5::environment_t & env = ...;
240  * so_5::mbox_t mb1 = ...;
241  * auto timer_id = msg_ns::make<my_message>(...)
242  * .envelope<my_envelope>(...)
243  * .send_periodic_to(env, mb1, 10s, 30s);
244  *
245  * // Create message of type my_message, envelop it into my_envelope
246  * // and then send it to the mchain ch1 as delayed message.
247  * so_5::mchain_t ch1 = ...;
248  * auto timer_id = msg_ns::make<my_message>(...)
249  * .envelope<my_envelope>(...)
250  * .send_periodic_to(ch1, 10s, 30s);
251  *
252  * // Create message of type my_message, envelop it into my_envelope
253  * // and then send it to the direct mbox of the agent a1 as delayed message.
254  * so_5::agent_t & a1 = ...;
255  * auto timer_id = msg_ns::make<my_message>(...)
256  * .envelope<my_envelope>(...)
257  * .send_periodic_to(a1, 10s, 30s);
258  * \endcode
259  *
260  * \since
261  * v.1.2.0
262  */
263 template< typename Message, typename... Args >
264 SO_5_NODISCARD
265 details::payload_holder_t
266 make( Args && ...args )
267  {
268  message_ref_t message{
269  so_5::details::make_message_instance< Message >(
270  std::forward<Args>(args)... )
271  };
272 
273  so_5::details::mark_as_mutable_if_necessary< Message >( *message );
274 
275  return {
276  message_payload_type< Message >::subscription_type_index(),
277  std::move(message)
278  };
279  }
280 
281 } /* namespace enveloped_msg */
282 
283 } /* namespace extra */
284 
285 } /* namespace so_5 */
SO_5_NODISCARD auto send_periodic_to(Target &&to, std::chrono::steady_clock::duration pause, std::chrono::steady_clock::duration period)
payload_holder_t(std::type_index msg_type, message_ref_t message)
Ranges for error codes of each submodules.
Definition: details.hpp:14
payload_holder_t(const payload_holder_t &)=delete
void ensure_not_empty_object(const char *context_name) const
SO_5_NODISCARD details::payload_holder_t make(Args &&...args)
A special message builder that allows to wrap a message into an envelope.
payload_holder_t & operator=(payload_holder_t &&)=default