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