1 //
2 // execution/connect.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10 
11 #ifndef BOOST_ASIO_EXECUTION_CONNECT_HPP
12 #define BOOST_ASIO_EXECUTION_CONNECT_HPP
13 
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17 
18 #include <boost/asio/detail/config.hpp>
19 #include <boost/asio/detail/type_traits.hpp>
20 #include <boost/asio/execution/detail/as_invocable.hpp>
21 #include <boost/asio/execution/detail/as_operation.hpp>
22 #include <boost/asio/execution/detail/as_receiver.hpp>
23 #include <boost/asio/execution/executor.hpp>
24 #include <boost/asio/execution/operation_state.hpp>
25 #include <boost/asio/execution/receiver.hpp>
26 #include <boost/asio/execution/sender.hpp>
27 #include <boost/asio/traits/connect_member.hpp>
28 #include <boost/asio/traits/connect_free.hpp>
29 
30 #include <boost/asio/detail/push_options.hpp>
31 
32 #if defined(GENERATING_DOCUMENTATION)
33 
34 namespace boost {
35 namespace asio {
36 namespace execution {
37 
38 /// A customisation point that connects a sender to a receiver.
39 /**
40  * The name <tt>execution::connect</tt> denotes a customisation point object.
41  * For some subexpressions <tt>s</tt> and <tt>r</tt>, let <tt>S</tt> be a type
42  * such that <tt>decltype((s))</tt> is <tt>S</tt> and let <tt>R</tt> be a type
43  * such that <tt>decltype((r))</tt> is <tt>R</tt>. The expression
44  * <tt>execution::connect(s, r)</tt> is expression-equivalent to:
45  *
46  * @li <tt>s.connect(r)</tt>, if that expression is valid, if its type
47  *   satisfies <tt>operation_state</tt>, and if <tt>S</tt> satisfies
48  *   <tt>sender</tt>.
49  *
50  * @li Otherwise, <tt>connect(s, r)</tt>, if that expression is valid, if its
51  *   type satisfies <tt>operation_state</tt>, and if <tt>S</tt> satisfies
52  *   <tt>sender</tt>, with overload resolution performed in a context that
53  *   includes the declaration <tt>void connect();</tt> and that does not include
54  *   a declaration of <tt>execution::connect</tt>.
55  *
56  * @li Otherwise, <tt>as_operation{s, r}</tt>, if <tt>r</tt> is not an instance
57  *  of <tt>as_receiver<F, S></tt> for some type <tt>F</tt>, and if
58  *  <tt>receiver_of<R> && executor_of<remove_cvref_t<S>,
59  *  as_invocable<remove_cvref_t<R>, S>></tt> is <tt>true</tt>, where
60  *  <tt>as_operation</tt> is an implementation-defined class equivalent to
61  *  @code template <class S, class R>
62  *  struct as_operation
63  *  {
64  *    remove_cvref_t<S> e_;
65  *    remove_cvref_t<R> r_;
66  *    void start() noexcept try {
67  *      execution::execute(std::move(e_),
68  *          as_invocable<remove_cvref_t<R>, S>{r_});
69  *    } catch(...) {
70  *      execution::set_error(std::move(r_), current_exception());
71  *    }
72  *  }; @endcode
73  *  and <tt>as_invocable</tt> is a class template equivalent to the following:
74  *  @code template<class R>
75  *  struct as_invocable
76  *  {
77  *    R* r_;
78  *    explicit as_invocable(R& r) noexcept
79  *      : r_(std::addressof(r)) {}
80  *    as_invocable(as_invocable && other) noexcept
81  *      : r_(std::exchange(other.r_, nullptr)) {}
82  *    ~as_invocable() {
83  *      if(r_)
84  *        execution::set_done(std::move(*r_));
85  *    }
86  *    void operator()() & noexcept try {
87  *      execution::set_value(std::move(*r_));
88  *      r_ = nullptr;
89  *    } catch(...) {
90  *      execution::set_error(std::move(*r_), current_exception());
91  *      r_ = nullptr;
92  *    }
93  *  };
94  *  @endcode
95  *
96  * @li Otherwise, <tt>execution::connect(s, r)</tt> is ill-formed.
97  */
98 inline constexpr unspecified connect = unspecified;
99 
100 /// A type trait that determines whether a @c connect expression is
101 /// well-formed.
102 /**
103  * Class template @c can_connect is a trait that is derived from
104  * @c true_type if the expression <tt>execution::connect(std::declval<S>(),
105  * std::declval<R>())</tt> is well formed; otherwise @c false_type.
106  */
107 template <typename S, typename R>
108 struct can_connect :
109   integral_constant<bool, automatically_determined>
110 {
111 };
112 
113 /// A type trait to determine the result of a @c connect expression.
114 template <typename S, typename R>
115 struct connect_result
116 {
117   /// The type of the connect expression.
118   /**
119    * The type of the expression <tt>execution::connect(std::declval<S>(),
120    * std::declval<R>())</tt>.
121    */
122   typedef automatically_determined type;
123 };
124 
125 /// A type alis to determine the result of a @c connect expression.
126 template <typename S, typename R>
127 using connect_result_t = typename connect_result<S, R>::type;
128 
129 } // namespace execution
130 } // namespace asio
131 } // namespace boost
132 
133 #else // defined(GENERATING_DOCUMENTATION)
134 
135 namespace asio_execution_connect_fn {
136 
137 using boost::asio::conditional;
138 using boost::asio::declval;
139 using boost::asio::enable_if;
140 using boost::asio::execution::detail::as_invocable;
141 using boost::asio::execution::detail::as_operation;
142 using boost::asio::execution::detail::is_as_receiver;
143 using boost::asio::execution::is_executor_of;
144 using boost::asio::execution::is_operation_state;
145 using boost::asio::execution::is_receiver;
146 using boost::asio::execution::is_sender;
147 using boost::asio::false_type;
148 using boost::asio::remove_cvref;
149 using boost::asio::traits::connect_free;
150 using boost::asio::traits::connect_member;
151 
152 void connect();
153 
154 enum overload_type
155 {
156   call_member,
157   call_free,
158   adapter,
159   ill_formed
160 };
161 
162 template <typename S, typename R, typename = void,
163    typename = void, typename = void, typename = void>
164 struct call_traits
165 {
166   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);
167   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
168   typedef void result_type;
169 };
170 
171 template <typename S, typename R>
172 struct call_traits<S, void(R),
173   typename enable_if<
174     connect_member<S, R>::is_valid
175   >::type,
176   typename enable_if<
177     is_operation_state<typename connect_member<S, R>::result_type>::value
178   >::type,
179   typename enable_if<
180     is_sender<typename remove_cvref<S>::type>::value
181   >::type> :
182   connect_member<S, R>
183 {
184   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);
185 };
186 
187 template <typename S, typename R>
188 struct call_traits<S, void(R),
189   typename enable_if<
190     !connect_member<S, R>::is_valid
191   >::type,
192   typename enable_if<
193     connect_free<S, R>::is_valid
194   >::type,
195   typename enable_if<
196     is_operation_state<typename connect_free<S, R>::result_type>::value
197   >::type,
198   typename enable_if<
199     is_sender<typename remove_cvref<S>::type>::value
200   >::type> :
201   connect_free<S, R>
202 {
203   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);
204 };
205 
206 template <typename S, typename R>
207 struct call_traits<S, void(R),
208   typename enable_if<
209     !connect_member<S, R>::is_valid
210   >::type,
211   typename enable_if<
212     !connect_free<S, R>::is_valid
213   >::type,
214   typename enable_if<
215     is_receiver<R>::value
216   >::type,
217   typename enable_if<
218     conditional<
219       !is_as_receiver<
220         typename remove_cvref<R>::type
221       >::value,
222       is_executor_of<
223         typename remove_cvref<S>::type,
224         as_invocable<typename remove_cvref<R>::type, S>
225       >,
226       false_type
227     >::type::value
228   >::type>
229 {
230   BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = adapter);
231   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
232   typedef as_operation<S, R> result_type;
233 };
234 
235 struct impl
236 {
237 #if defined(BOOST_ASIO_HAS_MOVE)
238   template <typename S, typename R>
239   BOOST_ASIO_CONSTEXPR typename enable_if<
240     call_traits<S, void(R)>::overload == call_member,
241     typename call_traits<S, void(R)>::result_type
242   >::type
operator ()asio_execution_connect_fn::impl243   operator()(S&& s, R&& r) const
244     BOOST_ASIO_NOEXCEPT_IF((
245       call_traits<S, void(R)>::is_noexcept))
246   {
247     return BOOST_ASIO_MOVE_CAST(S)(s).connect(BOOST_ASIO_MOVE_CAST(R)(r));
248   }
249 
250   template <typename S, typename R>
251   BOOST_ASIO_CONSTEXPR typename enable_if<
252     call_traits<S, void(R)>::overload == call_free,
253     typename call_traits<S, void(R)>::result_type
254   >::type
operator ()asio_execution_connect_fn::impl255   operator()(S&& s, R&& r) const
256     BOOST_ASIO_NOEXCEPT_IF((
257       call_traits<S, void(R)>::is_noexcept))
258   {
259     return connect(BOOST_ASIO_MOVE_CAST(S)(s), BOOST_ASIO_MOVE_CAST(R)(r));
260   }
261 
262   template <typename S, typename R>
263   BOOST_ASIO_CONSTEXPR typename enable_if<
264     call_traits<S, void(R)>::overload == adapter,
265     typename call_traits<S, void(R)>::result_type
266   >::type
operator ()asio_execution_connect_fn::impl267   operator()(S&& s, R&& r) const
268     BOOST_ASIO_NOEXCEPT_IF((
269       call_traits<S, void(R)>::is_noexcept))
270   {
271     return typename call_traits<S, void(R)>::result_type(
272         BOOST_ASIO_MOVE_CAST(S)(s), BOOST_ASIO_MOVE_CAST(R)(r));
273   }
274 #else // defined(BOOST_ASIO_HAS_MOVE)
275   template <typename S, typename R>
276   BOOST_ASIO_CONSTEXPR typename enable_if<
277     call_traits<S&, void(R&)>::overload == call_member,
278     typename call_traits<S&, void(R&)>::result_type
279   >::type
280   operator()(S& s, R& r) const
281     BOOST_ASIO_NOEXCEPT_IF((
282       call_traits<S&, void(R&)>::is_noexcept))
283   {
284     return s.connect(r);
285   }
286 
287   template <typename S, typename R>
288   BOOST_ASIO_CONSTEXPR typename enable_if<
289     call_traits<const S&, void(R&)>::overload == call_member,
290     typename call_traits<const S&, void(R&)>::result_type
291   >::type
292   operator()(const S& s, R& r) const
293     BOOST_ASIO_NOEXCEPT_IF((
294       call_traits<const S&, void(R&)>::is_noexcept))
295   {
296     return s.connect(r);
297   }
298 
299   template <typename S, typename R>
300   BOOST_ASIO_CONSTEXPR typename enable_if<
301     call_traits<S&, void(R&)>::overload == call_free,
302     typename call_traits<S&, void(R&)>::result_type
303   >::type
304   operator()(S& s, R& r) const
305     BOOST_ASIO_NOEXCEPT_IF((
306       call_traits<S&, void(R&)>::is_noexcept))
307   {
308     return connect(s, r);
309   }
310 
311   template <typename S, typename R>
312   BOOST_ASIO_CONSTEXPR typename enable_if<
313     call_traits<const S&, void(R&)>::overload == call_free,
314     typename call_traits<const S&, void(R&)>::result_type
315   >::type
316   operator()(const S& s, R& r) const
317     BOOST_ASIO_NOEXCEPT_IF((
318       call_traits<const S&, void(R&)>::is_noexcept))
319   {
320     return connect(s, r);
321   }
322 
323   template <typename S, typename R>
324   BOOST_ASIO_CONSTEXPR typename enable_if<
325     call_traits<S&, void(R&)>::overload == adapter,
326     typename call_traits<S&, void(R&)>::result_type
327   >::type
328   operator()(S& s, R& r) const
329     BOOST_ASIO_NOEXCEPT_IF((
330       call_traits<S&, void(R&)>::is_noexcept))
331   {
332     return typename call_traits<S&, void(R&)>::result_type(s, r);
333   }
334 
335   template <typename S, typename R>
336   BOOST_ASIO_CONSTEXPR typename enable_if<
337     call_traits<const S&, void(R&)>::overload == adapter,
338     typename call_traits<const S&, void(R&)>::result_type
339   >::type
340   operator()(const S& s, R& r) const
341     BOOST_ASIO_NOEXCEPT_IF((
342       call_traits<const S&, void(R&)>::is_noexcept))
343   {
344     return typename call_traits<const S&, void(R&)>::result_type(s, r);
345   }
346 
347   template <typename S, typename R>
348   BOOST_ASIO_CONSTEXPR typename enable_if<
349     call_traits<S&, void(const R&)>::overload == call_member,
350     typename call_traits<S&, void(const R&)>::result_type
351   >::type
352   operator()(S& s, const R& r) const
353     BOOST_ASIO_NOEXCEPT_IF((
354       call_traits<S&, void(const R&)>::is_noexcept))
355   {
356     return s.connect(r);
357   }
358 
359   template <typename S, typename R>
360   BOOST_ASIO_CONSTEXPR typename enable_if<
361     call_traits<const S&, void(const R&)>::overload == call_member,
362     typename call_traits<const S&, void(const R&)>::result_type
363   >::type
364   operator()(const S& s, const R& r) const
365     BOOST_ASIO_NOEXCEPT_IF((
366       call_traits<const S&, void(const R&)>::is_noexcept))
367   {
368     return s.connect(r);
369   }
370 
371   template <typename S, typename R>
372   BOOST_ASIO_CONSTEXPR typename enable_if<
373     call_traits<S&, void(const R&)>::overload == call_free,
374     typename call_traits<S&, void(const R&)>::result_type
375   >::type
376   operator()(S& s, const R& r) const
377     BOOST_ASIO_NOEXCEPT_IF((
378       call_traits<S&, void(const R&)>::is_noexcept))
379   {
380     return connect(s, r);
381   }
382 
383   template <typename S, typename R>
384   BOOST_ASIO_CONSTEXPR typename enable_if<
385     call_traits<const S&, void(const R&)>::overload == call_free,
386     typename call_traits<const S&, void(const R&)>::result_type
387   >::type
388   operator()(const S& s, const R& r) const
389     BOOST_ASIO_NOEXCEPT_IF((
390       call_traits<const S&, void(const R&)>::is_noexcept))
391   {
392     return connect(s, r);
393   }
394 
395   template <typename S, typename R>
396   BOOST_ASIO_CONSTEXPR typename enable_if<
397     call_traits<S&, void(const R&)>::overload == adapter,
398     typename call_traits<S&, void(const R&)>::result_type
399   >::type
400   operator()(S& s, const R& r) const
401     BOOST_ASIO_NOEXCEPT_IF((
402       call_traits<S&, void(const R&)>::is_noexcept))
403   {
404     return typename call_traits<S&, void(const R&)>::result_type(s, r);
405   }
406 
407   template <typename S, typename R>
408   BOOST_ASIO_CONSTEXPR typename enable_if<
409     call_traits<const S&, void(const R&)>::overload == adapter,
410     typename call_traits<const S&, void(const R&)>::result_type
411   >::type
412   operator()(const S& s, const R& r) const
413     BOOST_ASIO_NOEXCEPT_IF((
414       call_traits<const S&, void(const R&)>::is_noexcept))
415   {
416     return typename call_traits<const S&, void(const R&)>::result_type(s, r);
417   }
418 #endif // defined(BOOST_ASIO_HAS_MOVE)
419 };
420 
421 template <typename T = impl>
422 struct static_instance
423 {
424   static const T instance;
425 };
426 
427 template <typename T>
428 const T static_instance<T>::instance = {};
429 
430 } // namespace asio_execution_connect_fn
431 namespace boost {
432 namespace asio {
433 namespace execution {
434 namespace {
435 
436 static BOOST_ASIO_CONSTEXPR const asio_execution_connect_fn::impl&
437   connect = asio_execution_connect_fn::static_instance<>::instance;
438 
439 } // namespace
440 
441 template <typename S, typename R>
442 struct can_connect :
443   integral_constant<bool,
444     asio_execution_connect_fn::call_traits<S, void(R)>::overload !=
445       asio_execution_connect_fn::ill_formed>
446 {
447 };
448 
449 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
450 
451 template <typename S, typename R>
452 constexpr bool can_connect_v = can_connect<S, R>::value;
453 
454 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
455 
456 template <typename S, typename R>
457 struct is_nothrow_connect :
458   integral_constant<bool,
459     asio_execution_connect_fn::call_traits<S, void(R)>::is_noexcept>
460 {
461 };
462 
463 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
464 
465 template <typename S, typename R>
466 constexpr bool is_nothrow_connect_v
467   = is_nothrow_connect<S, R>::value;
468 
469 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
470 
471 template <typename S, typename R>
472 struct connect_result
473 {
474   typedef typename asio_execution_connect_fn::call_traits<
475       S, void(R)>::result_type type;
476 };
477 
478 #if defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES)
479 
480 template <typename S, typename R>
481 using connect_result_t = typename connect_result<S, R>::type;
482 
483 #endif // defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES)
484 
485 } // namespace execution
486 } // namespace asio
487 } // namespace boost
488 
489 #endif // defined(GENERATING_DOCUMENTATION)
490 
491 #include <boost/asio/detail/pop_options.hpp>
492 
493 #endif // BOOST_ASIO_EXECUTION_CONNECT_HPP
494