74 lines
4.9 KiB
Markdown
74 lines
4.9 KiB
Markdown
[exec.connect]
|
||
|
||
# 33 Execution control library [[exec]](./#exec)
|
||
|
||
## 33.9 Senders [[exec.snd]](exec.snd#exec.connect)
|
||
|
||
### 33.9.10 execution::connect [exec.connect]
|
||
|
||
[1](#1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2734)
|
||
|
||
connect connects ([[exec.async.ops]](exec.async.ops "33.3 Asynchronous operations")) a sender with a receiver[.](#1.sentence-1)
|
||
|
||
[2](#2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2737)
|
||
|
||
The name connect denotes a customization point object[.](#2.sentence-1)
|
||
|
||
For subexpressions sndr and rcvr,
|
||
let Sndr be decltype((sndr)) andRcvr be decltype((rcvr)),
|
||
let new_sndr be the expressiontransform_sender(decltype(*get-domain-late*(sndr, get_env(rcvr))){}, sndr, get_env(rcvr)) and let DS and DR bedecay_t<decltype((new_sndr))> and decay_t<Rcvr>, respectively[.](#2.sentence-2)
|
||
|
||
[3](#3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2749)
|
||
|
||
Let *connect-awaitable-promise* be the following exposition-only class:
|
||
|
||
namespace std::execution {struct *connect-awaitable-promise* : *with-await-transform*<*connect-awaitable-promise*> {*connect-awaitable-promise*(DS&, DR& rcvr) noexcept : *rcvr*(rcvr) {} suspend_always initial_suspend() noexcept { return {}; }[[noreturn]] suspend_always final_suspend() noexcept { terminate(); }[[noreturn]] void unhandled_exception() noexcept { terminate(); }[[noreturn]] void return_void() noexcept { terminate(); } coroutine_handle<> unhandled_stopped() noexcept { set_stopped(std::move(*rcvr*)); return noop_coroutine(); }*operation-state-task* get_return_object() noexcept {return *operation-state-task*{ coroutine_handle<*connect-awaitable-promise*>::from_promise(*this)}; } env_of_t<DR> get_env() const noexcept {return execution::get_env(*rcvr*); }private: DR& *rcvr*; // *exposition only*};}
|
||
|
||
[4](#4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2783)
|
||
|
||
Let *operation-state-task* be the following exposition-only class:namespace std::execution {struct *operation-state-task* { // *exposition only*using operation_state_concept = operation_state_t; using promise_type = *connect-awaitable-promise*; explicit *operation-state-task*(coroutine_handle<> h) noexcept : coro(h) {}*operation-state-task*(*operation-state-task*&&) = delete; ~*operation-state-task*() { *coro*.destroy(); }void start() & noexcept {*coro*.resume(); }private: coroutine_handle<> *coro*; // *exposition only*};}
|
||
|
||
[5](#5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2805)
|
||
|
||
Let V name the type*await-result-type*<DS, *connect-awaitable-promise*>,
|
||
let Sigs name the typecompletion_signatures<*SET-VALUE-SIG*(V), // see [[exec.snd.concepts]](exec.snd.concepts "33.9.3 Sender concepts") set_error_t(exception_ptr),
|
||
set_stopped_t()> and let *connect-awaitable* be an exposition-only coroutine
|
||
defined as follows:namespace std::execution {template<class Fun, class... Ts>auto *suspend-complete*(Fun fun, Ts&&... as) noexcept { // *exposition only*auto fn = [&, fun]() noexcept { fun(std::forward<Ts>(as)...); }; struct awaiter {decltype(fn) *fn*; // *exposition only*static constexpr bool await_ready() noexcept { return false; }void await_suspend(coroutine_handle<>) noexcept { *fn*(); }[[noreturn]] void await_resume() noexcept { unreachable(); }}; return awaiter{fn}; }*operation-state-task* *connect-awaitable*(DS sndr, DR rcvr) requires [receiver_of](exec.recv.concepts#concept:receiver_of "33.7.1 Receiver concepts [exec.recv.concepts]")<DR, Sigs> { exception_ptr ep; try {if constexpr ([same_as](concept.same#concept:same_as "18.4.2 Concept same_as [concept.same]")<V, void>) {co_await std::move(sndr); co_await *suspend-complete*(set_value, std::move(rcvr)); } else {co_await *suspend-complete*(set_value, std::move(rcvr), co_await std::move(sndr)); }} catch(...) { ep = current_exception(); }co_await *suspend-complete*(set_error, std::move(rcvr), std::move(ep)); }}
|
||
|
||
[6](#6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/exec.tex#L2850)
|
||
|
||
The expression connect(sndr, rcvr) is expression-equivalent to:
|
||
|
||
- [(6.1)](#6.1)
|
||
|
||
new_sndr.connect(rcvr) if that expression is well-formed[.](#6.1.sentence-1)
|
||
*Mandates*: The type of the expression above satisfies [operation_state](exec.opstate.general#concept:operation_state "33.8.1 General [exec.opstate.general]")[.](#6.1.sentence-2)
|
||
|
||
- [(6.2)](#6.2)
|
||
|
||
Otherwise, *connect-awaitable*(new_sndr, rcvr)[.](#6.2.sentence-1)
|
||
|
||
Except that rcvr is evaluated only once[.](#6.sentence-2)
|
||
|
||
*Mandates*: The following are true:
|
||
|
||
- [(6.3)](#6.3)
|
||
|
||
[sender_in](exec.snd.concepts#concept:sender_in "33.9.3 Sender concepts [exec.snd.concepts]")<Sndr, env_of_t<Rcvr>>
|
||
|
||
- [(6.4)](#6.4)
|
||
|
||
[receiver_of](exec.recv.concepts#concept:receiver_of "33.7.1 Receiver concepts [exec.recv.concepts]")<Rcvr, completion_signatures_of_t<Sndr, env_of_t<Rcvr>>>
|