1 /*
2 * Copyright (c) 2022-2024 NVIDIA Corporation
3 *
4 * Licensed under the Apache License Version 2.0 with LLVM Exceptions
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * https://llvm.org/LICENSE.txt
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #pragma once
17
18 #include "../functional.hpp"
19 #include "__concepts.hpp"
20 #include "__diagnostics.hpp"
21 #include "__env.hpp"
22 #include "__execution_fwd.hpp"
23 #include "__tag_invoke.hpp"
24
25 #include <exception>
26
27 namespace stdexec
28 {
29 /////////////////////////////////////////////////////////////////////////////
30 // [execution.receivers]
31 namespace __rcvrs
32 {
33 struct set_value_t
34 {
35 template <class _Fn, class... _Args>
36 using __f = __minvoke<_Fn, _Args...>;
37
38 template <__same_as<set_value_t> _Self, class _Receiver, class... _As>
39 STDEXEC_ATTRIBUTE((host, device, always_inline))
tag_invoke(_Self,_Receiver && __rcvr,_As &&...__as)40 friend auto tag_invoke(_Self, _Receiver&& __rcvr, _As&&... __as) noexcept
41 -> decltype(static_cast<_Receiver&&>(__rcvr).set_value(
42 static_cast<_As&&>(__as)...))
43 {
44 static_assert(noexcept(static_cast<_Receiver&&>(__rcvr).set_value(
45 static_cast<_As&&>(__as)...)),
46 "set_value member functions must be noexcept");
47 static_assert(
48 __same_as<decltype(static_cast<_Receiver&&>(__rcvr).set_value(
49 static_cast<_As&&>(__as)...)),
50 void>,
51 "set_value member functions must return void");
52 static_cast<_Receiver&&>(__rcvr).set_value(static_cast<_As&&>(__as)...);
53 }
54
55 template <class _Receiver, class... _As>
56 requires tag_invocable<set_value_t, _Receiver, _As...>
57 STDEXEC_ATTRIBUTE((host, device, always_inline))
operator ()stdexec::__rcvrs::set_value_t58 void operator()(_Receiver&& __rcvr, _As&&... __as) const noexcept
59 {
60 static_assert(nothrow_tag_invocable<set_value_t, _Receiver, _As...>);
61 (void)tag_invoke(stdexec::set_value_t{},
62 static_cast<_Receiver&&>(__rcvr),
63 static_cast<_As&&>(__as)...);
64 }
65 };
66
67 struct set_error_t
68 {
69 template <class _Fn, class... _Args>
70 requires(sizeof...(_Args) == 1)
71 using __f = __minvoke<_Fn, _Args...>;
72
73 template <__same_as<set_error_t> _Self, class _Receiver, class _Error>
74 STDEXEC_ATTRIBUTE((host, device, always_inline))
tag_invoke(_Self,_Receiver && __rcvr,_Error && __err)75 friend auto tag_invoke(_Self, _Receiver&& __rcvr, _Error&& __err) noexcept
76 -> decltype(static_cast<_Receiver&&>(__rcvr).set_error(
77 static_cast<_Error&&>(__err)))
78 {
79 static_assert(noexcept(static_cast<_Receiver&&>(__rcvr).set_error(
80 static_cast<_Error&&>(__err))),
81 "set_error member functions must be noexcept");
82 static_assert(
83 __same_as<decltype(static_cast<_Receiver&&>(__rcvr).set_error(
84 static_cast<_Error&&>(__err))),
85 void>,
86 "set_error member functions must return void");
87 static_cast<_Receiver&&>(__rcvr).set_error(
88 static_cast<_Error&&>(__err));
89 }
90
91 template <class _Receiver, class _Error>
92 requires tag_invocable<set_error_t, _Receiver, _Error>
93 STDEXEC_ATTRIBUTE((host, device, always_inline))
operator ()stdexec::__rcvrs::set_error_t94 void operator()(_Receiver&& __rcvr, _Error&& __err) const noexcept
95 {
96 static_assert(nothrow_tag_invocable<set_error_t, _Receiver, _Error>);
97 (void)tag_invoke(stdexec::set_error_t{},
98 static_cast<_Receiver&&>(__rcvr),
99 static_cast<_Error&&>(__err));
100 }
101 };
102
103 struct set_stopped_t
104 {
105 template <class _Fn, class... _Args>
106 requires(sizeof...(_Args) == 0)
107 using __f = __minvoke<_Fn, _Args...>;
108
109 template <__same_as<set_stopped_t> _Self, class _Receiver>
110 STDEXEC_ATTRIBUTE((host, device, always_inline))
tag_invoke(_Self,_Receiver && __rcvr)111 friend auto tag_invoke(_Self, _Receiver&& __rcvr) noexcept
112 -> decltype(static_cast<_Receiver&&>(__rcvr).set_stopped())
113 {
114 static_assert(noexcept(static_cast<_Receiver&&>(__rcvr).set_stopped()),
115 "set_stopped member functions must be noexcept");
116 static_assert(
117 __same_as<decltype(static_cast<_Receiver&&>(__rcvr).set_stopped()),
118 void>,
119 "set_stopped member functions must return void");
120 static_cast<_Receiver&&>(__rcvr).set_stopped();
121 }
122
123 template <class _Receiver>
124 requires tag_invocable<set_stopped_t, _Receiver>
125 STDEXEC_ATTRIBUTE((host, device, always_inline))
operator ()stdexec::__rcvrs::set_stopped_t126 void operator()(_Receiver&& __rcvr) const noexcept
127 {
128 static_assert(nothrow_tag_invocable<set_stopped_t, _Receiver>);
129 (void)tag_invoke(stdexec::set_stopped_t{},
130 static_cast<_Receiver&&>(__rcvr));
131 }
132 };
133 } // namespace __rcvrs
134
135 using __rcvrs::set_error_t;
136 using __rcvrs::set_stopped_t;
137 using __rcvrs::set_value_t;
138 inline constexpr set_value_t set_value{};
139 inline constexpr set_error_t set_error{};
140 inline constexpr set_stopped_t set_stopped{};
141
142 struct receiver_t
143 {
144 using receiver_concept = receiver_t; // NOT TO SPEC
145 };
146
147 namespace __detail
148 {
149 template <class _Receiver>
150 concept __enable_receiver = //
151 (STDEXEC_NVHPC(requires { typename _Receiver::receiver_concept; }&&) //
152 derived_from<typename _Receiver::receiver_concept, receiver_t>) ||
153 requires { typename _Receiver::is_receiver; } // back-compat, NOT TO SPEC
154 || STDEXEC_IS_BASE_OF(receiver_t,
155 _Receiver); // NOT TO SPEC, for receiver_adaptor
156 } // namespace __detail
157
158 template <class _Receiver>
159 inline constexpr bool enable_receiver =
160 __detail::__enable_receiver<_Receiver>; // NOT TO SPEC
161
162 template <class _Receiver>
163 concept receiver = //
164 enable_receiver<__decay_t<_Receiver>> //
165 && environment_provider<__cref_t<_Receiver>> //
166 && move_constructible<__decay_t<_Receiver>> //
167 && constructible_from<__decay_t<_Receiver>, _Receiver>;
168
169 namespace __detail
170 {
171 template <class _Receiver, class _Tag, class... _Args>
172 auto __try_completion(_Tag (*)(_Args...))
173 -> __mexception<_MISSING_COMPLETION_SIGNAL_<_Tag(_Args...)>,
174 _WITH_RECEIVER_<_Receiver>>;
175
176 template <class _Receiver, class _Tag, class... _Args>
177 requires nothrow_tag_invocable<_Tag, _Receiver, _Args...>
178 auto __try_completion(_Tag (*)(_Args...)) -> __msuccess;
179
180 template <class _Receiver, class... _Sigs>
181 auto __try_completions(completion_signatures<_Sigs...>*) //
182 -> decltype((
183 __msuccess(), ...,
184 __detail::__try_completion<_Receiver>(static_cast<_Sigs*>(nullptr))));
185 } // namespace __detail
186
187 template <class _Receiver, class _Completions>
188 concept receiver_of = //
189 receiver<_Receiver> && //
190 requires(_Completions* __completions) {
191 {
192 __detail::__try_completions<__decay_t<_Receiver>>(__completions)
193 } -> __ok;
194 };
195
196 template <class _Receiver, class _Sender>
197 concept __receiver_from =
198 receiver_of<_Receiver,
199 __completion_signatures_of_t<_Sender, env_of_t<_Receiver>>>;
200
201 /// A utility for calling set_value with the result of a function invocation:
202 template <bool _CanThrow = false, class _Receiver, class _Fun, class... _As>
__set_value_invoke(_Receiver && __rcvr,_Fun && __fun,_As &&...__as)203 void __set_value_invoke(_Receiver&& __rcvr, _Fun&& __fun,
204 _As&&... __as) noexcept(!_CanThrow)
205 {
206 if constexpr (_CanThrow || __nothrow_invocable<_Fun, _As...>)
207 {
208 if constexpr (same_as<void, __invoke_result_t<_Fun, _As...>>)
209 {
210 __invoke(static_cast<_Fun&&>(__fun), static_cast<_As&&>(__as)...);
211 stdexec::set_value(static_cast<_Receiver&&>(__rcvr));
212 }
213 else
214 {
215 set_value(static_cast<_Receiver&&>(__rcvr),
216 __invoke(static_cast<_Fun&&>(__fun),
217 static_cast<_As&&>(__as)...));
218 }
219 }
220 else
221 {
222 try
223 {
224 stdexec::__set_value_invoke<true>(static_cast<_Receiver&&>(__rcvr),
225 static_cast<_Fun&&>(__fun),
226 static_cast<_As&&>(__as)...);
227 }
228 catch (...)
229 {
230 stdexec::set_error(static_cast<_Receiver&&>(__rcvr),
231 std::current_exception());
232 }
233 }
234 }
235 } // namespace stdexec
236