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/send_functions.hpp>
15 
16 #include <so_5/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 >
79  [[nodiscard]]
80  payload_holder_t
81  envelope( Args && ...args )
82  {
83  ensure_not_empty_object( "envelope()" );
84 
85  message_ref_t envelope{
86  std::make_unique< Envelope >(
87  m_data->m_message,
88  std::forward<Args>(args)... )
89  };
90 
91  payload_holder_t result{
92  m_data->m_msg_type,
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
104  send_to( Target && to )
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.
110  so_5::send_functions_details::arg_to_mbox( to )->
111  do_deliver_message(
112  so_5::message_delivery_mode_t::ordinary,
113  m_data->m_msg_type,
114  m_data->m_message,
115  1u );
116  }
117 
118  void
120  const so_5::mbox_t & to,
121  std::chrono::steady_clock::duration pause )
122  {
123  ensure_not_empty_object( "send_delayed_to()" );
124 
125  so_5::low_level_api::single_timer(
126  m_data->m_msg_type,
127  m_data->m_message,
128  to,
129  pause );
130  }
131 
132  template< typename Target >
133  void
135  Target && to,
136  std::chrono::steady_clock::duration pause )
137  {
138  return this->send_delayed_to(
139  so_5::send_functions_details::arg_to_mbox( to ),
140  pause );
141  }
142 
143  [[nodiscard]]
144  auto
146  const so_5::mbox_t & to,
147  std::chrono::steady_clock::duration pause,
148  std::chrono::steady_clock::duration period )
149  {
150  ensure_not_empty_object( "send_periodic_to()" );
151 
152  return so_5::low_level_api::schedule_timer(
153  m_data->m_msg_type,
154  m_data->m_message,
155  to,
156  pause,
157  period );
158  }
159 
160  template< typename Target >
161  [[nodiscard]]
162  auto
164  Target && to,
165  std::chrono::steady_clock::duration pause,
166  std::chrono::steady_clock::duration period )
167  {
168  return this->send_periodic_to(
169  so_5::send_functions_details::arg_to_mbox( to ),
170  pause,
171  period );
172  }
173  };
174 
175 } /* namespace details */
176 
177 /*!
178  * \brief A special message builder that allows to wrap a message into an
179  * envelope.
180  *
181  * This function creates an instance of a specified message type and creates
182  * a chain of builders that envelope this instance into an envelope and send
183  * the enveloped message as ordinary or delayed/periodic message.
184  *
185  * Usage examples:
186  * \code
187  * namespace msg_ns = so_5::extra::enveloped_msg;
188  *
189  * // Create message of type my_message, envelop it into my_envelope
190  * // and then send it to the mbox mb1.
191  * so_5::mbox_t mb1 = ...;
192  * msg_ns::make<my_message>(...)
193  * .envelope<my_envelope>(...)
194  * .send_to(mb1);
195  *
196  * // Create message of type my_message, envelop it into my_envelope
197  * // and then send it to the mchain ch1.
198  * so_5::mchain_t ch1 = ...;
199  * msg_ns::make<my_message>(...)
200  * .envelope<my_envelope>(...)
201  * .send_to(ch1);
202  *
203  * // Create message of type my_message, envelop it into my_envelope
204  * // and then send it to the direct mbox of the agent a1.
205  * so_5::agent_t & a1 = ...;
206  * msg_ns::make<my_message>(...)
207  * .envelope<my_envelope>(...)
208  * .send_to(a1);
209  *
210  * // Create message of type my_message, envelop it into my_envelope
211  * // and then send it to the mbox mb1 as delayed message.
212  * so_5::mbox_t mb1 = ...;
213  * msg_ns::make<my_message>(...)
214  * .envelope<my_envelope>(...)
215  * .send_delayed_to(mb1, 10s);
216  *
217  * // Create message of type my_message, envelop it into my_envelope
218  * // and then send it to the mchain ch1 as delayed message.
219  * so_5::mchain_t ch1 = ...;
220  * msg_ns::make<my_message>(...)
221  * .envelope<my_envelope>(...)
222  * .send_delayed_to(ch1, 10s);
223  *
224  * // Create message of type my_message, envelop it into my_envelope
225  * // and then send it to the direct mbox of the agent a1 as delayed message.
226  * so_5::agent_t & a1 = ...;
227  * msg_ns::make<my_message>(...)
228  * .envelope<my_envelope>(...)
229  * .send_delayed_to(a1, 10s);
230  *
231  * // Create message of type my_message, envelop it into my_envelope
232  * // and then send it to the mbox mb1 as periodic message.
233  * so_5::mbox_t mb1 = ...;
234  * auto timer_id = msg_ns::make<my_message>(...)
235  * .envelope<my_envelope>(...)
236  * .send_periodic_to(mb1, 10s, 30s);
237  *
238  * // Create message of type my_message, envelop it into my_envelope
239  * // and then send it to the mchain ch1 as delayed message.
240  * so_5::mchain_t ch1 = ...;
241  * auto timer_id = msg_ns::make<my_message>(...)
242  * .envelope<my_envelope>(...)
243  * .send_periodic_to(ch1, 10s, 30s);
244  *
245  * // Create message of type my_message, envelop it into my_envelope
246  * // and then send it to the direct mbox of the agent a1 as delayed message.
247  * so_5::agent_t & a1 = ...;
248  * auto timer_id = msg_ns::make<my_message>(...)
249  * .envelope<my_envelope>(...)
250  * .send_periodic_to(a1, 10s, 30s);
251  * \endcode
252  *
253  * \since
254  * v.1.2.0
255  */
256 template< typename Message, typename... Args >
257 [[nodiscard]]
258 details::payload_holder_t
259 make( Args && ...args )
260  {
263  std::forward<Args>(args)... )
264  };
265 
267 
268  return {
270  std::move(message)
271  };
272  }
273 
274 } /* namespace enveloped_msg */
275 
276 } /* namespace extra */
277 
278 } /* namespace so_5 */
auto send_periodic_to(const so_5::mbox_t &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)
void send_delayed_to(Target &&to, std::chrono::steady_clock::duration pause)
auto send_periodic_to(Target &&to, std::chrono::steady_clock::duration pause, std::chrono::steady_clock::duration period)
Ranges for error codes of each submodules.
Definition: details.hpp:13
void send_delayed_to(const so_5::mbox_t &to, std::chrono::steady_clock::duration pause)
payload_holder_t(const payload_holder_t &)=delete
details::payload_holder_t make(Args &&...args)
A special message builder that allows to wrap a message into an envelope.
void ensure_not_empty_object(const char *context_name) const
payload_holder_t & operator=(payload_holder_t &&)=default