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