From Jason Turner

[exec.connect]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmp7dy87dhb/{from.md → to.md} +132 -0
tmp/tmp7dy87dhb/{from.md → to.md} RENAMED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ### `execution::connect` <a id="exec.connect">[[exec.connect]]</a>
2
+
3
+ `connect` connects [[exec.async.ops]] a sender with a receiver.
4
+
5
+ The name `connect` denotes a customization point object. For
6
+ subexpressions `sndr` and `rcvr`, let `Sndr` be `decltype((sndr))` and
7
+ `Rcvr` be `decltype((rcvr))`, let `new_sndr` be the expression
8
+
9
+ ``` cpp
10
+ transform_sender(decltype(get-domain-late(sndr, get_env(rcvr))){}, sndr, get_env(rcvr))
11
+ ```
12
+
13
+ and let `DS` and `DR` be `decay_t<decltype((new_sndr))>` and
14
+ `decay_t<Rcvr>`, respectively.
15
+
16
+ Let *`connect-awaitable-promise`* be the following exposition-only
17
+ class:
18
+
19
+ ``` cpp
20
+ namespace std::execution {
21
+ struct connect-awaitable-promise : with-await-transform<connect-awaitable-promise> {
22
+
23
+ connect-awaitable-promise(DS&, DR& rcvr) noexcept : rcvr(rcvr) {}
24
+
25
+ suspend_always initial_suspend() noexcept { return {}; }
26
+ [[noreturn]] suspend_always final_suspend() noexcept { terminate(); }
27
+ [[noreturn]] void unhandled_exception() noexcept { terminate(); }
28
+ [[noreturn]] void return_void() noexcept { terminate(); }
29
+
30
+ coroutine_handle<> unhandled_stopped() noexcept {
31
+ set_stopped(std::move(rcvr));
32
+ return noop_coroutine();
33
+ }
34
+
35
+ operation-state-task get_return_object() noexcept {
36
+ return operation-state-task{
37
+ coroutine_handle<connect-awaitable-promise>::from_promise(*this)};
38
+ }
39
+
40
+ env_of_t<DR> get_env() const noexcept {
41
+ return execution::get_env(rcvr);
42
+ }
43
+
44
+ private:
45
+ DR& rcvr; // exposition only
46
+ };
47
+ }
48
+ ```
49
+
50
+ Let *`operation-state-task`* be the following exposition-only class:
51
+
52
+ ``` cpp
53
+ namespace std::execution {
54
+ struct operation-state-task { // exposition only
55
+ using operation_state_concept = operation_state_t;
56
+ using promise_type = connect-awaitable-promise;
57
+
58
+ explicit operation-state-task(coroutine_handle<> h) noexcept : coro(h) {}
59
+ operation-state-task(operation-state-task&&) = delete;
60
+ ~operation-state-task() { coro.destroy(); }
61
+
62
+ void start() & noexcept {
63
+ coro.resume();
64
+ }
65
+
66
+ private:
67
+ coroutine_handle<> coro; // exposition only
68
+ };
69
+ }
70
+ ```
71
+
72
+ Let `V` name the type
73
+ `await-result-type<DS, connect-awaitable-promise>`, let `Sigs` name the
74
+ type
75
+
76
+ ``` cpp
77
+ completion_signatures<
78
+ SET-VALUE-SIG(V), // see~[exec.snd.concepts]
79
+ set_error_t(exception_ptr),
80
+ set_stopped_t()>
81
+ ```
82
+
83
+ and let *`connect-awaitable`* be an exposition-only coroutine defined as
84
+ follows:
85
+
86
+ ``` cpp
87
+ namespace std::execution {
88
+ template<class Fun, class... Ts>
89
+ auto suspend-complete(Fun fun, Ts&&... as) noexcept { // exposition only
90
+ auto fn = [&, fun]() noexcept { fun(std::forward<Ts>(as)...); };
91
+
92
+ struct awaiter {
93
+ decltype(fn) fn; // exposition only
94
+
95
+ static constexpr bool await_ready() noexcept { return false; }
96
+ void await_suspend(coroutine_handle<>) noexcept { fn(); }
97
+ [[noreturn]] void await_resume() noexcept { unreachable(); }
98
+ };
99
+ return awaiter{fn};
100
+ }
101
+
102
+ operation-state-task connect-awaitable(DS sndr, DR rcvr) requires receiver_of<DR, Sigs> {
103
+ exception_ptr ep;
104
+ try {
105
+ if constexpr (same_as<V, void>) {
106
+ co_await std::move(sndr);
107
+ co_await suspend-complete(set_value, std::move(rcvr));
108
+ } else {
109
+ co_await suspend-complete(set_value, std::move(rcvr), co_await std::move(sndr));
110
+ }
111
+ } catch(...) {
112
+ ep = current_exception();
113
+ }
114
+ co_await suspend-complete(set_error, std::move(rcvr), std::move(ep));
115
+ }
116
+ }
117
+ ```
118
+
119
+ The expression `connect(sndr, rcvr)` is expression-equivalent to:
120
+
121
+ - `new_sndr.connect(rcvr)` if that expression is well-formed.
122
+ *Mandates:* The type of the expression above satisfies
123
+ `operation_state`.
124
+ - Otherwise, `connect-awaitable(new_sndr, rcvr)`.
125
+
126
+ Except that `rcvr` is evaluated only once.
127
+
128
+ *Mandates:* The following are `true`:
129
+
130
+ - `\texttt{sender_in}<Sndr, env_of_t<Rcvr>>`
131
+ - `\texttt{receiver_of}<Rcvr, completion_signatures_of_t<Sndr, env_of_t<Rcvr>>>`
132
+