2 // execution/connect.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~
5 // Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
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)
11 #ifndef BOOST_ASIO_EXECUTION_CONNECT_HPP
12 #define BOOST_ASIO_EXECUTION_CONNECT_HPP
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
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>
30 #include <boost/asio/detail/push_options.hpp>
32 #if defined(GENERATING_DOCUMENTATION)
38 /// A customisation point that connects a sender to a receiver.
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:
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
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>.
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>
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_});
70 * execution::set_error(std::move(r_), current_exception());
73 * and <tt>as_invocable</tt> is a class template equivalent to the following:
74 * @code template<class 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)) {}
84 * execution::set_done(std::move(*r_));
86 * void operator()() & noexcept try {
87 * execution::set_value(std::move(*r_));
90 * execution::set_error(std::move(*r_), current_exception());
96 * @li Otherwise, <tt>execution::connect(s, r)</tt> is ill-formed.
98 inline constexpr unspecified connect = unspecified;
100 /// A type trait that determines whether a @c connect expression is
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.
107 template <typename S, typename R>
109 integral_constant<bool, automatically_determined>
113 /// A type trait to determine the result of a @c connect expression.
114 template <typename S, typename R>
115 struct connect_result
117 /// The type of the connect expression.
119 * The type of the expression <tt>execution::connect(std::declval<S>(),
120 * std::declval<R>())</tt>.
122 typedef automatically_determined type;
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;
129 } // namespace execution
133 #else // defined(GENERATING_DOCUMENTATION)
135 namespace boost_asio_execution_connect_fn {
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;
162 template <typename S, typename R, typename = void,
163 typename = void, typename = void, typename = void>
166 BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed);
167 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
168 typedef void result_type;
171 template <typename S, typename R>
172 struct call_traits<S, void(R),
174 connect_member<S, R>::is_valid
177 is_operation_state<typename connect_member<S, R>::result_type>::value
180 is_sender<typename remove_cvref<S>::type>::value
184 BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member);
187 template <typename S, typename R>
188 struct call_traits<S, void(R),
190 !connect_member<S, R>::is_valid
193 connect_free<S, R>::is_valid
196 is_operation_state<typename connect_free<S, R>::result_type>::value
199 is_sender<typename remove_cvref<S>::type>::value
203 BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free);
206 template <typename S, typename R>
207 struct call_traits<S, void(R),
209 !connect_member<S, R>::is_valid
212 !connect_free<S, R>::is_valid
215 is_receiver<R>::value
220 typename remove_cvref<R>::type
223 typename remove_cvref<S>::type,
224 as_invocable<typename remove_cvref<R>::type, S>
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;
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
243 operator()(S&& s, R&& r) const
244 BOOST_ASIO_NOEXCEPT_IF((
245 call_traits<S, void(R)>::is_noexcept))
247 return BOOST_ASIO_MOVE_CAST(S)(s).connect(BOOST_ASIO_MOVE_CAST(R)(r));
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
255 operator()(S&& s, R&& r) const
256 BOOST_ASIO_NOEXCEPT_IF((
257 call_traits<S, void(R)>::is_noexcept))
259 return connect(BOOST_ASIO_MOVE_CAST(S)(s), BOOST_ASIO_MOVE_CAST(R)(r));
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
267 operator()(S&& s, R&& r) const
268 BOOST_ASIO_NOEXCEPT_IF((
269 call_traits<S, void(R)>::is_noexcept))
271 return typename call_traits<S, void(R)>::result_type(
272 BOOST_ASIO_MOVE_CAST(S)(s), BOOST_ASIO_MOVE_CAST(R)(r));
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
280 operator()(S& s, R& r) const
281 BOOST_ASIO_NOEXCEPT_IF((
282 call_traits<S&, void(R&)>::is_noexcept))
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
292 operator()(const S& s, R& r) const
293 BOOST_ASIO_NOEXCEPT_IF((
294 call_traits<const S&, void(R&)>::is_noexcept))
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
304 operator()(S& s, R& r) const
305 BOOST_ASIO_NOEXCEPT_IF((
306 call_traits<S&, void(R&)>::is_noexcept))
308 return connect(s, r);
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
316 operator()(const S& s, R& r) const
317 BOOST_ASIO_NOEXCEPT_IF((
318 call_traits<const S&, void(R&)>::is_noexcept))
320 return connect(s, r);
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
328 operator()(S& s, R& r) const
329 BOOST_ASIO_NOEXCEPT_IF((
330 call_traits<S&, void(R&)>::is_noexcept))
332 return typename call_traits<S&, void(R&)>::result_type(s, r);
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
340 operator()(const S& s, R& r) const
341 BOOST_ASIO_NOEXCEPT_IF((
342 call_traits<const S&, void(R&)>::is_noexcept))
344 return typename call_traits<const S&, void(R&)>::result_type(s, r);
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
352 operator()(S& s, const R& r) const
353 BOOST_ASIO_NOEXCEPT_IF((
354 call_traits<S&, void(const R&)>::is_noexcept))
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
364 operator()(const S& s, const R& r) const
365 BOOST_ASIO_NOEXCEPT_IF((
366 call_traits<const S&, void(const R&)>::is_noexcept))
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
376 operator()(S& s, const R& r) const
377 BOOST_ASIO_NOEXCEPT_IF((
378 call_traits<S&, void(const R&)>::is_noexcept))
380 return connect(s, r);
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
388 operator()(const S& s, const R& r) const
389 BOOST_ASIO_NOEXCEPT_IF((
390 call_traits<const S&, void(const R&)>::is_noexcept))
392 return connect(s, r);
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
400 operator()(S& s, const R& r) const
401 BOOST_ASIO_NOEXCEPT_IF((
402 call_traits<S&, void(const R&)>::is_noexcept))
404 return typename call_traits<S&, void(const R&)>::result_type(s, r);
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
412 operator()(const S& s, const R& r) const
413 BOOST_ASIO_NOEXCEPT_IF((
414 call_traits<const S&, void(const R&)>::is_noexcept))
416 return typename call_traits<const S&, void(const R&)>::result_type(s, r);
418 #endif // defined(BOOST_ASIO_HAS_MOVE)
421 template <typename T = impl>
422 struct static_instance
424 static const T instance;
427 template <typename T>
428 const T static_instance<T>::instance = {};
430 } // namespace boost_asio_execution_connect_fn
433 namespace execution {
436 static BOOST_ASIO_CONSTEXPR const boost_asio_execution_connect_fn::impl&
437 connect = boost_asio_execution_connect_fn::static_instance<>::instance;
441 template <typename S, typename R>
443 integral_constant<bool,
444 boost_asio_execution_connect_fn::call_traits<S, void(R)>::overload !=
445 boost_asio_execution_connect_fn::ill_formed>
449 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
451 template <typename S, typename R>
452 constexpr bool can_connect_v = can_connect<S, R>::value;
454 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
456 template <typename S, typename R>
457 struct is_nothrow_connect :
458 integral_constant<bool,
459 boost_asio_execution_connect_fn::call_traits<S, void(R)>::is_noexcept>
463 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
465 template <typename S, typename R>
466 constexpr bool is_nothrow_connect_v
467 = is_nothrow_connect<S, R>::value;
469 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
471 template <typename S, typename R>
472 struct connect_result
474 typedef typename boost_asio_execution_connect_fn::call_traits<
475 S, void(R)>::result_type type;
478 #if defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES)
480 template <typename S, typename R>
481 using connect_result_t = typename connect_result<S, R>::type;
483 #endif // defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES)
485 } // namespace execution
489 #endif // defined(GENERATING_DOCUMENTATION)
491 #include <boost/asio/detail/pop_options.hpp>
493 #endif // BOOST_ASIO_EXECUTION_CONNECT_HPP