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